60 lines
2.4 KiB
Go
60 lines
2.4 KiB
Go
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
|
|
}
|