Skip to main content

reserve_runner_core

Function reserve_runner_core 

Source
pub async fn reserve_runner_core(
    runners: &Arc<RwLock<HashMap<String, AgentRunner>>>,
    senders: &Arc<RwLock<HashMap<String, Sender<AgentEvent>>>>,
    session_id: &str,
    event_sender: &Sender<AgentEvent>,
) -> ReserveOutcome
Expand description

Shared runner-reservation core used by BOTH the server’s reserve_runner and the engine’s try_reserve_runner, so the idle-eviction sender re-assert can never drift between the two paths again (#346).

While holding the runners write lock it:

  1. short-circuits with ReserveOutcome::AlreadyRunning if a Running runner already exists;
  2. otherwise replaces any stale runner with a fresh Running one whose event_sender is event_sender;
  3. re-asserts event_sender into senders (entry().or_insert_with), STILL holding the runners write lock.

Step 3 closes the idle-sweep TOCTOU: a caller obtains the sender via get_or_create_event_sender and then reserves, but the 60s idle sweep can evict that session’s sender in between (it drops a terminal runner and its sender together under the same runnerssenders lock order). Without the re-assert, a resumed / re-executed run would publish to a channel no longer registered in senders, and a later subscriber’s get_or_create_event_sender would mint a different channel and silently miss every event of that run. Because both this re-assert and the sweep acquire runners first, they are mutually exclusive, and a freshly-inserted Running runner is never swept — so the re-asserted sender is durable for the run.