nautechsystems/nautilus_trader · warning

Failed to finish Betfair data session tasks: {e}

Error message

Failed to finish Betfair data session tasks: {e}

What it means

During Betfair data-client teardown, finish_tasks awaits both session and command task groups' finish_shutdown and maps any error in the session group to this message. It means session-related spawned tasks did not shut down cleanly within the 1s/2s grace timeouts.

Source

Thrown at crates/adapters/betfair/src/data.rs:228

    fn spawn_command<F>(&self, future: F)
    where
        F: std::future::Future<Output = ()> + Send + 'static,
    {
        if let Err(e) = self.command_tasks.spawn(future) {
            log::warn!("Skipping Betfair data command after shutdown began: {e}");
        }
    }

    async fn finish_tasks(&self) -> anyhow::Result<()> {
        let (session_result, command_result) = tokio::join!(
            self.session_tasks
                .finish_shutdown(Duration::from_secs(1), Duration::from_secs(2)),
            self.command_tasks
                .finish_shutdown(Duration::from_secs(1), Duration::from_secs(2)),
        );
        session_result
            .map_err(|e| anyhow::anyhow!("Failed to finish Betfair data session tasks: {e}"))?;
        command_result
            .map_err(|e| anyhow::anyhow!("Failed to finish Betfair data command tasks: {e}"))?;
        Ok(())
    }

    async fn prepare_task_groups(&mut self) -> anyhow::Result<()> {
        if !self.session_tasks.is_open() || !self.command_tasks.is_open() {
            self.teardown_partial_connect().await?;
            self.session_tasks
                .start_generation()
                .map_err(|e| anyhow::anyhow!("Failed to start Betfair data session tasks: {e}"))?;
            self.command_tasks
                .start_generation()
                .map_err(|e| anyhow::anyhow!("Failed to start Betfair data command tasks: {e}"))?;
        }
        Ok(())
    }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Check the wrapped {e} for whether tasks timed out or panicked
  2. Ensure the stream socket is properly closed/aborted before finish_shutdown so session tasks can exit
  3. Log and continue if this occurs during partial-teardown cleanup, since the client is being discarded anyway
  4. Increase shutdown budgets if the network legitimately needs longer to drain

Example fix

// before
session_tasks.finish_shutdown(Duration::from_secs(1), Duration::from_secs(2))
// after (if slow networks are expected)
session_tasks.finish_shutdown(Duration::from_secs(5), Duration::from_secs(10))
Defensive patterns

Strategy: try-catch

Try / catch

// Rust
if let Err(e) = finish_tasks().await {
    // teardown path: log, don't mask the original disconnect error
    tracing::warn!("betfair session tasks shutdown incomplete: {e:#}");
}

Prevention

When it happens

Trigger: Calling teardown_partial_connect -> finish_tasks when session tasks are hung, panicked, or fail to complete within Duration::from_secs(1)/from_secs(2) deadlines.

Common situations: Session tasks blocked on a stalled Betfair stream socket during disconnect; task panics from bad stream data; slow network keeping reads pending past the shutdown timeout.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/515aa9edbf0da033. Report an issue: GitHub.