Portal Community

Buffer Configuration

// LogBufferOptions (configured in appsettings.json)
{
  "LogBuffer": {
    "MaxEntriesPerFlush"  : 50,     // Flush when 50 entries accumulated per execution
    "FlushIntervalSeconds": 1       // Also flush every 1 second regardless of count
  }
}

Buffer Implementation

// SignalRLogBuffer.cs
public class SignalRLogBuffer : ILogBuffer, IHostedService
{
    private readonly ConcurrentDictionary<string, List<LogEntry>> _buffers = new();
    private readonly LogBufferOptions _options;
    private Timer? _flushTimer;

    public void Add(string executionId, LogEntry entry)
    {
        var buffer = _buffers.GetOrAdd(executionId, _ => new List<LogEntry>());

        lock (buffer)
        {
            buffer.Add(entry);

            // Flush immediately if batch size reached
            if (buffer.Count >= _options.MaxEntriesPerFlush)
            {
                FlushAsync(executionId).GetAwaiter().GetResult();
            }
        }
    }

    private async Task FlushAllAsync(CancellationToken ct)
    {
        foreach (var executionId in _buffers.Keys)
        {
            await FlushAsync(executionId);
        }
    }

    // Called by timer every FlushIntervalSeconds
    public Task StartAsync(CancellationToken ct)
    {
        _flushTimer = new Timer(
            _ => FlushAllAsync(CancellationToken.None).GetAwaiter().GetResult(),
            null,
            TimeSpan.FromSeconds(_options.FlushIntervalSeconds),
            TimeSpan.FromSeconds(_options.FlushIntervalSeconds));
        return Task.CompletedTask;
    }
}

Flush Triggers

TriggerConditionLatency
Size triggerBuffer reaches MaxEntriesPerFlush (default: 50)Immediate
Timer triggerFlushIntervalSeconds elapsed (default: 1s)Up to 1 second
Execution endExecutionCompleted event firesImmediate (final flush)
Buffering adds latency but reduces noise. For a node that emits 1000 log entries in 0.5 seconds, without buffering the client would receive 1000 individual SignalR messages. With buffering (batch of 50), it receives 20 messages — much more efficient. The 1-second timer ensures low-throughput nodes still get their logs delivered promptly.