pub struct RunnerAttempt {
pub id: AttemptId,
pub policy_id: PolicyId,
pub created_at: Timestamp,
/* private fields */
}Expand description
One ephemeral runner, from directory allocation to cleanup.
The fields 04-subsystem-contracts.md names are all here. Two are not in that
list and are added deliberately:
outcome, becauseb1’s Scope requires the attempt to “carry an outcome distinguishing ‘ran a job’ from ‘exited idle without work’”.last_state_change_at, because recovery decisions measure elapsed time in the current state — an idle timeout runs from enteringidle, not fromcreated_at— andb1’s Definition of Done requires those decisions to be testable against a fake clock.
b2 persists both.
Fields§
§id: AttemptId§policy_id: PolicyId§created_at: TimestampImplementations§
Source§impl RunnerAttempt
impl RunnerAttempt
Sourcepub fn to_persisted(&self) -> PersistedAttempt
pub fn to_persisted(&self) -> PersistedAttempt
Every stored column of this attempt, for b2 to write back.
The exact inverse of Self::from_persisted, so a round trip through
the journal is expressible without reaching for a field accessor per
column and without this type exposing its private fields for writing.
Sourcepub fn allocate(
id: AttemptId,
policy_id: PolicyId,
runtime_path: impl Into<PathBuf>,
now: Timestamp,
) -> Self
pub fn allocate( id: AttemptId, policy_id: PolicyId, runtime_path: impl Into<PathBuf>, now: Timestamp, ) -> Self
The first step of e3’s per-attempt flow: a runtime directory is
allocated and journalled before anything remote happens, so a crash
leaves a recoverable trace rather than an invisible one.
D3 keeps this the disposable path: an attempt allocated through it is
AttemptWorkspace::Ephemeral, so every existing caller and test goes on
producing the behaviour it produced before persistent slots existed.
Self::allocate_in is the one that leases a slot.
Sourcepub fn allocate_in(
id: AttemptId,
policy_id: PolicyId,
runtime_path: impl Into<PathBuf>,
workspace: AttemptWorkspace,
now: Timestamp,
) -> Self
pub fn allocate_in( id: AttemptId, policy_id: PolicyId, runtime_path: impl Into<PathBuf>, workspace: AttemptWorkspace, now: Timestamp, ) -> Self
The same first step, recording which workspace the directory came from.
c2 calls this with AttemptWorkspace::PersistentSlot while holding
the host allocation lock, so the slot lease is journalled “before package
or GitHub effects” and a crash between the two leaves a recoverable trace
rather than an orphaned slot.
Sourcepub fn from_persisted(fields: PersistedAttempt) -> Result<Self, AttemptError>
pub fn from_persisted(fields: PersistedAttempt) -> Result<Self, AttemptError>
Rebuild a journalled attempt.
§Errors
Any state/outcome/timestamp combination that this crate’s own transitions
cannot produce, so a hand-edited journal cannot inject a failed attempt
that claims to have run a job, or a finished one that never reached a
terminal state.
pub const fn state(&self) -> AttemptState
pub const fn outcome(&self) -> Option<&AttemptOutcome>
pub const fn github_runner_id(&self) -> Option<u64>
pub const fn process_id(&self) -> Option<u32>
pub fn runtime_path(&self) -> &Path
Sourcepub const fn workspace(&self) -> AttemptWorkspace
pub const fn workspace(&self) -> AttemptWorkspace
The immutable allocation fact: disposable, or the persistent slot leased.
There is no setter. Cleanup and recovery dispatch on this
(02-target-architecture.md, “Cleanup and recovery”), so a value that
could be changed after allocation would let the algorithm chosen for a
directory disagree with the one it was created under.
Sourcepub const fn holds_slot_lease(&self) -> bool
pub const fn holds_slot_lease(&self) -> bool
Whether this attempt holds a persistent slot lease.
Every uncleaned persistent attempt is a lease, including a terminal one whose cleanup failed — which is why this asks about the workspace and not about the state.
pub const fn terminal_at(&self) -> Option<Timestamp>
Sourcepub const fn last_state_change_at(&self) -> Timestamp
pub const fn last_state_change_at(&self) -> Timestamp
When the attempt entered its current state. Recovery timeouts run from here.
pub const fn is_terminal(&self) -> bool
Sourcepub const fn counts_against_capacity(&self) -> bool
pub const fn counts_against_capacity(&self) -> bool
Whether this attempt still holds one of the host’s capacity slots.
Sourcepub fn jit_received(&mut self, now: Timestamp) -> Result<(), AttemptError>
pub fn jit_received(&mut self, now: Timestamp) -> Result<(), AttemptError>
Sourcepub fn started(
&mut self,
process_id: u32,
now: Timestamp,
) -> Result<(), AttemptError>
pub fn started( &mut self, process_id: u32, now: Timestamp, ) -> Result<(), AttemptError>
jit_received -> starting, recording the child process identity.
§Errors
AttemptError::IllegalTransition from any other state.
Sourcepub fn registered_idle(
&mut self,
github_runner_id: u64,
now: Timestamp,
) -> Result<(), AttemptError>
pub fn registered_idle( &mut self, github_runner_id: u64, now: Timestamp, ) -> Result<(), AttemptError>
starting -> idle: the runner registered and is awaiting its one
assignment.
§Errors
AttemptError::IllegalTransition from any other state.
Sourcepub fn assigned_job(
&mut self,
github_runner_id: u64,
now: Timestamp,
) -> Result<(), AttemptError>
pub fn assigned_job( &mut self, github_runner_id: u64, now: Timestamp, ) -> Result<(), AttemptError>
starting | idle -> busy: the runner was assigned its one job.
Both sources are real. A runner may be observed taking a job directly out
of starting, or it may be seen idle first and pick the job up on a
later pass — e3’s Scope step 4 walks the second sequence explicitly.
§Errors
AttemptError::IllegalTransition from any other state.
Sourcepub fn conclude(
&mut self,
outcome: AttemptOutcome,
now: Timestamp,
) -> Result<(), AttemptError>
pub fn conclude( &mut self, outcome: AttemptOutcome, now: Timestamp, ) -> Result<(), AttemptError>
Record the terminal outcome, moving to the state it implies.
§Errors
AttemptError::OutcomeUnreachable when the outcome does not belong to
the current state — CompletedJob from anything but busy, or
ExitedIdleWithoutWork from anything but idle — and
AttemptError::IllegalTransition otherwise.
Sourcepub fn clean(&mut self, now: Timestamp) -> Result<(), AttemptError>
pub fn clean(&mut self, now: Timestamp) -> Result<(), AttemptError>
finished | failed | orphaned -> cleaned.
§Errors
AttemptError::BusyCannotBeCleaned for a busy attempt — the
scale-down case 04-subsystem-contracts.md forbids — and
AttemptError::IllegalTransition for any other non-terminal state or
for an already-cleaned attempt.
Trait Implementations§
Source§impl Clone for RunnerAttempt
impl Clone for RunnerAttempt
Source§fn clone(&self) -> RunnerAttempt
fn clone(&self) -> RunnerAttempt
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more