Skip to main content

mj_controller/session_manager/
types.rs

1use super::*;
2
3#[derive(Debug)]
4pub(super) struct ProjectionAdvancedError {
5    pub(super) event_ordinal: u64,
6}
7
8impl std::fmt::Display for ProjectionAdvancedError {
9    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
10        write!(
11            formatter,
12            "another projector committed relay event {} first",
13            self.event_ordinal
14        )
15    }
16}
17
18impl std::error::Error for ProjectionAdvancedError {}
19
20/// Delay before the next reconnect attempt after `failures` consecutive
21/// failures. Doubles from `RECONNECT_INTERVAL` up to the ceiling.
22pub(super) fn reconnect_delay(failures: u32) -> Duration {
23    let doubling = failures.saturating_sub(1).min(u32::BITS - 1);
24    RECONNECT_INTERVAL
25        .saturating_mul(1_u32 << doubling)
26        .min(RECONNECT_BACKOFF_CEILING)
27}
28
29#[derive(Debug, Clone, PartialEq, Eq)]
30pub struct RelaySessionTarget {
31    pub session_id: String,
32    pub spec: CommandSpec,
33    /// Prove the exact worker is absent before restarting it in place. Direct
34    /// relay clients omit recovery; controller-managed sessions self-heal
35    /// without turning a shared transport outage into destructive restarts.
36    pub worker_recovery: Option<WorkerRecoveryPlan>,
37    pub project_memory: Option<ProjectMemorySyncTarget>,
38}
39
40#[derive(Debug, Clone, PartialEq, Eq)]
41pub struct ProjectMemorySyncTarget {
42    pub canonical_root: std::path::PathBuf,
43}
44
45/// The working directory a bare-target worker must be able to enter before it
46/// can serve a relay handshake. Container availability is checked separately
47/// by the target recovery plan; bare targets have no runtime object to inspect.
48#[derive(Debug, Clone, PartialEq, Eq)]
49pub struct WorkerWorkspace {
50    pub target: mj_core::state::ManagedWorktreeTarget,
51    pub directory: PathBuf,
52}
53
54#[derive(Debug, Clone, PartialEq, Eq)]
55pub struct WorkerRecoveryPlan {
56    /// Durable target identity when this plan was built. A stale actor must
57    /// never recover a resource after the session moves or starts destruction.
58    pub source_target: mj_core::state::TargetLocator,
59    pub target: Option<TargetRecoveryPlan>,
60    pub workspace: Option<WorkerWorkspace>,
61    pub liveness_probe: CommandSpec,
62    /// Refresh a stale installed worker before restarting it. The digest is
63    /// computed inside the recovery task so hashing a large binary never
64    /// blocks a controller UI loop.
65    pub binary_refresh: Option<WorkerBinaryRefresh>,
66    /// Keep the worker executable and its launch schema paired. Configuration
67    /// bytes travel through redacted stdin only when their digest is stale.
68    pub launch_refresh: Option<WorkerLaunchRefreshPlan>,
69    pub restart: CommandPlan,
70}
71
72/// How recovery refreshes a stale installed worker binary before restarting.
73///
74/// Local targets resolve the source and the copy at plan-build time, which is
75/// cheap. Remote targets cannot: choosing the binary needs the target's
76/// architecture, and that probe plus hashing the remote binary are blocking
77/// ssh round-trips that must not run on the plan-build/UI path. So a remote
78/// refresh carries only what is cheap to compute and resolves the rest inside
79/// the recovery task.
80#[derive(Debug, Clone, PartialEq, Eq)]
81pub enum WorkerBinaryRefresh {
82    Prepared(WorkerBinaryRefreshPlan),
83    Remote(RemoteWorkerBinaryRefresh),
84}
85
86#[derive(Debug, Clone, PartialEq, Eq)]
87pub struct WorkerBinaryRefreshPlan {
88    pub source: PathBuf,
89    pub installed_digest: CommandSpec,
90    pub replace: CommandPlan,
91}
92
93/// A remote worker refresh resolved at recovery time: select the worker binary
94/// for the target's own architecture, compare it to the installed one, and
95/// copy only when they differ.
96#[derive(Debug, Clone, PartialEq, Eq)]
97pub struct RemoteWorkerBinaryRefresh {
98    pub locator: TargetLocator,
99    pub session_id: String,
100    pub installed_digest: CommandSpec,
101}
102
103#[derive(Debug, Clone, PartialEq, Eq)]
104pub struct WorkerLaunchRefreshPlan {
105    pub expected_sha256: String,
106    pub installed_digest: CommandSpec,
107    pub replace: CommandPlan,
108}