Skip to main content

temporalio_workflow/workflow_context/
view.rs

1use super::{
2    WorkflowContextKey, WorkflowContextValueStore, WorkflowRandomState, WorkflowRandomStream,
3    WorkflowRandomStreamSource,
4};
5use std::{
6    cell::RefCell,
7    rc::Rc,
8    time::{Duration, SystemTime},
9};
10
11use temporalio_common_wasm::{
12    Memo, Priority, RetryPolicy, WorkflowExecution,
13    data_converters::{PayloadConverter, SerializationContextData, WorkflowSerializationContext},
14    protos::coresdk::{
15        common::NamespacedWorkflowExecution, workflow_activation::InitializeWorkflow,
16    },
17    search_attributes::SearchAttributes,
18};
19
20/// Read-only view of workflow context for use in init, query, and update-validator handlers.
21///
22/// This provides access to workflow information but cannot issue commands.
23#[derive(Clone, Debug)]
24#[non_exhaustive]
25pub struct WorkflowContextView {
26    raw: InitializeWorkflow,
27    namespace: String,
28    task_queue: String,
29    run_id: String,
30    payload_converter: PayloadConverter,
31    requires_replay_safety: bool,
32    workflow_random: Option<Rc<RefCell<WorkflowRandomState>>>,
33    context_values: WorkflowContextValueStore,
34}
35
36impl WorkflowContextView {
37    /// Create a new view from workflow initialization data.
38    pub(crate) fn new(
39        namespace: String,
40        task_queue: String,
41        run_id: String,
42        raw: InitializeWorkflow,
43        payload_converter: PayloadConverter,
44        requires_replay_safety: bool,
45        workflow_random: Option<Rc<RefCell<WorkflowRandomState>>>,
46    ) -> Self {
47        Self {
48            raw,
49            namespace,
50            task_queue,
51            run_id,
52            payload_converter,
53            requires_replay_safety,
54            workflow_random,
55            context_values: WorkflowContextValueStore::default(),
56        }
57    }
58
59    pub(super) fn with_context_values(mut self, context_values: WorkflowContextValueStore) -> Self {
60        self.context_values = context_values;
61        self
62    }
63
64    pub(super) fn into_parts(self) -> (String, String, String, InitializeWorkflow) {
65        (self.namespace, self.task_queue, self.run_id, self.raw)
66    }
67
68    /// Returns the workflow's unique identifier.
69    pub fn workflow_id(&self) -> &str {
70        &self.raw.workflow_id
71    }
72
73    /// Returns the run ID of this workflow execution.
74    pub fn run_id(&self) -> &str {
75        &self.run_id
76    }
77
78    /// Returns the workflow type name.
79    pub fn workflow_type(&self) -> &str {
80        &self.raw.workflow_type
81    }
82
83    /// Returns the task queue this workflow is executing on.
84    pub fn task_queue(&self) -> &str {
85        &self.task_queue
86    }
87
88    /// Returns the namespace this workflow is executing in.
89    pub fn namespace(&self) -> &str {
90        &self.namespace
91    }
92
93    /// Returns the current attempt number, starting from one.
94    pub fn attempt(&self) -> u32 {
95        self.raw.attempt as u32
96    }
97
98    /// Returns the run ID of the first execution in the chain.
99    pub fn first_execution_run_id(&self) -> &str {
100        &self.raw.first_execution_run_id
101    }
102
103    /// Returns the run ID of the previous execution when this is a continuation.
104    pub fn continued_from_run_id(&self) -> Option<&str> {
105        (!self.raw.continued_from_execution_run_id.is_empty())
106            .then_some(self.raw.continued_from_execution_run_id.as_str())
107    }
108
109    /// Returns when the workflow execution started.
110    pub fn start_time(&self) -> Option<SystemTime> {
111        self.raw.start_time.and_then(|time| time.try_into().ok())
112    }
113
114    /// Returns the total workflow execution timeout, including retries and continue-as-new.
115    pub fn execution_timeout(&self) -> Option<Duration> {
116        self.raw
117            .workflow_execution_timeout
118            .and_then(|timeout| timeout.try_into().ok())
119    }
120
121    /// Returns the timeout of a single workflow run.
122    pub fn run_timeout(&self) -> Option<Duration> {
123        self.raw
124            .workflow_run_timeout
125            .and_then(|timeout| timeout.try_into().ok())
126    }
127
128    /// Returns the timeout of a single workflow task.
129    pub fn task_timeout(&self) -> Option<Duration> {
130        self.raw
131            .workflow_task_timeout
132            .and_then(|timeout| timeout.try_into().ok())
133    }
134
135    /// Returns information about the parent workflow when this is a child workflow.
136    pub fn parent(&self) -> Option<NamespacedWorkflowInfo> {
137        self.raw
138            .parent_workflow_info
139            .clone()
140            .map(NamespacedWorkflowInfo::from_raw)
141    }
142
143    /// Returns information about the root workflow in the execution chain.
144    pub fn root(&self) -> Option<WorkflowExecution> {
145        self.raw.root_workflow.clone().map(Into::into)
146    }
147
148    /// Returns the workflow's retry policy.
149    pub fn retry_policy(&self) -> Option<RetryPolicy> {
150        self.raw.retry_policy.clone().map(Into::into)
151    }
152
153    /// Returns the cron schedule when this workflow runs on one.
154    pub fn cron_schedule(&self) -> Option<&str> {
155        (!self.raw.cron_schedule.is_empty()).then_some(self.raw.cron_schedule.as_str())
156    }
157
158    /// Returns priority and fairness configuration for this workflow execution.
159    pub fn priority(&self) -> Priority {
160        self.raw.priority.clone().unwrap_or_default().into()
161    }
162
163    /// Returns user-defined memo values.
164    pub fn memo(&self) -> Memo {
165        Memo::from_raw(
166            self.raw.memo.clone(),
167            self.payload_converter.clone(),
168            SerializationContextData::Workflow(WorkflowSerializationContext::new()),
169        )
170    }
171
172    /// Returns initial search attributes as a typed collection.
173    pub fn search_attributes(&self) -> Option<SearchAttributes> {
174        self.raw
175            .search_attributes
176            .as_ref()
177            .map(SearchAttributes::from_proto)
178    }
179
180    /// Return the value associated with key type `K` in the current workflow context scope.
181    ///
182    /// This allows queries and update validators to observe values established by synchronous
183    /// inbound interceptors without allowing the handler to modify the context scope.
184    pub fn context_value<K: WorkflowContextKey>(&self) -> Option<Rc<K::Value>> {
185        self.context_values.context_value::<K>()
186    }
187
188    #[allow(
189        dead_code,
190        reason = "used by SDK-provided interceptors built separately from this change"
191    )]
192    pub(crate) fn random_stream(&self, name: impl Into<String>) -> WorkflowRandomStream {
193        let source = if self.requires_replay_safety {
194            WorkflowRandomStreamSource::Workflow(
195                self.workflow_random
196                    .clone()
197                    .expect("replay-safe context views must have workflow randomness"),
198            )
199        } else {
200            super::system_random_stream_source()
201        };
202        WorkflowRandomStream {
203            source,
204            name: name.into(),
205        }
206    }
207
208    /// Accesses the underlying workflow initialization protobuf.
209    pub fn raw(&self) -> &InitializeWorkflow {
210        &self.raw
211    }
212
213    /// Consumes this view and returns the underlying workflow initialization protobuf.
214    pub fn into_raw(self) -> InitializeWorkflow {
215        self.raw
216    }
217}
218
219/// Information about a parent workflow.
220#[derive(Clone, Debug)]
221#[non_exhaustive]
222pub struct NamespacedWorkflowInfo {
223    raw: NamespacedWorkflowExecution,
224}
225
226impl NamespacedWorkflowInfo {
227    fn from_raw(raw: NamespacedWorkflowExecution) -> Self {
228        Self { raw }
229    }
230
231    /// Returns the parent workflow's unique identifier.
232    pub fn workflow_id(&self) -> &str {
233        &self.raw.workflow_id
234    }
235
236    /// Returns the parent workflow's run ID.
237    pub fn run_id(&self) -> &str {
238        &self.raw.run_id
239    }
240
241    /// Returns the parent workflow's namespace.
242    pub fn namespace(&self) -> &str {
243        &self.raw.namespace
244    }
245
246    /// Accesses the underlying parent workflow protobuf.
247    pub fn raw(&self) -> &NamespacedWorkflowExecution {
248        &self.raw
249    }
250
251    /// Consumes this wrapper and returns the underlying parent workflow protobuf.
252    pub fn into_raw(self) -> NamespacedWorkflowExecution {
253        self.raw
254    }
255}