SeeStack

Buffering & Flushing

How the SDK buffers telemetry data and when it flushes to the backend.

The SeeStack SDK buffers events in memory and sends them in the background. This ensures that capture calls (captureError, captureLog, etc.) return instantly and never block your application.

How Buffering Works

Each feature maintains its own in-memory ring buffer:

PropertyValue
Buffer typeRing buffer (bounded FIFO)
Default size500 items per feature
Eviction policyOldest item dropped when full (tail-drop)
Features with separate buffersErrors, Logs, HTTP Requests, Replay Events

When the buffer is full, the oldest item is silently dropped to make room. The SDK emits a single internal warning (visible in debug mode) but does not throw an error.

Flush Triggers

The buffer is flushed (sent to the backend) in four situations:

TriggerBehavior
TimerEvery flushIntervalMs (default: 5,000ms)
CapacityWhen the buffer reaches 80% full
ManualWhen you call flush()
ShutdownBest-effort drain on application exit (5-second deadline)

Feature-Specific Behavior

Not all features use the same delivery strategy:

FeatureDeliveryBatching
ErrorsSent immediately (not buffered)No — 1 per request
LogsBuffered, flushed on timerNo — 1 per request
HTTP RequestsBuffered, flushed on timer or at 50 itemsYes — up to 100 per request
Session ReplayBuffered, flushed every 5s or at 50 eventsYes — unbounded batch size
Cron HeartbeatsSent immediately after job completesNo — 1 per request

Manual Flush

Call flush() to force-send all buffered events. This is useful before:

  • Application shutdown or process exit
  • Serverless function completion
  • Test assertions that verify backend receipt
// Flush and wait for completion
await SeeStack.flush();
# Flush and wait for completion
seestack.flush()
// Flush and wait for completion
seestack.Flush()

Shutdown Drain

On process exit, the SDK attempts to flush all remaining buffered events within a 5-second deadline. This is best-effort — if the deadline expires, remaining events are discarded.

server.js
// Node.js: ensure graceful shutdown
process.on('SIGTERM', async () => {
  await SeeStack.flush();
  process.exit(0);
});
browser.js
// Browser: use sendBeacon-based flush before page unload
document.addEventListener('visibilitychange', () => {
  if (document.visibilityState === 'hidden') {
    SeeStack.flush();
  }
});
app.py
import atexit

atexit.register(seestack.flush)
main.go
// Use defer in main() to ensure flush on exit
func main() {
    seestack.Init(config)
    defer seestack.Flush()

    // ... application logic
}

The SDK is fully non-blocking. All capture calls push events into the buffer and return immediately. A single background worker per feature handles flushing — no extra threads are spawned per event.

Configuring Buffer Size

You can adjust the buffer size at initialization:

SeeStack.init({
  apiKey: '...',
  host: '...',
  bufferSize: 1000, // 1,000 items per feature instead of default 500
});
seestack.init(
    api_key="...",
    host="...",
    buffer_size=1000,
)
seestack.Init(seestack.Config{
    APIKey:     "...",
    Host:       "...",
    BufferSize: 1000,
})

The total memory footprint scales with buffer size: ~500 items x 5 features = 2,500 items max at default settings, estimated at under 15 MB of heap usage.

On this page