scientific_workflow/runtime/
task.rs1use std::error::Error;
4
5use serde::de::DeserializeOwned;
6use serde_json::Value;
7
8use super::error::RuntimeError;
9use super::phase::{Task, TaskDisplayKind, TaskId, TaskKey};
10use super::reporting::{ActivityTask, TaskProgress};
11use crate::configuration::TaskConfig;
12
13pub type TaskResult = Result<(), Box<dyn Error + Send + Sync + 'static>>;
15
16pub(crate) type Workload = Box<dyn FnOnce(&TaskContext) -> TaskResult + Send + 'static>;
17
18enum TaskHandle {
19 Progress(TaskProgress),
20 Activity(ActivityTask),
21}
22
23pub struct TaskContext {
29 task: Task,
30 handle: TaskHandle,
31}
32
33impl TaskContext {
34 pub(crate) fn progress(task: Task, progress: TaskProgress) -> Self {
35 Self {
36 task,
37 handle: TaskHandle::Progress(progress),
38 }
39 }
40
41 pub(crate) fn activity(task: Task, activity: ActivityTask) -> Self {
42 Self {
43 task,
44 handle: TaskHandle::Activity(activity),
45 }
46 }
47
48 pub fn task(&self) -> &Task {
50 &self.task
51 }
52
53 pub fn key(&self) -> &TaskKey {
55 self.task.key()
56 }
57
58 pub fn id(&self) -> &TaskId {
60 self.task.id()
61 }
62
63 pub fn kind(&self) -> &str {
65 self.task.kind()
66 }
67
68 pub fn configuration(&self) -> &TaskConfig {
70 self.task.configuration()
71 }
72
73 pub fn value(&self, key: &str) -> Option<&Value> {
75 self.task.value(key)
76 }
77
78 pub fn decode_value<T>(&self, key: &str) -> Result<T, RuntimeError>
80 where
81 T: DeserializeOwned,
82 {
83 self.task.decode_value(key)
84 }
85
86 pub fn progress_handle(&self) -> Option<&TaskProgress> {
88 match &self.handle {
89 TaskHandle::Progress(progress) => Some(progress),
90 TaskHandle::Activity(_) => None,
91 }
92 }
93
94 pub fn set_target_iteration(&self, target: u64) -> Result<(), RuntimeError> {
96 self.required_progress()?.set_target_iteration(target)
97 }
98
99 pub fn set_iteration(&self, iteration: u64) -> Result<(), RuntimeError> {
101 self.required_progress()?.set_iteration(iteration)
102 }
103
104 pub fn should_continue(&self, iteration: u64) -> Result<bool, RuntimeError> {
106 self.required_progress()?.should_continue(iteration)
107 }
108
109 pub fn activity_handle(&self) -> Option<&ActivityTask> {
111 match &self.handle {
112 TaskHandle::Progress(_) => None,
113 TaskHandle::Activity(activity) => Some(activity),
114 }
115 }
116
117 pub fn is_cancelled(&self) -> bool {
119 match &self.handle {
120 TaskHandle::Progress(progress) => progress.is_cancelled(),
121 TaskHandle::Activity(activity) => activity.is_cancelled(),
122 }
123 }
124
125 pub fn set_detail(&self, detail: impl Into<String>) {
127 let detail = detail.into();
128 match &self.handle {
129 TaskHandle::Progress(progress) => progress.set_detail(detail),
130 TaskHandle::Activity(activity) => activity.set_detail(detail),
131 }
132 }
133
134 pub fn report(&self, message: impl Into<String>) -> Result<(), RuntimeError> {
136 let message = message.into();
137 match &self.handle {
138 TaskHandle::Progress(progress) => progress.report(message),
139 TaskHandle::Activity(activity) => activity.report(message),
140 }
141 }
142
143 pub(crate) fn complete(self) -> Result<(), RuntimeError> {
144 match self.handle {
145 TaskHandle::Progress(progress) => progress.complete(None),
146 TaskHandle::Activity(activity) => {
147 activity.complete();
148 Ok(())
149 }
150 }
151 }
152
153 pub(crate) fn fail(self, reason: impl Into<String>) {
154 let reason = reason.into();
155 match self.handle {
156 TaskHandle::Progress(progress) => progress.fail(reason),
157 TaskHandle::Activity(activity) => activity.fail(reason),
158 }
159 }
160
161 pub(crate) fn cancel(self, reason: impl Into<String>) {
162 let reason = reason.into();
163 match self.handle {
164 TaskHandle::Progress(progress) => progress.cancel(reason),
165 TaskHandle::Activity(activity) => activity.cancel(reason),
166 }
167 }
168
169 fn required_progress(&self) -> Result<&TaskProgress, RuntimeError> {
170 self.progress_handle()
171 .ok_or_else(|| RuntimeError::ManagedTaskKindMismatch {
172 task: self.key().to_string(),
173 requested: "progress",
174 actual: match self.task.display_kind() {
175 TaskDisplayKind::Progress => "progress",
176 TaskDisplayKind::Activity => "activity",
177 },
178 })
179 }
180}
181
182impl std::fmt::Debug for TaskContext {
183 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
184 formatter
185 .debug_struct("TaskContext")
186 .field("key", self.key())
187 .field("kind", &self.kind())
188 .field("display_kind", &self.task.display_kind())
189 .finish_non_exhaustive()
190 }
191}