#[non_exhaustive]pub struct ProcessInfo {Show 20 fields
pub id: u32,
pub name: String,
pub status: ProcStatus,
pub pid: Option<u32>,
pub restarts: u32,
pub uptime_ms: u64,
pub fold: Option<String>,
pub out_file: Option<String>,
pub err_file: Option<String>,
pub cpu_percent: Option<f32>,
pub memory_bytes: Option<u64>,
pub dog: Option<DogSource>,
pub lambs: Option<Vec<Lamb>>,
pub last_exit: Option<ExitInfo>,
pub smit: Option<String>,
pub instance: Option<u32>,
pub handshook: Option<bool>,
pub dog_stale: Option<bool>,
pub pending: Option<Vec<String>>,
pub overridden: Option<Vec<String>>,
}Expand description
Snapshot of one sheep for listings and events
#[non_exhaustive]: this struct grows fields over time with no hand-edit
sweep needed across OUT-OF-TREE callers — it forbids a struct literal
outside this crate, not inside it. sample_info() and
ProcessInfoBuilder both still name every field and both still need
updating the day a field is added; what the attribute buys is that
nothing downstream does. deferred.md’s own ProcessInfo entry defers
SPLITTING it into several smaller types, not growing it — this attribute
plus ProcessInfo::builder is “deliberately the opposite of forcing
the split early,” which is what makes a field like last_exit cheap to
add for a concrete operator need, not a reason to withhold one. Use
ProcessInfo::builder to construct one; the fields stay pub, so
reading them and assigning to them are both unchanged.
Fields (Non-exhaustive)§
This struct is marked as non-exhaustive
Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.id: u32Stable numeric id
name: StringSheep name
status: ProcStatusLifecycle status
pid: Option<u32>OS pid while running
restarts: u32Restart count since registration
uptime_ms: u64Milliseconds since last successful start
fold: Option<String>Fold membership
out_file: Option<String>Resolved stdout log path: the app’s explicit
AppConfig::out_file when it set one, else the daemon-derived
default. None only when the peer daemon predates this field.
err_file: Option<String>Resolved stderr log path, resolved exactly as Self::out_file
cpu_percent: Option<f32>Tree CPU as a percentage of one core, over the window since the
daemon’s last periodic sample. None when the sheep is not running,
when it has been up for less than one sampling window, or when the
peer daemon predates this field — all three of which a reader
renders as unknown, never as zero.
A value over 100 is a tree using more than one core, not a bug.
memory_bytes: Option<u64>Tree resident set size in bytes, current as of the reply. None
under the same three conditions as Self::cpu_percent, minus the
window one — memory needs no baseline.
dog: Option<DogSource>Set when this entry is a dog, naming where the dog came from;
None for a sheep.
Unlike Self::cpu_percent, None here does not need to enumerate
three cases. A daemon built before dogs existed has none, so “not a
dog” is the true answer whether this peer predates the field or the
entry is genuinely a sheep — there is no resource-usage-style claim
a stale zero could get wrong. Do not “fix” this into three cases.
lambs: Option<Vec<Lamb>>The processes the OS reports as descendants of this sheep, or None
when this reply did not walk for them.
None covers two cases and is deliberately not a third: this reply is
not a Describe (only Describe walks — the walk costs a second pass
over the machine’s process table, and a flock listing is the thing an
operator leaves running in a loop), or the peer daemon predates the
field. Some(vec![]) is the third case, and the one that means what it
looks like: walked, and this sheep has no children.
Read Lamb’s own doc before rendering this. The list is a parent-pid
walk and is NOT the set of processes a stop kills; any output built from
it has to say so where the operator will see it.
last_exit: Option<ExitInfo>How this sheep’s process most recently stopped existing under this
daemon. None while it has never exited under this daemon — either
it has not been started yet, or it is still on its very first run —
and also when the peer daemon predates this field, the same skew
rule Self::out_file documents for itself.
Sticky across a respawn, deliberately: this is the daemon’s answer
to “why did it last stop”, not “is it stopped right now” — status
and pid already answer that, and a sheep back Online after a
crash still has a true story to tell about the crash that restarted
it. It updates only on the next exit, never cleared by one starting
back up.
smit: Option<String>The marker a dog has asked to have painted beside this sheep, or
None when no dog has painted one — which also covers a peer daemon
that predates the field, the same skew rule Self::out_file
documents for itself.
A String rather than a Smit, deliberately: a client decoding a
listing from a daemon that already validated the text should not have
to re-run the parser, and ProcessInfo is a report rather than an
input. The validation that makes this safe to print happened at the
daemon’s ingress — see Smit for why there and not at the renderer.
Every instance of a name shows the same marker: smits are keyed by sheep name, not by instance id.
instance: Option<u32>Which instance slot of its app this sheep occupies, counting from 0.
None when the peer daemon predates the field, the same skew rule
Self::out_file documents for itself. Deliberately not a bare
u32 defaulted to 0: an app stocked to four instances would then
report four rows all claiming slot 0, which is the silently-wrong
zero Self::dog warns against. A reader that finds None should
render exactly what it rendered before this field existed.
handshook: Option<bool>Whether this dog has completed a handshake with the shepherd that is
reporting it, and not been refused since; None for a sheep.
Read Self::dog’s own doc first — this field follows it rather
than Self::cpu_percent, and for the same reason. None covers a
sheep and a peer daemon that predates the field, and collapsing the
two costs nothing: a sheep never handshakes with anything (it has no
connection to the shepherd at all, only a supervised process), so
“no handshake fact to report” is the true answer either way, and a
reader that finds None renders exactly what it rendered before
this field existed. Do not “fix” this into three cases.
Some(false) is the one that matters and it is why this exists.
Self::status reports whether a PROCESS is alive, which for a
sheep is the whole truth and for a dog is not: a dog that cannot
talk to the shepherd is not doing its job, however alive it is. A
dog running on a protocol this shepherd refuses is exactly that, and
before this field a listing reported it online with zero restarts
while its own log filled with refusals.
A fact and not a verdict, deliberately: this says whether the handshake happened, never what a renderer should print about it. A dog that has only just been spawned has not handshaken yet and is perfectly healthy, so the decision about which lifecycle states that silence is worth overriding belongs to the reader.
dog_stale: Option<bool>Whether the reporting shepherd has GIVEN UP on this dog — restarted
it once for never answering, watched that not help, and stopped
restarting it; None for a sheep.
The same None rule Self::handshook documents, for the same
reason: a sheep is never given up on because a sheep never had to
answer anything, so “no verdict to report” is the true answer both
for a sheep and for a peer daemon that predates this field, and a
reader that finds None renders exactly what it rendered before the
field existed. Do not “fix” this into three cases.
Why this is not derivable from Self::handshook, which is the
whole reason it exists. Some(false) there covers two dogs whose
rows are otherwise identical: one spawned three seconds ago that has
simply not dialled back yet, and one this shepherd has permanently
stopped restarting. The first needs nothing done about it and the
second is an incident. Before this field the give-up was a latch
inside the daemon that no listing could see, so every operator-facing
surface rendered both as the same word.
A fact and not a verdict, again deliberately. It says the shepherd
stopped, never why — the why is what the shepherd wrote into that
dog’s own log when it gave up, and it is the one place that can name
the evidence (shep bleats <dog>). A renderer that invented a cause
here would be re-committing the bug this field was added during: a
shepherd asserting a cause it never observed.
pending: Option<Vec<String>>The AppConfig field NAMES this sheep’s
spec differs from a load’s parked config for, in field-name order.
None when nothing is parked (every sheep outside the window
between a load that changed a NeedsRespawn field and the restart
that picks it up), and also when the peer daemon predates the field,
the same skew rule Self::out_file documents for itself.
Names only, never values, for the same reason SheepDrift::fields
carries names only: a differing env reports "env" and stops
there (IR-41). shep reload is what promotes a parked config.
#[serde(skip_serializing_if = "Option::is_none")]: most sheep are
not mid-parking, so this keeps the ordinary reply free of a key that
would otherwise be null on almost every row.
overridden: Option<Vec<String>>The AppConfig field NAMES an operator
has set on this sheep that its current Flockfile does not declare,
in field-name order. None when there is nothing to report: no
override on record for this sheep, or a peer daemon that predates
the field.
Names only, never values, for the reason Self::pending gives:
crate::overrides::AppOverrides::fields can hold an env value,
and nothing in shep sends an app’s env to a client (IR-41).
#[serde(skip_serializing_if = "Option::is_none")], for the same
reason Self::pending carries it: most sheep carry no override at
all.
Implementations§
Source§impl ProcessInfo
impl ProcessInfo
Sourcepub fn builder(
id: u32,
name: impl Into<String>,
status: ProcStatus,
) -> ProcessInfoBuilder
pub fn builder( id: u32, name: impl Into<String>, status: ProcStatus, ) -> ProcessInfoBuilder
Starts a builder for one sheep’s row.
The three required arguments are the three fields no row can omit and
no reader can default: which sheep this is, what it is called, and
what state it is in. Everything else is optional, derived, or
meaningfully absent, which is exactly the shape a builder is for —
a nine-argument new would put Option<String>, Option<String>, Option<f32>, Option<u64> next to each other at every call site and
invite a silent transposition the type system could not catch.
No #[must_use] here: ProcessInfoBuilder already carries one,
which clippy’s double_must_use lint treats as covering this
function’s return too.
Trait Implementations§
Source§impl Clone for ProcessInfo
impl Clone for ProcessInfo
Source§fn clone(&self) -> ProcessInfo
fn clone(&self) -> ProcessInfo
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more