temporalio_client/activity/
activity_handle.rs1use crate::{
2 ActivityCancelOptions, ActivityDescribeOptions, ActivityExecutionDescription,
3 ActivityTerminateOptions, NamespacedClient,
4 errors::{ActivityInteractionError, ActivityResultError},
5 grpc::WorkflowService,
6};
7use std::marker::PhantomData;
8use temporalio_common::{
9 ActivityDefinition,
10 data_converters::{DecodablePayloads, NoopDecodeHint, SerializationContextData},
11 protos::temporal::api::{
12 activity::v1::{ActivityExecutionOutcome, activity_execution_outcome},
13 failure::v1::failure::FailureInfo,
14 workflowservice::v1::{
15 DescribeActivityExecutionRequest, PollActivityExecutionRequest,
16 RequestCancelActivityExecutionRequest, TerminateActivityExecutionRequest,
17 },
18 },
19};
20use tonic::IntoRequest;
21use uuid::Uuid;
22
23pub struct ActivityHandle<ClientT, ActivityT>
33where
34 ActivityT: ActivityDefinition,
35{
36 client: ClientT,
37 activity_id: String,
38 run_id: Option<String>,
39 _phantom: PhantomData<ActivityT>,
40}
41
42impl<ClientT, ActivityT> ActivityHandle<ClientT, ActivityT>
43where
44 ActivityT: ActivityDefinition,
45{
46 pub(crate) fn new(client: ClientT, activity_id: String, run_id: Option<String>) -> Self {
47 Self {
48 client,
49 activity_id,
50 run_id,
51 _phantom: PhantomData,
52 }
53 }
54
55 pub fn activity_id(&self) -> &str {
57 &self.activity_id
58 }
59
60 pub fn run_id(&self) -> Option<&str> {
65 self.run_id.as_deref()
66 }
67}
68
69impl<ClientT, ActivityT> ActivityHandle<ClientT, ActivityT>
70where
71 ClientT: WorkflowService + NamespacedClient + Clone,
72 ActivityT: ActivityDefinition,
73{
74 pub async fn result(&self) -> Result<ActivityT::Output, ActivityResultError> {
77 let mut client = self.client.clone();
78 loop {
79 let resp = client
80 .poll_activity_execution(
81 PollActivityExecutionRequest {
82 namespace: client.namespace(),
83 activity_id: self.activity_id.clone(),
84 run_id: self.run_id.clone().unwrap_or_default(),
85 }
86 .into_request(),
87 )
88 .await?
89 .into_inner();
90
91 let Some(ActivityExecutionOutcome {
93 value: Some(outcome),
94 ..
95 }) = resp.outcome
96 else {
97 continue;
98 };
99
100 let dc = client.data_converter();
101 let ctx = SerializationContextData::Activity;
102
103 return match outcome {
104 activity_execution_outcome::Value::Result(payloads) => {
105 Ok(dc.from_payloads(&ctx, payloads.payloads).await?)
106 }
107 activity_execution_outcome::Value::Failure(failure) => {
108 Err(match failure.failure_info {
109 Some(FailureInfo::CanceledFailureInfo(info)) => {
110 let payloads = info.details.unwrap_or_default().payloads;
111 let details = DecodablePayloads::new(
112 payloads,
113 dc.payload_converter().clone(),
114 ctx,
115 );
116 ActivityResultError::Cancelled { details }
117 }
118 Some(FailureInfo::TerminatedFailureInfo(_)) => {
119 ActivityResultError::Terminated
120 }
121 _ => ActivityResultError::ActivityFailed(dc.to_error(
122 &ctx,
123 failure,
124 NoopDecodeHint,
125 )?),
126 })
127 }
128 };
129 }
130 }
131
132 pub async fn describe(
134 &self,
135 options: ActivityDescribeOptions,
136 ) -> Result<ActivityExecutionDescription<ActivityT>, ActivityInteractionError> {
137 let mut client = self.client.clone();
138 let resp = client
139 .describe_activity_execution(
140 DescribeActivityExecutionRequest {
141 namespace: client.namespace(),
142 activity_id: self.activity_id.clone(),
143 run_id: self.run_id.clone().unwrap_or_default(),
144 include_input: options.include_input,
145 include_outcome: options.include_outcome,
146 include_heartbeat_details: options.include_heartbeat_details,
147 include_last_failure: options.include_last_failure,
148 ..Default::default()
149 }
150 .into_request(),
151 )
152 .await?
153 .into_inner();
154
155 Ok(ActivityExecutionDescription::new(
156 client.data_converter().clone(),
157 SerializationContextData::Activity,
158 resp,
159 )?)
160 }
161
162 pub async fn cancel(
164 &self,
165 options: ActivityCancelOptions,
166 ) -> Result<(), ActivityInteractionError> {
167 let mut client = self.client.clone();
168 client
169 .request_cancel_activity_execution(
170 RequestCancelActivityExecutionRequest {
171 namespace: client.namespace(),
172 activity_id: self.activity_id.clone(),
173 run_id: self.run_id.clone().unwrap_or_default(),
174 identity: client.identity(),
175 request_id: Uuid::new_v4().to_string(),
176 reason: options.reason,
177 }
178 .into_request(),
179 )
180 .await?;
181
182 Ok(())
183 }
184
185 pub async fn terminate(
187 &self,
188 options: ActivityTerminateOptions,
189 ) -> Result<(), ActivityInteractionError> {
190 let mut client = self.client.clone();
191 client
192 .terminate_activity_execution(
193 TerminateActivityExecutionRequest {
194 namespace: client.namespace(),
195 activity_id: self.activity_id.clone(),
196 run_id: self.run_id.clone().unwrap_or_default(),
197 identity: client.identity(),
198 request_id: Uuid::new_v4().to_string(),
199 reason: options.reason,
200 }
201 .into_request(),
202 )
203 .await?;
204
205 Ok(())
206 }
207}