Skip to main content

rust_supervisor/spec/
supervisor_builder.rs

1//! Builder for [`SupervisorSpec`].
2//!
3//! Use this module when constructing supervisor specifications in code. The
4//! builder mirrors [`SupervisorSpec::root`](crate::spec::supervisor::SupervisorSpec::root)
5//! defaults, then lets callers override policy, topology, and runtime settings
6//! through a fluent API.
7
8use crate::error::types::SupervisorError;
9use crate::id::types::SupervisorPath;
10use crate::policy::budget::RestartBudgetConfig;
11use crate::policy::failure_window::FailureWindowConfig;
12use crate::policy::group::GroupDependencyEdge;
13use crate::policy::meltdown::MeltdownPolicy;
14use crate::policy::task_role_defaults::{SeverityClass, TaskRole};
15use crate::spec::child::{BackoffPolicy, ChildSpec, HealthPolicy, RestartPolicy};
16use crate::spec::shutdown::TreeShutdownPolicy;
17use crate::spec::supervisor::{
18    BackpressureConfig, ChildStrategyOverride, DynamicSupervisorPolicy, EscalationPolicy,
19    GroupConfig, GroupStrategy, RestartLimit, SupervisionStrategy, SupervisorSpec,
20};
21use std::collections::HashMap;
22
23/// Builder for [`SupervisorSpec`].
24///
25/// Public constructors and setters keep returning [`SupervisorSpecBuilder`] for
26/// chaining. Call [`build`](SupervisorSpecBuilder::build) to consume the
27/// builder, validate local invariants, and receive the final [`SupervisorSpec`].
28#[derive(Debug, Clone)]
29pub struct SupervisorSpecBuilder {
30    /// Supervisor specification under construction.
31    spec: SupervisorSpec,
32}
33
34impl SupervisorSpecBuilder {
35    /// Creates a root supervisor specification builder.
36    ///
37    /// # Arguments
38    ///
39    /// - `children`: Children declared under the root supervisor.
40    ///
41    /// # Returns
42    ///
43    /// Returns a builder seeded with the same defaults as [`SupervisorSpec::root`].
44    ///
45    /// # Examples
46    ///
47    /// ```
48    /// use rust_supervisor::spec::supervisor_builder::SupervisorSpecBuilder;
49    ///
50    /// # fn example() -> Result<(), rust_supervisor::error::types::SupervisorError> {
51    /// let spec = SupervisorSpecBuilder::root(Vec::new()).build()?;
52    /// assert_eq!(spec.path.to_string(), "/");
53    /// # Ok(())
54    /// # }
55    /// ```
56    pub fn root(children: Vec<ChildSpec>) -> Self {
57        Self {
58            spec: SupervisorSpec::root(children),
59        }
60    }
61
62    /// Creates a root supervisor specification builder.
63    ///
64    /// # Arguments
65    ///
66    /// - `children`: Children declared under the root supervisor.
67    ///
68    /// # Returns
69    ///
70    /// Returns a builder seeded with the same defaults as [`SupervisorSpec::root`].
71    pub fn new(children: Vec<ChildSpec>) -> Self {
72        Self::root(children)
73    }
74
75    /// Sets the supervisor path.
76    ///
77    /// # Arguments
78    ///
79    /// - `path`: Stable path for this supervisor.
80    ///
81    /// # Returns
82    ///
83    /// Returns the builder for chaining.
84    pub fn path(mut self, path: SupervisorPath) -> Self {
85        self.spec.path = path;
86        self
87    }
88
89    /// Sets the restart scope strategy.
90    ///
91    /// # Arguments
92    ///
93    /// - `strategy`: Restart strategy for child exits.
94    ///
95    /// # Returns
96    ///
97    /// Returns the builder for chaining.
98    pub fn strategy(mut self, strategy: SupervisionStrategy) -> Self {
99        self.spec.strategy = strategy;
100        self
101    }
102
103    /// Replaces supervisor children.
104    ///
105    /// # Arguments
106    ///
107    /// - `children`: Children declared under the supervisor.
108    ///
109    /// # Returns
110    ///
111    /// Returns the builder for chaining.
112    pub fn children(mut self, children: Vec<ChildSpec>) -> Self {
113        self.spec.children = children;
114        self
115    }
116
117    /// Appends one supervisor child.
118    ///
119    /// # Arguments
120    ///
121    /// - `child`: Child specification appended in declaration order.
122    ///
123    /// # Returns
124    ///
125    /// Returns the builder for chaining.
126    pub fn child(mut self, mut child: ChildSpec) -> Self {
127        child.shutdown_budget = self.spec.tree_shutdown.budget;
128        self.spec.children.push(child);
129        self
130    }
131
132    /// Sets the configuration version.
133    ///
134    /// # Arguments
135    ///
136    /// - `config_version`: Version string that produced this declaration.
137    ///
138    /// # Returns
139    ///
140    /// Returns the builder for chaining.
141    pub fn config_version(mut self, config_version: impl Into<String>) -> Self {
142        self.spec.config_version = config_version.into();
143        self
144    }
145
146    /// Sets the default restart policy.
147    ///
148    /// # Arguments
149    ///
150    /// - `default_restart_policy`: Restart policy inherited by children.
151    ///
152    /// # Returns
153    ///
154    /// Returns the builder for chaining.
155    pub fn default_restart_policy(mut self, default_restart_policy: RestartPolicy) -> Self {
156        self.spec.default_restart_policy = default_restart_policy;
157        self
158    }
159
160    /// Sets the default backoff policy.
161    ///
162    /// # Arguments
163    ///
164    /// - `default_backoff_policy`: Backoff policy inherited by children.
165    ///
166    /// # Returns
167    ///
168    /// Returns the builder for chaining.
169    pub fn default_backoff_policy(mut self, default_backoff_policy: BackoffPolicy) -> Self {
170        self.spec.default_backoff_policy = default_backoff_policy;
171        self
172    }
173
174    /// Sets the default health policy.
175    ///
176    /// # Arguments
177    ///
178    /// - `default_health_policy`: Health policy inherited by children.
179    ///
180    /// # Returns
181    ///
182    /// Returns the builder for chaining.
183    pub fn default_health_policy(mut self, default_health_policy: HealthPolicy) -> Self {
184        self.spec.default_health_policy = default_health_policy;
185        self
186    }
187
188    /// Sets the tree shutdown policy for this supervisor.
189    ///
190    /// # Arguments
191    ///
192    /// - `tree_shutdown`: Tree shutdown policy and default child budgets.
193    ///
194    /// # Returns
195    ///
196    /// Returns the builder for chaining.
197    pub fn tree_shutdown(mut self, tree_shutdown: TreeShutdownPolicy) -> Self {
198        self.spec.tree_shutdown = tree_shutdown;
199        self
200    }
201
202    /// Sets the supervisor failure limit.
203    ///
204    /// # Arguments
205    ///
206    /// - `supervisor_failure_limit`: Maximum supervisor failures before escalation.
207    ///
208    /// # Returns
209    ///
210    /// Returns the builder for chaining.
211    pub fn supervisor_failure_limit(mut self, supervisor_failure_limit: u32) -> Self {
212        self.spec.supervisor_failure_limit = supervisor_failure_limit;
213        self
214    }
215
216    /// Sets the supervisor-level restart limit.
217    ///
218    /// # Arguments
219    ///
220    /// - `restart_limit`: Restart limit applied at supervisor level.
221    ///
222    /// # Returns
223    ///
224    /// Returns the builder for chaining.
225    pub fn restart_limit(mut self, restart_limit: RestartLimit) -> Self {
226        self.spec.restart_limit = Some(restart_limit);
227        self
228    }
229
230    /// Clears the supervisor-level restart limit.
231    ///
232    /// # Arguments
233    ///
234    /// This function has no arguments.
235    ///
236    /// # Returns
237    ///
238    /// Returns the builder for chaining.
239    pub fn without_restart_limit(mut self) -> Self {
240        self.spec.restart_limit = None;
241        self
242    }
243
244    /// Sets the supervisor-level fallback escalation policy.
245    ///
246    /// The selected policy is used when a child-level or group-level execution
247    /// plan does not define its own escalation policy. Root supervisors do not
248    /// have a parent supervisor at runtime, so `EscalateToParent` is only a
249    /// configured planning and diagnostic label for root supervisors.
250    ///
251    /// # Arguments
252    ///
253    /// - `escalation_policy`: Fallback escalation policy applied at supervisor level.
254    ///
255    /// # Returns
256    ///
257    /// Returns the builder for chaining.
258    pub fn escalation_policy(mut self, escalation_policy: EscalationPolicy) -> Self {
259        self.spec.escalation_policy = Some(escalation_policy);
260        self
261    }
262
263    /// Clears the supervisor-level fallback escalation policy.
264    ///
265    /// # Arguments
266    ///
267    /// This function has no arguments.
268    ///
269    /// # Returns
270    ///
271    /// Returns the builder for chaining.
272    pub fn without_escalation_policy(mut self) -> Self {
273        self.spec.escalation_policy = None;
274        self
275    }
276
277    /// Replaces group strategy overrides.
278    ///
279    /// # Arguments
280    ///
281    /// - `group_strategies`: Group strategy overrides.
282    ///
283    /// # Returns
284    ///
285    /// Returns the builder for chaining.
286    pub fn group_strategies(mut self, group_strategies: Vec<GroupStrategy>) -> Self {
287        self.spec.group_strategies = group_strategies;
288        self
289    }
290
291    /// Appends one group strategy override.
292    ///
293    /// # Arguments
294    ///
295    /// - `group_strategy`: Group strategy override appended to the supervisor.
296    ///
297    /// # Returns
298    ///
299    /// Returns the builder for chaining.
300    pub fn group_strategy(mut self, group_strategy: GroupStrategy) -> Self {
301        self.spec.group_strategies.push(group_strategy);
302        self
303    }
304
305    /// Replaces group configurations.
306    ///
307    /// # Arguments
308    ///
309    /// - `group_configs`: Group-level membership and budget configurations.
310    ///
311    /// # Returns
312    ///
313    /// Returns the builder for chaining.
314    pub fn group_configs(mut self, group_configs: Vec<GroupConfig>) -> Self {
315        self.spec.group_configs = group_configs;
316        self
317    }
318
319    /// Appends one group configuration.
320    ///
321    /// # Arguments
322    ///
323    /// - `group_config`: Group configuration appended to the supervisor.
324    ///
325    /// # Returns
326    ///
327    /// Returns the builder for chaining.
328    pub fn group_config(mut self, group_config: GroupConfig) -> Self {
329        self.spec.group_configs.push(group_config);
330        self
331    }
332
333    /// Replaces cross-group dependency edges.
334    ///
335    /// # Arguments
336    ///
337    /// - `group_dependencies`: Cross-group dependency edges.
338    ///
339    /// # Returns
340    ///
341    /// Returns the builder for chaining.
342    pub fn group_dependencies(mut self, group_dependencies: Vec<GroupDependencyEdge>) -> Self {
343        self.spec.group_dependencies = group_dependencies;
344        self
345    }
346
347    /// Appends one cross-group dependency edge.
348    ///
349    /// # Arguments
350    ///
351    /// - `group_dependency`: Cross-group dependency edge appended to the supervisor.
352    ///
353    /// # Returns
354    ///
355    /// Returns the builder for chaining.
356    pub fn group_dependency(mut self, group_dependency: GroupDependencyEdge) -> Self {
357        self.spec.group_dependencies.push(group_dependency);
358        self
359    }
360
361    /// Replaces default severity classes by task role.
362    ///
363    /// # Arguments
364    ///
365    /// - `severity_defaults`: Default severity map by task role.
366    ///
367    /// # Returns
368    ///
369    /// Returns the builder for chaining.
370    pub fn severity_defaults(
371        mut self,
372        severity_defaults: HashMap<TaskRole, SeverityClass>,
373    ) -> Self {
374        self.spec.severity_defaults = severity_defaults;
375        self
376    }
377
378    /// Sets one default severity class.
379    ///
380    /// # Arguments
381    ///
382    /// - `task_role`: Task role receiving the default severity class.
383    /// - `severity`: Severity class used for the task role.
384    ///
385    /// # Returns
386    ///
387    /// Returns the builder for chaining.
388    pub fn severity_default(mut self, task_role: TaskRole, severity: SeverityClass) -> Self {
389        self.spec.severity_defaults.insert(task_role, severity);
390        self
391    }
392
393    /// Removes one default severity class.
394    ///
395    /// # Arguments
396    ///
397    /// - `task_role`: Task role whose default severity class is removed.
398    ///
399    /// # Returns
400    ///
401    /// Returns the builder for chaining.
402    pub fn without_severity_default(mut self, task_role: TaskRole) -> Self {
403        self.spec.severity_defaults.remove(&task_role);
404        self
405    }
406
407    /// Replaces child-level strategy overrides.
408    ///
409    /// # Arguments
410    ///
411    /// - `child_strategy_overrides`: Child-level strategy overrides.
412    ///
413    /// # Returns
414    ///
415    /// Returns the builder for chaining.
416    pub fn child_strategy_overrides(
417        mut self,
418        child_strategy_overrides: Vec<ChildStrategyOverride>,
419    ) -> Self {
420        self.spec.child_strategy_overrides = child_strategy_overrides;
421        self
422    }
423
424    /// Appends one child-level strategy override.
425    ///
426    /// # Arguments
427    ///
428    /// - `child_strategy_override`: Child-level strategy override appended to the supervisor.
429    ///
430    /// # Returns
431    ///
432    /// Returns the builder for chaining.
433    pub fn child_strategy_override(
434        mut self,
435        child_strategy_override: ChildStrategyOverride,
436    ) -> Self {
437        self.spec
438            .child_strategy_overrides
439            .push(child_strategy_override);
440        self
441    }
442
443    /// Sets the dynamic supervisor policy.
444    ///
445    /// # Arguments
446    ///
447    /// - `dynamic_supervisor_policy`: Runtime child addition policy.
448    ///
449    /// # Returns
450    ///
451    /// Returns the builder for chaining.
452    pub fn dynamic_supervisor_policy(
453        mut self,
454        dynamic_supervisor_policy: DynamicSupervisorPolicy,
455    ) -> Self {
456        self.spec.dynamic_supervisor_policy = dynamic_supervisor_policy;
457        self
458    }
459
460    /// Sets the control command channel capacity.
461    ///
462    /// # Arguments
463    ///
464    /// - `control_channel_capacity`: Control command channel capacity.
465    ///
466    /// # Returns
467    ///
468    /// Returns the builder for chaining.
469    pub fn control_channel_capacity(mut self, control_channel_capacity: usize) -> Self {
470        self.spec.control_channel_capacity = control_channel_capacity;
471        self
472    }
473
474    /// Sets the event broadcast channel capacity.
475    ///
476    /// # Arguments
477    ///
478    /// - `event_channel_capacity`: Event broadcast channel capacity.
479    ///
480    /// # Returns
481    ///
482    /// Returns the builder for chaining.
483    pub fn event_channel_capacity(mut self, event_channel_capacity: usize) -> Self {
484        self.spec.event_channel_capacity = event_channel_capacity;
485        self
486    }
487
488    /// Sets the backpressure configuration.
489    ///
490    /// # Arguments
491    ///
492    /// - `backpressure_config`: Backpressure configuration for event subscribers.
493    ///
494    /// # Returns
495    ///
496    /// Returns the builder for chaining.
497    pub fn backpressure_config(mut self, backpressure_config: BackpressureConfig) -> Self {
498        self.spec.backpressure_config = backpressure_config;
499        self
500    }
501
502    /// Sets the meltdown policy.
503    ///
504    /// # Arguments
505    ///
506    /// - `meltdown_policy`: Failure fuse policy.
507    ///
508    /// # Returns
509    ///
510    /// Returns the builder for chaining.
511    pub fn meltdown_policy(mut self, meltdown_policy: MeltdownPolicy) -> Self {
512        self.spec.meltdown_policy = meltdown_policy;
513        self
514    }
515
516    /// Sets the failure window configuration.
517    ///
518    /// # Arguments
519    ///
520    /// - `failure_window_config`: Failure accumulation window configuration.
521    ///
522    /// # Returns
523    ///
524    /// Returns the builder for chaining.
525    pub fn failure_window_config(mut self, failure_window_config: FailureWindowConfig) -> Self {
526        self.spec.failure_window_config = failure_window_config;
527        self
528    }
529
530    /// Sets the restart budget configuration.
531    ///
532    /// # Arguments
533    ///
534    /// - `restart_budget_config`: Restart budget configuration.
535    ///
536    /// # Returns
537    ///
538    /// Returns the builder for chaining.
539    pub fn restart_budget_config(mut self, restart_budget_config: RestartBudgetConfig) -> Self {
540        self.spec.restart_budget_config = restart_budget_config;
541        self
542    }
543
544    /// Sets the event journal capacity used by the supervision pipeline.
545    ///
546    /// # Arguments
547    ///
548    /// - `pipeline_journal_capacity`: Event journal capacity.
549    ///
550    /// # Returns
551    ///
552    /// Returns the builder for chaining.
553    pub fn pipeline_journal_capacity(mut self, pipeline_journal_capacity: usize) -> Self {
554        self.spec.pipeline_journal_capacity = pipeline_journal_capacity;
555        self
556    }
557
558    /// Sets the subscriber queue capacity used by the supervision pipeline.
559    ///
560    /// # Arguments
561    ///
562    /// - `pipeline_subscriber_capacity`: Subscriber queue capacity.
563    ///
564    /// # Returns
565    ///
566    /// Returns the builder for chaining.
567    pub fn pipeline_subscriber_capacity(mut self, pipeline_subscriber_capacity: usize) -> Self {
568        self.spec.pipeline_subscriber_capacity = pipeline_subscriber_capacity;
569        self
570    }
571
572    /// Sets the concurrent restart limit.
573    ///
574    /// # Arguments
575    ///
576    /// - `concurrent_restart_limit`: Maximum concurrent restarts for this supervisor.
577    ///
578    /// # Returns
579    ///
580    /// Returns the builder for chaining.
581    pub fn concurrent_restart_limit(mut self, concurrent_restart_limit: u32) -> Self {
582        self.spec.concurrent_restart_limit = concurrent_restart_limit;
583        self
584    }
585
586    /// Sets whether metrics recording is enabled.
587    ///
588    /// # Arguments
589    ///
590    /// - `metrics_enabled`: Whether metrics recording is enabled.
591    ///
592    /// # Returns
593    ///
594    /// Returns the builder for chaining.
595    pub fn metrics_enabled(mut self, metrics_enabled: bool) -> Self {
596        self.spec.metrics_enabled = metrics_enabled;
597        self
598    }
599
600    /// Sets whether audit event recording is enabled.
601    ///
602    /// # Arguments
603    ///
604    /// - `audit_enabled`: Whether audit event recording is enabled.
605    ///
606    /// # Returns
607    ///
608    /// Returns the builder for chaining.
609    pub fn audit_enabled(mut self, audit_enabled: bool) -> Self {
610        self.spec.audit_enabled = audit_enabled;
611        self
612    }
613    /// Builds and validates the supervisor specification.
614    ///
615    /// # Arguments
616    ///
617    /// This function has no arguments.
618    ///
619    /// # Returns
620    ///
621    /// Returns the constructed [`SupervisorSpec`] when local invariants pass.
622    ///
623    /// # Errors
624    ///
625    /// Returns [`SupervisorError`] when validation fails.
626    ///
627    /// # Examples
628    ///
629    /// ```
630    /// use rust_supervisor::spec::supervisor_builder::SupervisorSpecBuilder;
631    ///
632    /// # fn example() -> Result<(), rust_supervisor::error::types::SupervisorError> {
633    /// let spec = SupervisorSpecBuilder::root(Vec::new())
634    ///     .config_version("demo")
635    ///     .build()?;
636    /// assert_eq!(spec.config_version, "demo");
637    /// # Ok(())
638    /// # }
639    /// ```
640    ///
641    /// ```compile_fail
642    /// use rust_supervisor::spec::supervisor::SupervisorSpec;
643    /// use rust_supervisor::spec::supervisor_builder::SupervisorSpecBuilder;
644    ///
645    /// let builder = SupervisorSpecBuilder::root(Vec::new());
646    /// let _spec: SupervisorSpec = builder;
647    /// ```
648    pub fn build(self) -> Result<SupervisorSpec, SupervisorError> {
649        let spec = self.spec;
650        spec.validate()?;
651        Ok(spec)
652    }
653}