Skip to main content

mj_controller/
pollers.rs

1//! Background feeds for the control surfaces.
2//!
3//! Everything here runs off the event loop and reports back over a channel:
4//! harness quota refreshes, worker session polling, per-session resource and
5//! deployment capacity probes, credential-sync scheduling, and the one-shot
6//! tasks that recover interrupted closes. The loop that consumes them never
7//! blocks; see [`Feed`] for the wait-then-drain shape they all share.
8
9use std::future::Future;
10use std::path::PathBuf;
11use std::sync::Arc;
12use std::sync::atomic::{AtomicBool, Ordering};
13use std::time::{Duration, Instant};
14
15use anyhow::{Context, Result, bail};
16use mj_core::clock::epoch_seconds;
17use mj_core::config::Config;
18use mj_core::credentials::{
19    CredentialSyncCause, CredentialSyncHandle, CredentialSyncReason, CredentialSyncSignal,
20    CredentialSyncTarget,
21};
22use mj_core::state::{
23    ManagedSessionSnapshot, MaterializedSession, SessionRecord, SessionResourceAllocation,
24    SessionState, State,
25};
26
27use crate::controller::Controller;
28use crate::quota::{QuotaManager, QuotaRefreshOutcome, QuotaRefreshRequest};
29use crate::recovery::{RecoveryCoordinator, RecoveryResult};
30use crate::session_manager::{
31    ManagedSessionView, RelaySessionTarget, RemoteSessionRequest, SessionManagerControl,
32    SessionManagerShutdown, SessionManagerUpdate, SessionManagerUpdates, ViewError,
33    spawn_remote_session_manager,
34};
35use crate::targets::{
36    CancellableProcessExecutor, CommandExecutor, CommandOutput, CommandSpec,
37    DeploymentCapacityKind, DeploymentCapacityTarget, DeploymentCapacityUsage, ImageRefresh,
38    SessionResourceProbe, SessionResourceUsage,
39};
40use crate::worker_client::CredentialSyncCoordinator;
41
42use crate::daemon;
43use mj_core::state::short_id;
44use mj_core::subagent::SubagentRecord;
45
46#[cfg(test)]
47mod runtime_feed_tests;
48
49pub const QUOTA_REFRESH_INTERVAL: Duration = Duration::from_secs(10 * 60);
50/// When a quota reading stops counting as current. A reading only goes stale
51/// once a scheduled refresh should already have replaced it, so this is
52/// derived from the refresh interval rather than chosen next to it: a shorter
53/// threshold would label every healthy quota "stale" for part of every cycle.
54/// The extra interval is slack for a refresh that is itself still running.
55pub const QUOTA_STALE_AFTER: Duration = Duration::from_secs(2 * QUOTA_REFRESH_INTERVAL.as_secs());
56/// How often the daemon looks for a newer copy of every container image its
57/// targets use. Launches no longer pull, so this is what makes a remote
58/// `:latest` tag current, and it has to be rare enough to stay off the
59/// registry's back.
60pub const IMAGE_REFRESH_INTERVAL: Duration = Duration::from_secs(60 * 60);
61/// The daemon has startup work of its own, and a pull competes with it for the
62/// network. The first refresh waits this long, then the interval takes over.
63const IMAGE_REFRESH_DELAY: Duration = Duration::from_secs(30);
64pub const RESOURCE_POLL_INTERVAL: Duration = Duration::from_secs(60);
65const RESOURCE_POLL_TIMEOUT: Duration = Duration::from_secs(15);
66pub const CAPACITY_POLL_INTERVAL: Duration = Duration::from_secs(30);
67
68mod feed;
69pub use feed::*;
70mod types;
71pub use types::*;
72mod quota;
73pub use quota::*;
74mod worker_targets;
75pub use worker_targets::*;
76mod credential_sync;
77pub use credential_sync::*;
78mod resources;
79pub use resources::*;
80mod capacity;
81pub use capacity::*;
82mod runtime_feed;
83pub use runtime_feed::*;
84mod remote;
85pub use remote::*;
86mod lifecycle;
87pub use lifecycle::*;
88
89#[cfg(test)]
90mod tests;