-
Notifications
You must be signed in to change notification settings - Fork 814
Description
Feature Request
(Open to implementing this change, if crate maintainers would accept a contribution)
Crates
tracing-appender
Motivation
NonBlocking allows you to signal a final flush before shutdown. This is done by dropping a WorkerGuard.
I want to explicitly signal flushes throughout my application's life, instead of only on shutdown.
My use case is long running-process (a server) that is sensitive to latency on the request/response path. The whole process sometimes sleeps for longer periods inbetween requests based on an external orchestrator. So, I want to complete the request/response cycle, then tell my worker thread to flush, before my whole process might be put to sleep.
My specific environment (AWS Lambda) works well with that flush pattern (per-request) because it only receives one request, potentially longer-running, at a time. At the same time Rust lambdas generally drive work on a tokio current-thread
runtime, which is very sensitive to blocking by in-thread flushes.
Here is a good example of where you might use the proposed feature.
Proposal
Aflush
method on the WorkerGuard
would be pretty simple and backwards compatible.
Right now, the logging thread listener accepts two commands:
pub(crate) enum Msg {
// written to by subscriber
Line(Vec<u8>),
// written to on WorkerGuard drop
Shutdown,
}
The worker thread currently handles the Shutdown
variant by triggering a flush, and then when it finishes, signals on a 0-sized channel to tell the WorkerGuard
that it successfully flushed and exited.
We could add a third Msg
variant, Flush
, that is written to in a new WorkerGuard::flush
method.
The worker would handle this variant by flushing, signaling completion to the 0-sized response channel, and then continuing on its work loop.
There is a bit of awkwardness regarding handling timeouts, etc, which also exists for the shutdown handling. There is a PR open that makes the timeout configurable via NonBlocking
builder. We could apply a similar approach here here (maybe across two PRs).
Alternatives
WorkerGuard::flush_async()
I would love to offer an asynchronous flush API. It's great for a use case like mine, where I am on a current-thread
tokio runtime that is sensitive to long future polls. Since, we have some blocking send_with_timeouts
in our flush handling that we could sleep on. It also would make timeout handling more elegant in general.
That's a more opinionated design choice though since it would maybe involve introducing new synchronization flows (async channels), feature flags, etc, for the appender.
Some related discussion: #3238
Either way we would would want to expose a sync flush, so better to keep initial scope simpler.