Flow Studio
Log Buffering
The server-side log buffer accumulates log entries per execution and flushes them as batches, either when the buffer reaches its size limit or when the flush timer fires. Batching reduces SignalR message volume for nodes that emit many log entries in rapid succession.
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
| Trigger | Condition | Latency |
|---|---|---|
| Size trigger | Buffer reaches MaxEntriesPerFlush (default: 50) | Immediate |
| Timer trigger | FlushIntervalSeconds elapsed (default: 1s) | Up to 1 second |
| Execution end | ExecutionCompleted event fires | Immediate (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.