Skip to main content

folk_core/
worker_slot.rs

1//! Per-slot state for one worker.
2
3use std::time::Instant;
4
5use crate::config::WorkersConfig;
6
7/// Current state of a worker slot.
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum SlotState {
10    /// Spawn requested; waiting for `control.ready`.
11    Spawning,
12    /// Ready to accept work.
13    Idle,
14    /// Currently handling a request.
15    Busy,
16    /// Recycle requested; finishing in-flight work, then will be replaced.
17    Stopping,
18    /// Terminated. Slot will be replaced.
19    Dead,
20}
21
22/// Mutable state for a single worker slot. Owned exclusively by its supervisor task.
23pub struct SlotInfo {
24    pub state: SlotState,
25    pub pid: Option<u32>,
26    pub jobs_handled: u64,
27    pub created_at: Instant,
28}
29
30impl SlotInfo {
31    pub fn new() -> Self {
32        Self {
33            state: SlotState::Spawning,
34            pid: None,
35            jobs_handled: 0,
36            created_at: Instant::now(),
37        }
38    }
39
40    /// Returns `true` if this slot should be recycled per the configured policies.
41    pub fn should_recycle(&self, cfg: &WorkersConfig) -> bool {
42        if self.jobs_handled >= cfg.max_jobs {
43            return true;
44        }
45        if self.created_at.elapsed() >= cfg.ttl {
46            return true;
47        }
48        false
49    }
50
51    /// Transition to `Idle` after a successful boot.
52    pub fn mark_ready(&mut self, pid: u32) {
53        debug_assert!(matches!(self.state, SlotState::Spawning));
54        self.state = SlotState::Idle;
55        self.pid = Some(pid);
56    }
57
58    /// Transition to `Busy` when dispatching a request.
59    pub fn mark_busy(&mut self) {
60        debug_assert!(matches!(self.state, SlotState::Idle));
61        self.state = SlotState::Busy;
62    }
63
64    /// Transition to `Idle` after a successful response.
65    pub fn mark_idle(&mut self) {
66        debug_assert!(matches!(self.state, SlotState::Busy | SlotState::Stopping));
67        self.jobs_handled += 1;
68        if matches!(self.state, SlotState::Busy) {
69            self.state = SlotState::Idle;
70        }
71        // If Stopping, stay there until shutdown completes.
72    }
73
74    /// Mark the slot as terminated (worker died, runtime returned EOF, etc.).
75    pub fn mark_dead(&mut self) {
76        self.state = SlotState::Dead;
77    }
78
79    /// Request graceful drain.
80    pub fn request_stop(&mut self) {
81        if matches!(self.state, SlotState::Idle | SlotState::Busy) {
82            self.state = SlotState::Stopping;
83        }
84    }
85}
86
87impl Default for SlotInfo {
88    fn default() -> Self {
89        Self::new()
90    }
91}