1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
//! The deadlines, poll intervals and fixture strings the cases here share.
use *;
/// Bound on every `shep` invocation here; `.output()` blocks unbounded
/// without it.
///
/// Must outlive [`shep_client::spawn::SPAWN_DEADLINE`]: the autostart path can
/// spend that whole budget before reporting `DaemonUnreachable`, and an equal
/// bound kills the process before it can report exit 5.
pub const CMD_TIMEOUT: Duration =
from_secs;
/// Bound on how long [`concurrent_cold_starts_produce_exactly_one_daemon`]
/// waits for one of its racers.
///
/// [`CMD_TIMEOUT`] bounds the process wait, not the reader threads after it:
/// those end on EOF, which waits for every copy of the write end, including
/// one a daemon inherited. Strictly longer than [`CMD_TIMEOUT`], so it fires
/// only on a stuck racer.
pub const RACER_DEADLINE: Duration = from_secs;
/// How long [`bleats_no_follow_until_written`] keeps retrying.
pub const BLEATS_DEADLINE: Duration = from_secs;
/// Gap between [`bleats_no_follow_until_written`]'s retries.
pub const BLEATS_POLL_INTERVAL: Duration = from_millis;
/// How long a fixture sheep's script sleeps after writing whatever it writes.
///
/// Outlasts every case that uses it, and short enough that a sheep the
/// [`DaemonGuard`] sweep missed self-terminates. The real-clock cases use
/// [`SLOW_SCRIPT_SLEEP_SECS`].
pub const SCRIPT_SLEEP_SECS: u32 = 60;
/// [`SCRIPT_SLEEP_SECS`] for the two real-clock cases.
///
/// Twice [`CRON_DEADLINE`], the longest of their deadlines: a script that
/// could exit inside the observation window would make "the sheep restarted"
/// equally consistent with a crash loop.
pub const SLOW_SCRIPT_SLEEP_SECS: u32 = 300;
/// Basename, under a case's own `$SHEP_HOME`, of the file every fixture
/// script appends its own pid to. Written by [`record_pid_line`], read by
/// [`DaemonGuard`].
pub const FIXTURE_PIDS: &str = "fixture.pids";
/// How long [`DaemonGuard::drop`] keeps retrying for a parseable daemon pid.
///
/// `PidfileLock::acquire` creates the pidfile empty and `record` fills it only
/// once the control socket is bound, so a fresh `$SHEP_HOME` has an empty
/// pidfile for the whole bind.
pub const GUARD_PID_DEADLINE: Duration = from_secs;
/// Gap between [`GUARD_PID_DEADLINE`]'s and [`GUARD_SWEEP_WINDOW`]'s retries.
pub const GUARD_PID_POLL_INTERVAL: Duration = from_millis;
/// How long [`sweep_flock`] keeps re-reading a case's recorded sheep pids.
/// Covers the gap between the spawn `shep start` reports as `Online` and the
/// script's first line, which is when the pid reaches disk.
pub const GUARD_SWEEP_WINDOW: Duration = from_secs;
/// How long [`poll_flock`] keeps asking before returning what it last saw.
///
/// One deadline for both directions: a case waiting for a restart and a case
/// proving none came must wait the same length. Sized against the 500ms
/// `DEFAULT_WATCH_DELAY` debounce plus a spawn and two RPC round trips, with
/// an order of magnitude of headroom.
pub const FLOCK_DEADLINE: Duration = from_secs;
/// Gap between [`poll_flock`]'s attempts.
pub const FLOCK_POLL_INTERVAL: Duration = from_millis;
/// `RequestError::Closed`: the reply a client loses when the image on the
/// other end of its request was replaced by a handover. An accepted
/// connection is `FD_CLOEXEC` and dies at the `execve`; the handover spec's
/// H2 table rules that the client sees the drop.
pub const DROPPED_REPLY: &str = "the connection closed before a reply arrived";
/// `ConnectError::HandshakeClosed`: the same exec, caught between the accept
/// and the `HelloReply`. A shepherd that is gone prints "could not connect"
/// instead, so neither is reachable from a dead one.
pub const DROPPED_HANDSHAKE: &str = "the daemon closed the connection during the handshake";
/// How long [`poll_metrics`] keeps retrying a `/metrics` scrape.
///
/// `shep enable metrics` returns once the `EnableDog` RPC is accepted, before
/// the daemon has exec'd `shep dog metrics` or that process has bound.
pub const METRICS_SCRAPE_DEADLINE: Duration = FLOCK_DEADLINE;
/// Gap between [`poll_metrics`]'s retries.
pub const METRICS_SCRAPE_POLL_INTERVAL: Duration = from_millis;
/// Bound on a single scrape attempt's own I/O, inside [`poll_metrics`]'s retry
/// loop: a peer that connects and then never answers must not stall it past
/// its own deadline.
pub const METRICS_SCRAPE_READ_TIMEOUT: Duration = from_secs;
/// How long [`poll_http_get`] keeps retrying a `shep serve` worker. `shep
/// serve` returning success means the sheep is registered, not that the worker
/// has bound its listener.
pub const SERVE_HTTP_DEADLINE: Duration = FLOCK_DEADLINE;
/// Gap between [`poll_http_get`]'s retries.
pub const SERVE_HTTP_POLL_INTERVAL: Duration = from_millis;
/// Bound on a single `shep serve` request's own I/O, inside
/// [`poll_http_get`]'s retry loop.
pub const SERVE_HTTP_READ_TIMEOUT: Duration = from_secs;
/// How long [`a_cron_occurrence_restarts_a_sheep_on_the_real_clock`] waits.
///
/// A `* * * * *` pattern armed at an arbitrary moment is up to 60s from its
/// first occurrence. Two and a half minutes covers two, so a loaded runner
/// that misses the first still has a second. The case costs 26s to 61s.
pub const CRON_DEADLINE: Duration = from_secs;
/// How long [`a_real_memory_breach_restarts_a_sheep`] waits for its breach.
///
/// The enforcer samples every `shep_daemon::limits::MEMORY_POLL_INTERVAL`
/// (15s), phased off daemon boot, so the worst wait is one whole interval plus
/// a kill ladder and a respawn. Four times that is headroom.
pub const BREACH_DEADLINE: Duration = from_secs;
/// How long a string [`write_ballooning_script`] grows, in bytes.
///
/// Growing a 16 MiB string takes a `/bin/sh` from about 1.2 MB resident to
/// about 166 MB: the doubling loop's intermediate allocations stay in its
/// heap. The string alone is twice [`BREACH_LIMIT`].
pub const BALLOON_BYTES: u64 = 16 * 1024 * 1024;
/// The `max_memory` the ballooning sheep is given: above a bare shell's 1.2 MB
/// resident set and half the string it grows, so it is under the ceiling
/// before and over it after.
pub const BREACH_LIMIT: &str = "8M";
/// The `listen_timeout` [`write_never_ready_flockfile`] gives its sheep.
///
/// Nothing races it: the sheep never signals, so this is a delay before a
/// certainty. The daemon takes a timed-out `wait_ready` sheep `Online`, so the
/// elapse shows in `shep flock` too.
pub const NEVER_READY_TIMEOUT: &str = "1s";
/// What [`write_rotating_script`]'s sheep prints before the rotation, and
/// what must end up in the renamed archive rather than in the recreated log.
pub const ROTATE_BEFORE: &str = "before-the-rotation";
/// What the same sheep prints after it. Its arrival in the recreated file is
/// the whole assertion.
pub const ROTATE_AFTER: &str = "after-the-rotation";
/// The daemon record the two log-plane cases read out of
/// `$SHEP_HOME/logs/shepd.err.log`, written at `WARN` by
/// `Actor::handle_ready_result`.
///
/// One owner for the string: the two cases assert opposite things about the
/// same record, and a drifted pair would keep passing while proving nothing.
pub const READINESS_RECORD: &str = "readiness deadline elapsed";
/// How long [`counting_lines`] waits for a counter sheep to reach a line
/// count, and [`wait_for_pid`] for a sheep to be online with a pid.
///
/// The counter emits five lines a second and the longest wait here is six
/// lines, so twenty seconds is a loaded runner's margin, not the sheep's pace.
pub const HANDOVER_DEADLINE: Duration = from_secs;
/// Gap between [`counting_lines`]'s reads.
pub const HANDOVER_POLL_INTERVAL: Duration = from_millis;
/// How long [`a_sheep_owed_a_restart_still_gets_one_after_a_daemon_reload`]
/// waits for a re-armed backoff to fire.
///
/// The app's `restart_delay` is 8s and the successor re-arms with the same
/// figure, so five times that is a loaded runner's margin.
pub const RESTARTED_DEADLINE: Duration = from_secs;