Reliability
The design promise of the Rius SDK: tracing never blocks and never breaks your application. This page explains the machinery behind that and the knobs you can tune.
The export pipeline
Spans are queued in-process and exported in batches from a background thread
(OpenTelemetry’s BatchSpanProcessor with an OTLP/HTTP exporter). Span
creation is an in-memory operation; the network never sits on your agent’s
hot path.
Standard OpenTelemetry environment variables tune the batching:
| Variable | Default | Meaning |
|---|---|---|
OTEL_BSP_MAX_QUEUE_SIZE | 2048 | Spans buffered in memory. When full, new spans are dropped with a warning. |
OTEL_BSP_SCHEDULE_DELAY | 5000 (ms) | How often a batch is flushed. |
OTEL_BSP_MAX_EXPORT_BATCH_SIZE | 512 | Spans per HTTP request. |
OTEL_BSP_EXPORT_TIMEOUT | 30000 (ms) | Timeout per export attempt. |
For very chatty agents, raise the queue size before lowering the sample rate; for latency-sensitive shutdowns, lower the schedule delay.
Retries and failure behavior
- Transient failures (connection errors, HTTP 429, 5xx) are retried with exponential backoff and jitter, bounded by the export timeout.
- Non-transient failures (other 4xx) are not retried; the batch is dropped and the error logged.
- If the backend stays unreachable, spans are dropped and errors are logged. Your application continues normally; exporter exceptions never propagate into application code.
Flushing and shutdown
Pending spans are flushed automatically at interpreter exit. For short-lived scripts and batch jobs, or before a hard kill, flush explicitly:
client = glassflow.init(...)
...
client.flush(timeout_millis=30_000) # force an export; False on timeout
client.shutdown() # drain, stop the thread, release init()shutdown() also releases the global init() slot, which is what allows a
later init() to reconfigure the SDK.
Short-lived processes
Export happens on a background thread, so what you need to do depends on how your process ends:
| Where your code runs | What to do | Why |
|---|---|---|
| Long-running server (FastAPI, worker, …) | Nothing | Batches export continuously; the exit hook drains the rest on clean shutdown. |
| CLI or batch job | client.flush() before exiting (or rely on the exit hook) | Short processes can finish before the first scheduled batch export fires. |
| Serverless (Lambda, Cloud Functions, …) | client.flush() at the end of every invocation | The runtime freezes the process between invocations; a frozen background thread exports nothing, and the exit hook may never run. |
| Fork-based workers (gunicorn, multiprocessing) | Nothing at fork time; flush() only if workers are killed hard | The exporter re-creates its background thread in each forked child automatically; only an unclean worker shutdown can lose the last batch. |
Never call flush() inside request handlers or other hot paths: it blocks
until the export completes, which is exactly the stall the background
exporter exists to avoid. Flush at process or invocation boundaries only.
Disabled mode
disabled=True (or GLASSFLOW_DISABLED=1) attaches no exporter at all:
spans are created and dropped in-process. Instrumented code runs unchanged,
which makes it the right kill switch for tests and incident response.
Next steps
- Troubleshooting: symptom-first diagnosis when traces go missing.
- Advanced features: sampling, when the volume rather than the pipeline is the problem.