Skip to content

Add synchronous mode for serverless environments#227

Open
duncanista wants to merge 2 commits intomasterfrom
jordan.gonzalez/synchronous-mode
Open

Add synchronous mode for serverless environments#227
duncanista wants to merge 2 commits intomasterfrom
jordan.gonzalez/synchronous-mode

Conversation

@duncanista
Copy link
Copy Markdown

Summary

  • Add StatsdConfig.SynchronousMode option that bypasses the async background worker and sends metrics directly on the calling thread
  • Extract IStatsBufferize interface from StatsBufferize to enable swapping async/sync implementations
  • Suppress the telemetry background timer when synchronous mode is enabled

Motivation

In AWS Lambda and similar serverless environments, the runtime freezes the sandbox immediately after the handler returns. The DogStatsD client processes metrics on a background thread via AsynchronousWorker, so buffered metrics can be lost when the freeze hits. The existing Flush() method has a hardcoded 3-second timeout and still relies on a background thread to drain the queue — making it fundamentally unreliable in serverless contexts.

SynchronousMode eliminates this class of bugs entirely: no background threads, no async queue, no race with the sandbox freeze. Metrics are routed and serialized on the calling thread, batched into efficient UDP packets via the existing BufferBuilder, and the user calls Flush() at the end of their handler to send any remaining partial buffer.

Usage

var dogstatsd = new DogStatsdService();
dogstatsd.Configure(new StatsdConfig
{
    StatsdServerName = "127.0.0.1",
    SynchronousMode = true,
});

// In Lambda handler:
dogstatsd.Counter("lambda.invocations", 1);
dogstatsd.Flush(); // all metrics sent before handler returns

Test plan

  • All 384 existing tests pass (pure refactoring in Phase 1)
  • 7 unit tests for SynchronousSender (pool behavior, send/flush, batching, auto-flush on full buffer, dispose triggers flush, thread safety, empty flush)
  • 2 builder tests verifying sync mode wiring (skips async CreateStatsBufferize, passes synchronousMode to telemetry)
  • 10 integration tests with real UDP listener (counter, gauge, histogram, distribution, timer, set, tags, event, service check, dispose-flush)
  • Manual validation in a Lambda environment

In AWS Lambda and similar serverless environments, background threads
get frozen when the handler returns, causing buffered metrics to be
lost. This adds a SynchronousMode option that bypasses the async queue
and sends metrics directly on the calling thread.

Changes:
- Extract IStatsBufferize interface from StatsBufferize
- Add SynchronousSender that routes metrics synchronously
- Add StatsdConfig.SynchronousMode property (default false)
- Suppress telemetry background timer in sync mode
- Add unit tests, builder tests, and integration tests
@duncanista duncanista requested a review from a team as a code owner April 14, 2026 14:50
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a138a5f742

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/StatsdClient/Bufferize/SynchronousSender.cs Outdated
In the async path, AsynchronousWorker.Dequeue() catches exceptions from
Route/Flush and forwards them to optionalExceptionHandler. The sync
path was letting exceptions propagate directly into user code, which
could crash Lambda handlers on transport failures or serialization
errors. Wrap Send and Flush in try-catch to match async behavior.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant