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