Operations
You have to be able to see a service and trust it under load. Benzene's operational features are ordinary middleware, the same on every transport, and the docs are candid about what's in the box versus what you supply.
See everything it's doing
Observability is opt-in middleware, shared across transports, and free until you attach an exporter. Full picture in Monitoring.
Traces and metrics via OpenTelemetry
Every middleware in every pipeline can emit its own Activity span, plus processed-count and duration metrics. Export to Jaeger, Tempo, Prometheus, or App Insights through standard OpenTelemetry; Benzene stays exporter-agnostic.
Traces that cross service hops
UseW3CTraceContext() continues a W3C trace from inbound headers and stamps it onto outbound messages, so one request is one trace across HTTP and queue/topic hops (SQS, SNS, Kafka, Event Hub).
Structured, correlated logs
One UseBenzeneEnrichment() attaches invocation id, trace/span id, topic, transport, and handler to the log scope on every platform, through standard Microsoft.Extensions.Logging, so Serilog or App Insights just work.
Know when it's healthy
Health is pipeline middleware, so it works on every transport, not just HTTP. See Health Checks.
Liveness and readiness
Kubernetes-shaped liveness/readiness probes, on a topic for any transport or on GET /livez / /readyz for HTTP hosts.
Dependency checks included
Ship-ready checks for EF Core database connectivity/migrations, a downstream HTTP ping, and schema availability, wired as readiness checks.
Aggregated, with timeouts
Checks run together and report an aggregated status; each is wrapped in a timeout so one slow dependency can't hang the probe (a fixed 10s guard today).
Fail safely
At-least-once transports redeliver, batches partially fail, and dependencies wobble. Benzene has first-class handling for each, and the capability matrix is the honest what-does-what.
Retries, and full resilience via Polly
Retry with exponential backoff is built in (UseRetry()). For circuit breakers, timeouts, hedging, and fallback, Benzene runs your Polly pipeline as middleware, exposing Polly rather than re-abstracting it.
Idempotency for redelivery
Idempotency middleware makes a handler run at most once per message via a pluggable store. In-memory out of the box; back it with DynamoDB or Redis for multi-instance deployments.
Only the failures redeliver
On SQS, only the messages that actually failed are reported back for redelivery, not the whole batch. Per-transport ack/nack and failure escalation are covered in Handling SQS failures. (Dead-letter queues remain your infrastructure config.)
Ship it where you run
Deployment is a wiring choice rather than a rewrite; the hosting reach is in Hosting.
Serverless, containers, or bare process
AWS Lambda and Azure Functions for serverless; ASP.NET Core or a self-hosted worker for containers, Kubernetes, and VMs. The handlers are the same in every case.
Infrastructure as code
Generate Terraform for the Lambda and its event-source permissions straight from your handlers, so the deployment surface tracks the code.
Tuned for cold starts
A Roslyn source generator can discover handlers at compile time instead of by reflection, one of several cold-start optimizations for serverless.