Skip to main content

dataflow_rs/engine/
task_outcome.rs

1//! # Task outcome
2//!
3//! Type returned by every task execution. Replaces the historical
4//! `(usize, Vec<Change>)` tuple — the bare `usize` doubled as both an HTTP-like
5//! status (200) *and* an in-band control-flow signal (skip / halt) which made
6//! the contract impossible to type-check. `TaskOutcome` makes the four cases
7//! explicit; the audit-trail status code is derived from the variant.
8//!
9//! The `Vec<Change>` is no longer part of the return value — sync built-ins
10//! emit changes via the executor's per-task buffer, async handlers via
11//! `TaskContext`. The audit trail is recorded by the workflow executor based
12//! on the variant returned here.
13
14/// Status code recorded on the audit trail when a task halts the workflow.
15///
16/// Preserved from v3 (`FILTER_STATUS_HALT = 299`) so existing audit-log
17/// consumers (e.g. dataflow-ui) keep parsing halt entries unchanged.
18pub const HALT_STATUS_CODE: u16 = 299;
19
20/// Outcome of a single task execution.
21///
22/// Returned by `AsyncFunctionHandler::execute` and by the engine's internal
23/// sync-builtin dispatch path. The workflow executor uses the variant to
24/// decide whether to continue, skip the audit trail, or halt the workflow.
25///
26/// HTTP-like status semantics (preserved from v3 and earlier):
27/// - status `200` — normal completion
28/// - status `400..500` — logged as a warning, workflow continues
29/// - status `500..` — recorded; fails the workflow unless the task or
30///   workflow has `continue_on_error = true`
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
32#[must_use]
33pub enum TaskOutcome {
34    /// Normal completion. Audit trail records status `200` and the workflow
35    /// continues with the next task.
36    #[default]
37    Success,
38
39    /// Completion with an explicit HTTP-like status code. Audit trail records
40    /// the supplied status. Codes in the `400..500` range log a warning;
41    /// codes `>= 500` fail the workflow unless `continue_on_error` is set.
42    Status(u16),
43
44    /// Skip recording an audit trail entry for this task; continue with the
45    /// next task. Used by filter gates that intentionally no-op when their
46    /// condition does not match.
47    Skip,
48
49    /// Record the audit trail (status [`HALT_STATUS_CODE`]) and stop further
50    /// tasks in the current workflow. Subsequent workflows registered on the
51    /// same engine still process this message normally.
52    Halt,
53}
54
55impl TaskOutcome {
56    /// HTTP-like status code that will be stamped on the audit trail entry
57    /// for this outcome. `Skip` returns `None` since no audit entry is
58    /// recorded in that case.
59    #[inline]
60    pub fn audit_status(self) -> Option<u16> {
61        match self {
62            TaskOutcome::Success => Some(200),
63            TaskOutcome::Status(s) => Some(s),
64            TaskOutcome::Skip => None,
65            TaskOutcome::Halt => Some(HALT_STATUS_CODE),
66        }
67    }
68
69    /// Whether the workflow executor should halt further tasks in this
70    /// workflow after observing this outcome.
71    #[inline]
72    pub fn halts_workflow(self) -> bool {
73        matches!(self, TaskOutcome::Halt)
74    }
75}