CaptureHandle Runtime Pattern
Context
CaptureHandle::spawn() needs to work both inside and outside a Tokio runtime. Required because the sync test connection_id_increments calls spawn() from a plain #[test] with no async executor.
Pattern
Use tokio::runtime::Handle::try_current() to detect runtime presence:
- Runtime present: spawn on the current handle via handle.spawn(background)
- No runtime: create a new multi_thread runtime with 1 worker, spawn on it, then std::mem::forget(rt) to keep it alive
Why std::mem::forget
Dropping the Runtime cancels all tasks on it. The background writer must outlive spawn(), so the runtime must stay alive. Leaking it is intentional — acceptable for a capture subsystem.
Returned JoinHandle
In both branches a valid tokio::task::JoinHandle<()> is returned. In the no-runtime case the handle is tied to the leaked runtime; awaiting it still works correctly from async context later.
Files
- train_track/src/capture/mod.rs
- train_track/tests/capture_handle_test.rs