package service // queueReservation is the dispatch goroutine's handle on one admitted lease. // Admission reserves a slot on the selected node/provider — and a long-context // slot when the request is long and the provider declares a long-context limit — // and mints the lease that owns it before any request is built or sent. Every // dispatch path that fails after admission hands the lease back through release. // // The exactly-once guarantee lives in the manager, not here: release resolves the // lease id under the manager lock, so a send failure racing an early terminal // event or a node disconnect frees the slot once regardless of which one wins. // This handle only tracks whether *this* goroutine still owns the lease, and is // touched from the single dispatch goroutine. // // A dispatch that succeeds calls handOff: the run terminal path (normalized) or // the tunnel terminal frame / close (tunnel) owns the release from that point. type queueReservation struct { queue *modelQueueManager leaseID uint64 // done marks that this handle has given up ownership, either by releasing // the lease or by handing it to the run/tunnel lifecycle. done bool } // newQueueReservation takes ownership of the lease that admission minted for the // selected candidate. func newQueueReservation(queue *modelQueueManager, selected *candidateNode) *queueReservation { return &queueReservation{queue: queue, leaseID: selected.leaseID} } // track binds the run id to the lease so terminal events and node disconnects // can find it. It runs before the send so a terminal event arriving early still // resolves the lease to release. func (res *queueReservation) track(runID string) { if res == nil || res.queue == nil { return } res.queue.trackLease(res.leaseID, runID) } // release frees the lease. Repeated calls, and calls after handOff, are no-ops // on this handle; a release that does reach the manager is itself idempotent by // lease identity. func (res *queueReservation) release(reason string) { if res == nil || res.queue == nil || res.done { return } res.done = true res.queue.releaseLease(res.leaseID, reason) } // handOff marks the lease as owned by the dispatched run or tunnel lifecycle, so // no later release on this handle can free a slot that now belongs to a live // request. func (res *queueReservation) handOff() { if res == nil { return } res.done = true }