pub struct ApprovalConfig { /* private fields */ }Expand description
Configuration for a human approval step.
When the workflow reaches an approval step, the run transitions to
AwaitingApproval and waits for a human to approve or reject via
the API.
A gate can carry an SLA: with_deadline arms a timer
persisted alongside the step, and on_timeout says what
happens when it fires. The timer lives in the database, so it survives an API
or worker restart.
A gate can also carry a dynamic approval matrix:
with_rule appends an ApprovalRule whose condition is
evaluated against the run context when the gate opens. The first matching
rule decides how many distinct approvals the gate needs and which groups may
vote; when no rule matches, one approval from anyone allowed to answer the
gate resolves it. A config without rules behaves exactly as before.
§Examples
use ironflow_engine::config::{ApprovalConfig, ApprovalRule};
let config = ApprovalConfig::new("Deploy to production?");
assert_eq!(config.message(), "Deploy to production?");
assert!(config.timeout_seconds().is_none());
let rule = ApprovalRule::new("payload.amount > 10000", 2).with_approver_groups(["finance"]);
let payment = ApprovalConfig::new("Release the payment?").with_rule(rule);
assert_eq!(payment.rules().len(), 1);Implementations§
Source§impl ApprovalConfig
impl ApprovalConfig
Sourcepub fn new(message: &str) -> Self
pub fn new(message: &str) -> Self
Create a new approval config with the given message.
§Examples
use ironflow_engine::config::ApprovalConfig;
let config = ApprovalConfig::new("Approve this deployment?");
assert_eq!(config.message(), "Approve this deployment?");Sourcepub fn with_timeout_seconds(self, seconds: u64) -> Self
pub fn with_timeout_seconds(self, seconds: u64) -> Self
Set an auto-reject timeout in seconds.
If no approval or rejection is received within this duration, the run is automatically rejected (marked as Failed).
This is the legacy spelling of with_deadline_secs
with an implicit EscalationPolicy::AutoReject. It is now actually
enforced by the escalator; a config that sets both keeps the explicit
deadline.
§Examples
use ironflow_engine::config::{ApprovalConfig, EscalationPolicy};
let config = ApprovalConfig::new("Approve?")
.with_timeout_seconds(3600);
assert_eq!(config.timeout_seconds(), Some(3600));
assert_eq!(config.effective_deadline_secs(), Some(3600));
assert_eq!(config.effective_policy(), EscalationPolicy::AutoReject);Sourcepub fn with_deadline(self, deadline: Duration) -> Self
pub fn with_deadline(self, deadline: Duration) -> Self
Set the SLA deadline of this gate.
Sub-second precision is dropped: the deadline is stored in whole seconds.
§Panics
Panics if deadline rounds down to zero seconds.
§Examples
use std::time::Duration;
use ironflow_engine::config::ApprovalConfig;
let config = ApprovalConfig::new("Approve?")
.with_deadline(Duration::from_secs(1800));
assert_eq!(config.deadline(), Some(Duration::from_secs(1800)));Sourcepub fn with_deadline_secs(self, secs: u64) -> Self
pub fn with_deadline_secs(self, secs: u64) -> Self
Set the SLA deadline of this gate, in seconds.
§Panics
Panics if secs is zero: a gate that expires the instant it opens can
never be approved by a human.
§Examples
use ironflow_engine::config::ApprovalConfig;
let config = ApprovalConfig::new("Approve?").with_deadline_secs(1800);
assert_eq!(config.deadline_secs(), Some(1800));Sourcepub fn on_timeout(self, policy: EscalationPolicy) -> Self
pub fn on_timeout(self, policy: EscalationPolicy) -> Self
Set the policy applied when the deadline fires.
§Examples
use ironflow_engine::config::{ApprovalConfig, EscalationPolicy};
let config = ApprovalConfig::new("Approve?")
.with_deadline_secs(3600)
.on_timeout(EscalationPolicy::AutoApprove);
assert_eq!(config.effective_policy(), EscalationPolicy::AutoApprove);Sourcepub fn assigned_to(self, assignee: Assignee) -> Self
pub fn assigned_to(self, assignee: Assignee) -> Self
Assign the gate to a user or group.
§Panics
Panics if the assignee name is empty or only whitespace.
§Examples
use ironflow_engine::config::ApprovalConfig;
use ironflow_store::entities::Assignee;
let config = ApprovalConfig::new("Approve?").assigned_to(Assignee::group("release-managers"));
assert_eq!(config.assignee(), Some(&Assignee::group("release-managers")));Sourcepub fn with_rule(self, rule: ApprovalRule) -> Self
pub fn with_rule(self, rule: ApprovalRule) -> Self
Append an approval rule. Rules are evaluated in the order they were added and the first match wins.
§Examples
use ironflow_engine::config::{ApprovalConfig, ApprovalRule};
let config = ApprovalConfig::new("Approve?")
.with_rule(ApprovalRule::new("payload.amount > 100000", 3))
.with_rule(ApprovalRule::new("payload.amount > 10000", 2));
assert_eq!(config.rules()[0].required_approvers(), 3);Sourcepub fn rules(&self) -> &[ApprovalRule]
pub fn rules(&self) -> &[ApprovalRule]
The approval rules, in evaluation order.
§Examples
use ironflow_engine::config::ApprovalConfig;
assert!(ApprovalConfig::new("Approve?").rules().is_empty());Sourcepub fn evaluate_rules(&self, ctx: &Value) -> ApprovalRequirement
pub fn evaluate_rules(&self, ctx: &Value) -> ApprovalRequirement
Evaluate the rules in order against ctx.
Every evaluated rule is recorded in
ApprovalRequirement::evaluated, up to and including the first match.
The first matching rule decides the requirement; when none matches, the
default requirement applies (one
approval, any approver).
§Examples
use ironflow_engine::config::{ApprovalConfig, ApprovalRule};
use serde_json::json;
let rule = ApprovalRule::new("payload.amount > 10000", 2).with_approver_groups(["finance"]);
let config = ApprovalConfig::new("Approve?").with_rule(rule);
let big = config.evaluate_rules(&json!({"payload": {"amount": 15000}}));
assert_eq!(big.rule_index, Some(0));
assert_eq!(big.required_approvers, 2);
let small = config.evaluate_rules(&json!({"payload": {"amount": 10}}));
assert_eq!(small.rule_index, None);
assert_eq!(small.required_approvers, 1);
assert!(!small.evaluated[0].matched);Sourcepub fn timeout_seconds(&self) -> Option<u64>
pub fn timeout_seconds(&self) -> Option<u64>
Optional auto-reject timeout in seconds.
Sourcepub fn deadline(&self) -> Option<Duration>
pub fn deadline(&self) -> Option<Duration>
The configured SLA deadline, if any.
§Examples
use std::time::Duration;
use ironflow_engine::config::ApprovalConfig;
let config = ApprovalConfig::new("Approve?").with_deadline_secs(60);
assert_eq!(config.deadline(), Some(Duration::from_secs(60)));Sourcepub fn deadline_secs(&self) -> Option<u64>
pub fn deadline_secs(&self) -> Option<u64>
The configured SLA deadline in seconds, if any.
Sourcepub fn on_timeout_policy(&self) -> Option<&EscalationPolicy>
pub fn on_timeout_policy(&self) -> Option<&EscalationPolicy>
The configured escalation policy, if any.
Sourcepub fn effective_deadline_secs(&self) -> Option<u64>
pub fn effective_deadline_secs(&self) -> Option<u64>
The deadline actually enforced, in seconds.
with_deadline_secs wins; the legacy
with_timeout_seconds is honoured as a
fallback so configs written before escalation existed finally behave the
way their documentation always promised.
§Examples
use ironflow_engine::config::ApprovalConfig;
let legacy = ApprovalConfig::new("Approve?").with_timeout_seconds(7200);
assert_eq!(legacy.effective_deadline_secs(), Some(7200));
let both = legacy.with_deadline_secs(60);
assert_eq!(both.effective_deadline_secs(), Some(60));
assert_eq!(ApprovalConfig::new("Approve?").effective_deadline_secs(), None);Sourcepub fn effective_policy(&self) -> EscalationPolicy
pub fn effective_policy(&self) -> EscalationPolicy
The policy applied when the deadline fires. Defaults to
EscalationPolicy::AutoReject, matching the documented meaning of
timeout_seconds.
§Examples
use ironflow_engine::config::{ApprovalConfig, EscalationPolicy};
let config = ApprovalConfig::new("Approve?").with_deadline_secs(60);
assert_eq!(config.effective_policy(), EscalationPolicy::AutoReject);