Skip to main content

temporalio_client/
interceptors.rs

1//! Interceptors for high-level client operations.
2
3use crate::{
4    ActivityHeartbeatResponse, ActivityIdentifier, WorkflowCancelOptions, WorkflowCountOptions,
5    WorkflowDescribeOptions, WorkflowFetchHistoryOptions, WorkflowQueryOptions,
6    WorkflowSignalOptions, WorkflowStartError, WorkflowStartOptions, WorkflowStartUpdateOptions,
7    WorkflowTerminateOptions,
8    errors::{
9        AsyncActivityError, ClientError, WorkflowInteractionError, WorkflowQueryError,
10        WorkflowUpdateError,
11    },
12    schedules::{
13        CreateScheduleOptions, ScheduleBackfill, ScheduleError, ScheduleOverlapPolicy,
14        ScheduleUpdate,
15    },
16};
17use futures_util::future::BoxFuture;
18use std::{any::Any, sync::Arc};
19use temporalio_common::{
20    data_converters::{
21        GenericPayloadConverter, PayloadConversionError, SerializationContext, TemporalSerializable,
22    },
23    protos::temporal::api::{
24        common::v1::Payload,
25        history::v1::HistoryEvent,
26        schedule::v1::ScheduleListEntry,
27        update::v1::Outcome,
28        workflow::v1::WorkflowExecutionInfo,
29        workflowservice::v1::{
30            CountWorkflowExecutionsResponse, DescribeScheduleResponse,
31            DescribeWorkflowExecutionResponse, QueryWorkflowResponse,
32        },
33    },
34};
35
36mod temporal_client_value {
37    use super::*;
38
39    pub trait Sealed {
40        fn serialize_client_payloads(
41            &self,
42            context: &SerializationContext<'_>,
43        ) -> Result<Vec<Payload>, PayloadConversionError>;
44    }
45
46    impl<T> Sealed for T
47    where
48        T: Any + TemporalSerializable + Send,
49    {
50        fn serialize_client_payloads(
51            &self,
52            context: &SerializationContext<'_>,
53        ) -> Result<Vec<Payload>, PayloadConversionError> {
54            context.converter.to_payloads(context, self)
55        }
56    }
57}
58
59/// Type-erased input carried through the client interceptor chain.
60pub trait TemporalClientValue: Any + Send + temporal_client_value::Sealed {
61    /// Access this value as [`Any`] for type-specific inspection.
62    fn as_any(&self) -> &dyn Any;
63
64    /// Access this value as mutable [`Any`] for type-specific mutation.
65    fn as_any_mut(&mut self) -> &mut dyn Any;
66}
67
68impl<T> TemporalClientValue for T
69where
70    T: Any + TemporalSerializable + Send,
71{
72    fn as_any(&self) -> &dyn Any {
73        self
74    }
75
76    fn as_any_mut(&mut self) -> &mut dyn Any {
77        self
78    }
79}
80
81impl dyn TemporalClientValue {
82    pub(crate) fn serialize_payloads(
83        &self,
84        context: &SerializationContext<'_>,
85    ) -> Result<Vec<Payload>, PayloadConversionError> {
86        temporal_client_value::Sealed::serialize_client_payloads(self, context)
87    }
88}
89
90/// Provides access to the arguments carried by a client interceptor input.
91pub trait HasArgs {
92    /// Attempt to access the arguments as a concrete type.
93    fn args_ref<T: Any>(&self) -> Option<&T>;
94
95    /// Attempt to mutably access the arguments as a concrete type.
96    fn args_mut<T: Any>(&mut self) -> Option<&mut T>;
97
98    /// Replace the arguments with another serializable value.
99    fn replace_args<T>(&mut self, args: T)
100    where
101        T: TemporalSerializable + Send + 'static;
102}
103
104macro_rules! impl_with_args {
105    ($input:ty) => {
106        impl HasArgs for $input {
107            fn args_ref<T: Any>(&self) -> Option<&T> {
108                self.args.as_any().downcast_ref()
109            }
110
111            fn args_mut<T: Any>(&mut self) -> Option<&mut T> {
112                self.args.as_any_mut().downcast_mut()
113            }
114
115            fn replace_args<T>(&mut self, args: T)
116            where
117                T: TemporalSerializable + Send + 'static,
118            {
119                self.args = Box::new(args);
120            }
121        }
122    };
123}
124
125/// Continuation for an intercepted client operation.
126///
127/// A continuation can be invoked at most once because [`run`](Self::run) consumes it.
128pub struct Next<'a, I, O> {
129    inner: Box<dyn FnOnce(I) -> O + Send + 'a>,
130}
131
132impl<'a, I, O> Next<'a, I, O> {
133    pub(crate) fn new(f: impl FnOnce(I) -> O + Send + 'a) -> Self {
134        Self { inner: Box::new(f) }
135    }
136
137    /// Continue the interceptor chain with the provided input.
138    pub fn run(self, input: I) -> O {
139        (self.inner)(input)
140    }
141}
142
143/// Input to [`ClientInterceptor::start_workflow`].
144#[non_exhaustive]
145#[derive(derive_more::Debug)]
146pub struct StartWorkflowInput {
147    /// The workflow type sent to the server.
148    pub workflow_type: String,
149    /// Options for the workflow start.
150    pub options: WorkflowStartOptions,
151    /// Controls for the start RPC.
152    pub rpc_options: crate::RpcOptions,
153    #[debug(skip)]
154    args: Box<dyn TemporalClientValue>,
155}
156
157impl StartWorkflowInput {
158    pub(crate) fn new<T>(workflow_type: String, args: T, mut options: WorkflowStartOptions) -> Self
159    where
160        T: TemporalSerializable + Send + 'static,
161    {
162        let rpc_options = std::mem::take(&mut options.rpc_options);
163        Self {
164            workflow_type,
165            options,
166            rpc_options,
167            args: Box::new(args),
168        }
169    }
170
171    pub(crate) fn into_parts(
172        self,
173    ) -> (
174        String,
175        Box<dyn TemporalClientValue>,
176        WorkflowStartOptions,
177        crate::RpcOptions,
178    ) {
179        (
180            self.workflow_type,
181            self.args,
182            self.options,
183            self.rpc_options,
184        )
185    }
186}
187
188impl_with_args!(StartWorkflowInput);
189
190/// Result of a successful intercepted workflow start.
191#[non_exhaustive]
192#[derive(Clone, Debug, PartialEq, Eq)]
193pub struct StartWorkflowOutput {
194    /// The workflow ID used by the start operation.
195    pub workflow_id: String,
196    /// The run ID returned by the service or a short-circuiting interceptor.
197    pub run_id: String,
198}
199
200impl StartWorkflowOutput {
201    pub(crate) fn new(workflow_id: impl Into<String>, run_id: impl Into<String>) -> Self {
202        Self {
203            workflow_id: workflow_id.into(),
204            run_id: run_id.into(),
205        }
206    }
207}
208
209/// Input to [`ClientInterceptor::list_workflows_page`].
210#[non_exhaustive]
211#[derive(Clone, Debug)]
212pub struct ListWorkflowsPageInput {
213    /// Visibility query used to select workflows.
214    pub query: String,
215    /// Token identifying the page to retrieve, or empty for the first page.
216    pub next_page_token: Vec<u8>,
217    /// Controls for this page RPC.
218    pub rpc_options: crate::RpcOptions,
219}
220
221/// Result of one intercepted workflow-list page.
222#[non_exhaustive]
223#[derive(Clone, Debug)]
224pub struct ListWorkflowsPageOutput {
225    /// Workflow executions returned by the service.
226    pub executions: Vec<WorkflowExecutionInfo>,
227    /// Token identifying the next page, or empty when no pages remain.
228    pub next_page_token: Vec<u8>,
229}
230
231impl ListWorkflowsPageOutput {
232    pub(crate) fn new(executions: Vec<WorkflowExecutionInfo>, next_page_token: Vec<u8>) -> Self {
233        Self {
234            executions,
235            next_page_token,
236        }
237    }
238}
239
240/// Input to [`ClientInterceptor::count_workflows`].
241#[non_exhaustive]
242#[derive(Clone, Debug)]
243pub struct CountWorkflowsInput {
244    /// Visibility query used to count workflows.
245    pub query: String,
246    /// Count options, including per-call RPC controls.
247    pub options: WorkflowCountOptions,
248}
249
250/// Result of an intercepted workflow count.
251#[non_exhaustive]
252#[derive(Clone, Debug)]
253pub struct CountWorkflowsOutput {
254    /// Raw service response used to assemble the high-level count result.
255    pub response: CountWorkflowExecutionsResponse,
256}
257
258impl CountWorkflowsOutput {
259    pub(crate) fn new(response: CountWorkflowExecutionsResponse) -> Self {
260        Self { response }
261    }
262}
263
264/// Input to [`ClientInterceptor::describe_workflow`].
265#[non_exhaustive]
266#[derive(Clone, Debug)]
267pub struct DescribeWorkflowInput {
268    /// Workflow ID to describe.
269    pub workflow_id: String,
270    /// Run ID to describe, or empty for the latest run.
271    pub run_id: String,
272    /// Describe options, including per-call RPC controls.
273    pub options: WorkflowDescribeOptions,
274}
275
276/// Result of an intercepted workflow describe.
277#[non_exhaustive]
278#[derive(Clone, Debug)]
279pub struct DescribeWorkflowOutput {
280    /// Raw service response decoded after interceptor dispatch.
281    pub response: DescribeWorkflowExecutionResponse,
282}
283
284impl DescribeWorkflowOutput {
285    pub(crate) fn new(response: DescribeWorkflowExecutionResponse) -> Self {
286        Self { response }
287    }
288}
289
290/// Input to [`ClientInterceptor::fetch_workflow_history_page`].
291#[non_exhaustive]
292#[derive(Clone, Debug)]
293pub struct FetchWorkflowHistoryPageInput {
294    /// Workflow ID whose history is being retrieved.
295    pub workflow_id: String,
296    /// Run ID whose history is being retrieved.
297    pub run_id: String,
298    /// Token identifying the page to retrieve, or empty for the first page.
299    pub next_page_token: Vec<u8>,
300    /// History options, including per-page RPC controls.
301    pub options: WorkflowFetchHistoryOptions,
302}
303
304/// Result of one intercepted workflow-history page.
305#[non_exhaustive]
306#[derive(Clone, Debug)]
307pub struct FetchWorkflowHistoryPageOutput {
308    /// History events returned on this page.
309    pub events: Vec<HistoryEvent>,
310    /// Token identifying the next page, or empty when no pages remain.
311    pub next_page_token: Vec<u8>,
312}
313
314impl FetchWorkflowHistoryPageOutput {
315    pub(crate) fn new(events: Vec<HistoryEvent>, next_page_token: Vec<u8>) -> Self {
316        Self {
317            events,
318            next_page_token,
319        }
320    }
321}
322
323/// Input to [`ClientInterceptor::signal_workflow`].
324#[non_exhaustive]
325#[derive(derive_more::Debug)]
326pub struct SignalWorkflowInput {
327    /// Workflow ID to signal.
328    pub workflow_id: String,
329    /// Run ID to signal, or empty for the latest run.
330    pub run_id: String,
331    /// Signal name sent to the workflow.
332    pub signal_name: String,
333    /// Signal options, including per-call RPC controls.
334    pub options: WorkflowSignalOptions,
335    #[debug(skip)]
336    args: Box<dyn TemporalClientValue>,
337}
338
339impl SignalWorkflowInput {
340    pub(crate) fn new<T>(
341        workflow_id: String,
342        run_id: String,
343        signal_name: String,
344        args: T,
345        options: WorkflowSignalOptions,
346    ) -> Self
347    where
348        T: TemporalSerializable + Send + 'static,
349    {
350        Self {
351            workflow_id,
352            run_id,
353            signal_name,
354            options,
355            args: Box::new(args),
356        }
357    }
358
359    pub(crate) fn into_parts(
360        self,
361    ) -> (
362        String,
363        String,
364        String,
365        Box<dyn TemporalClientValue>,
366        WorkflowSignalOptions,
367    ) {
368        (
369            self.workflow_id,
370            self.run_id,
371            self.signal_name,
372            self.args,
373            self.options,
374        )
375    }
376}
377
378impl_with_args!(SignalWorkflowInput);
379
380/// Input to [`ClientInterceptor::query_workflow`].
381#[non_exhaustive]
382#[derive(derive_more::Debug)]
383pub struct QueryWorkflowInput {
384    /// Workflow ID to query.
385    pub workflow_id: String,
386    /// Run ID to query, or empty for the latest run.
387    pub run_id: String,
388    /// Query name sent to the workflow.
389    pub query_name: String,
390    /// Query options, including per-call RPC controls.
391    pub options: WorkflowQueryOptions,
392    #[debug(skip)]
393    args: Box<dyn TemporalClientValue>,
394}
395
396impl QueryWorkflowInput {
397    pub(crate) fn new<T>(
398        workflow_id: String,
399        run_id: String,
400        query_name: String,
401        args: T,
402        options: WorkflowQueryOptions,
403    ) -> Self
404    where
405        T: TemporalSerializable + Send + 'static,
406    {
407        Self {
408            workflow_id,
409            run_id,
410            query_name,
411            options,
412            args: Box::new(args),
413        }
414    }
415
416    pub(crate) fn into_parts(
417        self,
418    ) -> (
419        String,
420        String,
421        String,
422        Box<dyn TemporalClientValue>,
423        WorkflowQueryOptions,
424    ) {
425        (
426            self.workflow_id,
427            self.run_id,
428            self.query_name,
429            self.args,
430            self.options,
431        )
432    }
433}
434
435impl_with_args!(QueryWorkflowInput);
436
437/// Result of an intercepted workflow query before typed result conversion.
438#[non_exhaustive]
439#[derive(Clone, Debug)]
440pub struct QueryWorkflowOutput {
441    /// Raw service response decoded after interceptor dispatch.
442    pub response: QueryWorkflowResponse,
443}
444
445impl QueryWorkflowOutput {
446    pub(crate) fn new(response: QueryWorkflowResponse) -> Self {
447        Self { response }
448    }
449}
450
451/// Input to [`ClientInterceptor::start_workflow_update`].
452#[non_exhaustive]
453#[derive(derive_more::Debug)]
454pub struct StartWorkflowUpdateInput {
455    /// Workflow ID to update.
456    pub workflow_id: String,
457    /// Run ID to update, or empty for the latest run.
458    pub run_id: String,
459    /// Update name sent to the workflow.
460    pub update_name: String,
461    /// Update options, including per-call RPC controls.
462    pub options: WorkflowStartUpdateOptions,
463    #[debug(skip)]
464    args: Box<dyn TemporalClientValue>,
465}
466
467impl StartWorkflowUpdateInput {
468    pub(crate) fn new<T>(
469        workflow_id: String,
470        run_id: String,
471        update_name: String,
472        args: T,
473        options: WorkflowStartUpdateOptions,
474    ) -> Self
475    where
476        T: TemporalSerializable + Send + 'static,
477    {
478        Self {
479            workflow_id,
480            run_id,
481            update_name,
482            options,
483            args: Box::new(args),
484        }
485    }
486
487    pub(crate) fn into_parts(
488        self,
489    ) -> (
490        String,
491        String,
492        String,
493        Box<dyn TemporalClientValue>,
494        WorkflowStartUpdateOptions,
495    ) {
496        (
497            self.workflow_id,
498            self.run_id,
499            self.update_name,
500            self.args,
501            self.options,
502        )
503    }
504}
505
506impl_with_args!(StartWorkflowUpdateInput);
507
508/// Result of an intercepted workflow-update start.
509#[non_exhaustive]
510#[derive(Clone, Debug)]
511pub struct StartWorkflowUpdateOutput {
512    /// Update ID used by the operation.
513    pub update_id: String,
514    /// Workflow ID associated with the update.
515    pub workflow_id: String,
516    /// Run ID returned by the service, when available.
517    pub run_id: Option<String>,
518    /// Outcome returned when the requested wait stage completed the update.
519    pub known_outcome: Option<Outcome>,
520}
521
522impl StartWorkflowUpdateOutput {
523    pub(crate) fn new(
524        update_id: impl Into<String>,
525        workflow_id: impl Into<String>,
526        run_id: Option<String>,
527        known_outcome: Option<Outcome>,
528    ) -> Self {
529        Self {
530            update_id: update_id.into(),
531            workflow_id: workflow_id.into(),
532            run_id,
533            known_outcome,
534        }
535    }
536}
537
538/// Input to [`ClientInterceptor::poll_workflow_update`].
539#[non_exhaustive]
540#[derive(Clone, Debug)]
541pub struct PollWorkflowUpdateInput {
542    /// Update ID being polled.
543    pub update_id: String,
544    /// Workflow ID associated with the update.
545    pub workflow_id: String,
546    /// Run ID associated with the update, or empty for the latest run.
547    pub run_id: String,
548    /// Controls for every RPC in the polling loop.
549    pub rpc_options: crate::RpcOptions,
550}
551
552/// Result of an intercepted workflow-update poll.
553#[non_exhaustive]
554#[derive(Clone, Debug)]
555pub struct PollWorkflowUpdateOutput {
556    /// Completed update outcome.
557    pub outcome: Outcome,
558}
559
560impl PollWorkflowUpdateOutput {
561    pub(crate) fn new(outcome: Outcome) -> Self {
562        Self { outcome }
563    }
564}
565
566/// Input to [`ClientInterceptor::cancel_workflow`].
567#[non_exhaustive]
568#[derive(Clone, Debug)]
569pub struct CancelWorkflowInput {
570    /// Workflow ID to cancel.
571    pub workflow_id: String,
572    /// Run ID to cancel, or empty for the latest run.
573    pub run_id: String,
574    /// First execution run ID used to constrain the cancellation.
575    pub first_execution_run_id: String,
576    /// Cancellation options, including per-call RPC controls.
577    pub options: WorkflowCancelOptions,
578}
579
580/// Input to [`ClientInterceptor::terminate_workflow`].
581#[non_exhaustive]
582#[derive(Clone, Debug)]
583pub struct TerminateWorkflowInput {
584    /// Workflow ID to terminate.
585    pub workflow_id: String,
586    /// Run ID to terminate, or empty for the latest run.
587    pub run_id: String,
588    /// First execution run ID used to constrain the termination.
589    pub first_execution_run_id: String,
590    /// Termination options, including per-call RPC controls.
591    pub options: WorkflowTerminateOptions,
592}
593
594/// Input to [`ClientInterceptor::create_schedule`].
595#[non_exhaustive]
596#[derive(Debug)]
597pub struct CreateScheduleInput {
598    /// Schedule ID to create.
599    pub schedule_id: String,
600    /// Schedule definition and per-call RPC controls.
601    pub options: CreateScheduleOptions,
602}
603
604/// Result of an intercepted schedule create.
605#[non_exhaustive]
606#[derive(Clone, Debug, PartialEq, Eq)]
607pub struct CreateScheduleOutput {
608    /// Schedule ID associated with the created handle.
609    pub schedule_id: String,
610}
611
612impl CreateScheduleOutput {
613    pub(crate) fn new(schedule_id: impl Into<String>) -> Self {
614        Self {
615            schedule_id: schedule_id.into(),
616        }
617    }
618}
619
620/// Input to [`ClientInterceptor::list_schedules_page`].
621#[non_exhaustive]
622#[derive(Clone, Debug)]
623pub struct ListSchedulesPageInput {
624    /// Maximum number of results requested from the service.
625    pub maximum_page_size: i32,
626    /// Visibility query used to select schedules.
627    pub query: String,
628    /// Token identifying the page to retrieve, or empty for the first page.
629    pub next_page_token: Vec<u8>,
630    /// Controls for this page RPC.
631    pub rpc_options: crate::RpcOptions,
632}
633
634/// Result of one intercepted schedule-list page.
635#[non_exhaustive]
636#[derive(Clone, Debug)]
637pub struct ListSchedulesPageOutput {
638    /// Schedule entries returned by the service.
639    pub schedules: Vec<ScheduleListEntry>,
640    /// Token identifying the next page, or empty when no pages remain.
641    pub next_page_token: Vec<u8>,
642}
643
644impl ListSchedulesPageOutput {
645    pub(crate) fn new(schedules: Vec<ScheduleListEntry>, next_page_token: Vec<u8>) -> Self {
646        Self {
647            schedules,
648            next_page_token,
649        }
650    }
651}
652
653/// Input to [`ClientInterceptor::describe_schedule`].
654#[non_exhaustive]
655#[derive(Clone, Debug)]
656pub struct DescribeScheduleInput {
657    /// Schedule ID to describe.
658    pub schedule_id: String,
659    /// Controls for the describe RPC.
660    pub rpc_options: crate::RpcOptions,
661}
662
663/// Result of an intercepted schedule describe.
664#[non_exhaustive]
665#[derive(Clone, Debug)]
666pub struct DescribeScheduleOutput {
667    /// Raw service response decoded after interceptor dispatch.
668    pub response: DescribeScheduleResponse,
669}
670
671impl DescribeScheduleOutput {
672    pub(crate) fn new(response: DescribeScheduleResponse) -> Self {
673        Self { response }
674    }
675}
676
677/// Input to [`ClientInterceptor::update_schedule`].
678#[non_exhaustive]
679#[derive(Clone, Debug)]
680pub struct UpdateScheduleInput {
681    /// Schedule ID to update.
682    pub schedule_id: String,
683    /// Controls shared by the describe and update RPCs.
684    pub rpc_options: crate::RpcOptions,
685}
686
687/// Input to [`ClientInterceptor::send_schedule_update`].
688#[non_exhaustive]
689#[derive(Clone, Debug)]
690pub struct SendScheduleUpdateInput {
691    /// Schedule ID to update.
692    pub schedule_id: String,
693    /// Pre-built schedule update.
694    pub update: ScheduleUpdate,
695    /// Controls for the update RPC.
696    pub rpc_options: crate::RpcOptions,
697}
698
699/// Input to [`ClientInterceptor::delete_schedule`].
700#[non_exhaustive]
701#[derive(Clone, Debug)]
702pub struct DeleteScheduleInput {
703    /// Schedule ID to delete.
704    pub schedule_id: String,
705    /// Controls for the delete RPC.
706    pub rpc_options: crate::RpcOptions,
707}
708
709/// Input to [`ClientInterceptor::pause_schedule`].
710#[non_exhaustive]
711#[derive(Clone, Debug)]
712pub struct PauseScheduleInput {
713    /// Schedule ID to pause.
714    pub schedule_id: String,
715    /// Note attached to the pause operation.
716    pub note: String,
717    /// Controls for the patch RPC.
718    pub rpc_options: crate::RpcOptions,
719}
720
721/// Input to [`ClientInterceptor::unpause_schedule`].
722#[non_exhaustive]
723#[derive(Clone, Debug)]
724pub struct UnpauseScheduleInput {
725    /// Schedule ID to unpause.
726    pub schedule_id: String,
727    /// Note attached to the unpause operation.
728    pub note: String,
729    /// Controls for the patch RPC.
730    pub rpc_options: crate::RpcOptions,
731}
732
733/// Input to [`ClientInterceptor::trigger_schedule`].
734#[non_exhaustive]
735#[derive(Clone, Debug)]
736pub struct TriggerScheduleInput {
737    /// Schedule ID to trigger.
738    pub schedule_id: String,
739    /// Overlap policy for the immediate action.
740    pub overlap_policy: ScheduleOverlapPolicy,
741    /// Controls for the patch RPC.
742    pub rpc_options: crate::RpcOptions,
743}
744
745/// Input to [`ClientInterceptor::backfill_schedule`].
746#[non_exhaustive]
747#[derive(Clone, Debug)]
748pub struct BackfillScheduleInput {
749    /// Schedule ID to backfill.
750    pub schedule_id: String,
751    /// Backfill ranges requested by the caller.
752    pub backfills: Vec<ScheduleBackfill>,
753    /// Controls for the patch RPC.
754    pub rpc_options: crate::RpcOptions,
755}
756
757/// Input to [`ClientInterceptor::complete_async_activity`].
758#[non_exhaustive]
759#[derive(derive_more::Debug)]
760pub struct CompleteAsyncActivityInput {
761    /// Activity being completed.
762    pub identifier: ActivityIdentifier,
763    #[debug(skip)]
764    result: Option<Box<dyn TemporalClientValue>>,
765    /// Controls for the completion RPC.
766    pub rpc_options: crate::RpcOptions,
767}
768
769impl CompleteAsyncActivityInput {
770    pub(crate) fn new<T>(
771        identifier: ActivityIdentifier,
772        result: Option<T>,
773        rpc_options: crate::RpcOptions,
774    ) -> Self
775    where
776        T: TemporalSerializable + Send + 'static,
777    {
778        Self {
779            identifier,
780            result: result.map(|value| Box::new(value) as Box<dyn TemporalClientValue>),
781            rpc_options,
782        }
783    }
784
785    pub(crate) fn into_parts(
786        self,
787    ) -> (
788        ActivityIdentifier,
789        Option<Box<dyn TemporalClientValue>>,
790        crate::RpcOptions,
791    ) {
792        (self.identifier, self.result, self.rpc_options)
793    }
794
795    /// Attempt to access the activity result as a concrete type.
796    pub fn result_ref<T: Any>(&self) -> Option<&T> {
797        self.result
798            .as_ref()
799            .and_then(|result| result.as_any().downcast_ref())
800    }
801
802    /// Attempt to mutably access the activity result as a concrete type.
803    pub fn result_mut<T: Any>(&mut self) -> Option<&mut T> {
804        self.result
805            .as_mut()
806            .and_then(|result| result.as_any_mut().downcast_mut())
807    }
808
809    /// Replace or clear the activity result.
810    pub fn replace_result<T>(&mut self, result: Option<T>)
811    where
812        T: TemporalSerializable + Send + 'static,
813    {
814        self.result = result.map(|value| Box::new(value) as Box<dyn TemporalClientValue>);
815    }
816}
817
818/// Input to [`ClientInterceptor::fail_async_activity`].
819#[non_exhaustive]
820#[derive(derive_more::Debug)]
821pub struct FailAsyncActivityInput {
822    /// Activity being failed.
823    pub identifier: ActivityIdentifier,
824    /// Application failure reported for the activity.
825    pub failure: temporalio_common::error::ApplicationFailure,
826    #[debug(skip)]
827    last_heartbeat_details: Option<Box<dyn TemporalClientValue>>,
828    /// Controls for the failure RPC.
829    pub rpc_options: crate::RpcOptions,
830}
831
832impl FailAsyncActivityInput {
833    pub(crate) fn new<T>(
834        identifier: ActivityIdentifier,
835        failure: temporalio_common::error::ApplicationFailure,
836        last_heartbeat_details: Option<T>,
837        rpc_options: crate::RpcOptions,
838    ) -> Self
839    where
840        T: TemporalSerializable + Send + 'static,
841    {
842        Self {
843            identifier,
844            failure,
845            last_heartbeat_details: last_heartbeat_details
846                .map(|value| Box::new(value) as Box<dyn TemporalClientValue>),
847            rpc_options,
848        }
849    }
850
851    pub(crate) fn into_parts(
852        self,
853    ) -> (
854        ActivityIdentifier,
855        temporalio_common::error::ApplicationFailure,
856        Option<Box<dyn TemporalClientValue>>,
857        crate::RpcOptions,
858    ) {
859        (
860            self.identifier,
861            self.failure,
862            self.last_heartbeat_details,
863            self.rpc_options,
864        )
865    }
866
867    /// Attempt to access the last heartbeat details as a concrete type.
868    pub fn last_heartbeat_details_ref<T: Any>(&self) -> Option<&T> {
869        self.last_heartbeat_details
870            .as_ref()
871            .and_then(|details| details.as_any().downcast_ref())
872    }
873
874    /// Attempt to mutably access the last heartbeat details as a concrete type.
875    pub fn last_heartbeat_details_mut<T: Any>(&mut self) -> Option<&mut T> {
876        self.last_heartbeat_details
877            .as_mut()
878            .and_then(|details| details.as_any_mut().downcast_mut())
879    }
880
881    /// Replace or clear the last heartbeat details.
882    pub fn replace_last_heartbeat_details<T>(&mut self, details: Option<T>)
883    where
884        T: TemporalSerializable + Send + 'static,
885    {
886        self.last_heartbeat_details =
887            details.map(|value| Box::new(value) as Box<dyn TemporalClientValue>);
888    }
889}
890
891/// Input to [`ClientInterceptor::report_async_activity_cancellation`].
892#[non_exhaustive]
893#[derive(derive_more::Debug)]
894pub struct ReportAsyncActivityCancellationInput {
895    /// Activity being reported as cancelled.
896    pub identifier: ActivityIdentifier,
897    #[debug(skip)]
898    details: Option<Box<dyn TemporalClientValue>>,
899    /// Controls for the cancellation RPC.
900    pub rpc_options: crate::RpcOptions,
901}
902
903impl ReportAsyncActivityCancellationInput {
904    pub(crate) fn new<T>(
905        identifier: ActivityIdentifier,
906        details: Option<T>,
907        rpc_options: crate::RpcOptions,
908    ) -> Self
909    where
910        T: TemporalSerializable + Send + 'static,
911    {
912        Self {
913            identifier,
914            details: details.map(|value| Box::new(value) as Box<dyn TemporalClientValue>),
915            rpc_options,
916        }
917    }
918
919    pub(crate) fn into_parts(
920        self,
921    ) -> (
922        ActivityIdentifier,
923        Option<Box<dyn TemporalClientValue>>,
924        crate::RpcOptions,
925    ) {
926        (self.identifier, self.details, self.rpc_options)
927    }
928
929    /// Attempt to access the cancellation details as a concrete type.
930    pub fn details_ref<T: Any>(&self) -> Option<&T> {
931        self.details
932            .as_ref()
933            .and_then(|details| details.as_any().downcast_ref())
934    }
935
936    /// Attempt to mutably access the cancellation details as a concrete type.
937    pub fn details_mut<T: Any>(&mut self) -> Option<&mut T> {
938        self.details
939            .as_mut()
940            .and_then(|details| details.as_any_mut().downcast_mut())
941    }
942
943    /// Replace or clear the cancellation details.
944    pub fn replace_details<T>(&mut self, details: Option<T>)
945    where
946        T: TemporalSerializable + Send + 'static,
947    {
948        self.details = details.map(|value| Box::new(value) as Box<dyn TemporalClientValue>);
949    }
950}
951
952/// Input to [`ClientInterceptor::heartbeat_async_activity`].
953#[non_exhaustive]
954#[derive(derive_more::Debug)]
955pub struct HeartbeatAsyncActivityInput {
956    /// Activity being heartbeated.
957    pub identifier: ActivityIdentifier,
958    #[debug(skip)]
959    details: Option<Box<dyn TemporalClientValue>>,
960    /// Controls for the heartbeat RPC.
961    pub rpc_options: crate::RpcOptions,
962}
963
964impl HeartbeatAsyncActivityInput {
965    pub(crate) fn new<T>(
966        identifier: ActivityIdentifier,
967        details: Option<T>,
968        rpc_options: crate::RpcOptions,
969    ) -> Self
970    where
971        T: TemporalSerializable + Send + 'static,
972    {
973        Self {
974            identifier,
975            details: details.map(|value| Box::new(value) as Box<dyn TemporalClientValue>),
976            rpc_options,
977        }
978    }
979
980    pub(crate) fn into_parts(
981        self,
982    ) -> (
983        ActivityIdentifier,
984        Option<Box<dyn TemporalClientValue>>,
985        crate::RpcOptions,
986    ) {
987        (self.identifier, self.details, self.rpc_options)
988    }
989
990    /// Attempt to access the heartbeat details as a concrete type.
991    pub fn details_ref<T: Any>(&self) -> Option<&T> {
992        self.details
993            .as_ref()
994            .and_then(|details| details.as_any().downcast_ref())
995    }
996
997    /// Attempt to mutably access the heartbeat details as a concrete type.
998    pub fn details_mut<T: Any>(&mut self) -> Option<&mut T> {
999        self.details
1000            .as_mut()
1001            .and_then(|details| details.as_any_mut().downcast_mut())
1002    }
1003
1004    /// Replace or clear the heartbeat details.
1005    pub fn replace_details<T>(&mut self, details: Option<T>)
1006    where
1007        T: TemporalSerializable + Send + 'static,
1008    {
1009        self.details = details.map(|value| Box::new(value) as Box<dyn TemporalClientValue>);
1010    }
1011}
1012
1013/// Intercepts high-level client operations.
1014///
1015/// The first interceptor configured on a client is the outermost interceptor. An interceptor can
1016/// do asynchronous work before and after calling `next`, mutate or replace typed input, or return
1017/// without calling `next` to short-circuit the operation.
1018///
1019/// ```
1020/// use futures_util::future::BoxFuture;
1021/// use std::{sync::Arc, time::Duration};
1022/// use temporalio_client::{
1023///     ClientInterceptor, ClientOptions, Next, StartWorkflowInput, StartWorkflowOutput,
1024///     errors::WorkflowStartError,
1025/// };
1026///
1027/// struct StartTimeout;
1028///
1029/// impl ClientInterceptor for StartTimeout {
1030///     fn start_workflow<'a>(
1031///         &'a self,
1032///         mut input: StartWorkflowInput,
1033///         next: Next<
1034///             'a,
1035///             StartWorkflowInput,
1036///             BoxFuture<'a, Result<StartWorkflowOutput, WorkflowStartError>>,
1037///         >,
1038///     ) -> BoxFuture<'a, Result<StartWorkflowOutput, WorkflowStartError>> {
1039///         Box::pin(async move {
1040///             input.rpc_options.timeout = Some(Duration::from_secs(10));
1041///             let output = next.run(input).await?;
1042///             Ok(output)
1043///         })
1044///     }
1045/// }
1046///
1047/// let _options = ClientOptions::new("my-namespace")
1048///     .client_interceptors(vec![Arc::new(StartTimeout)])
1049///     .build();
1050/// ```
1051pub trait ClientInterceptor: Send + Sync + 'static {
1052    /// Intercept a `start_workflow` operation.
1053    fn start_workflow<'a>(
1054        &'a self,
1055        input: StartWorkflowInput,
1056        next: Next<
1057            'a,
1058            StartWorkflowInput,
1059            BoxFuture<'a, Result<StartWorkflowOutput, WorkflowStartError>>,
1060        >,
1061    ) -> BoxFuture<'a, Result<StartWorkflowOutput, WorkflowStartError>> {
1062        next.run(input)
1063    }
1064
1065    /// Intercept a `list_workflows_page` operation.
1066    fn list_workflows_page<'a>(
1067        &'a self,
1068        input: ListWorkflowsPageInput,
1069        next: Next<
1070            'a,
1071            ListWorkflowsPageInput,
1072            BoxFuture<'a, Result<ListWorkflowsPageOutput, ClientError>>,
1073        >,
1074    ) -> BoxFuture<'a, Result<ListWorkflowsPageOutput, ClientError>> {
1075        next.run(input)
1076    }
1077
1078    /// Intercept a `count_workflows` operation.
1079    fn count_workflows<'a>(
1080        &'a self,
1081        input: CountWorkflowsInput,
1082        next: Next<
1083            'a,
1084            CountWorkflowsInput,
1085            BoxFuture<'a, Result<CountWorkflowsOutput, ClientError>>,
1086        >,
1087    ) -> BoxFuture<'a, Result<CountWorkflowsOutput, ClientError>> {
1088        next.run(input)
1089    }
1090
1091    /// Intercept a `describe_workflow` operation.
1092    fn describe_workflow<'a>(
1093        &'a self,
1094        input: DescribeWorkflowInput,
1095        next: Next<
1096            'a,
1097            DescribeWorkflowInput,
1098            BoxFuture<'a, Result<DescribeWorkflowOutput, WorkflowInteractionError>>,
1099        >,
1100    ) -> BoxFuture<'a, Result<DescribeWorkflowOutput, WorkflowInteractionError>> {
1101        next.run(input)
1102    }
1103
1104    /// Intercept a `fetch_workflow_history_page` operation.
1105    fn fetch_workflow_history_page<'a>(
1106        &'a self,
1107        input: FetchWorkflowHistoryPageInput,
1108        next: Next<
1109            'a,
1110            FetchWorkflowHistoryPageInput,
1111            BoxFuture<'a, Result<FetchWorkflowHistoryPageOutput, WorkflowInteractionError>>,
1112        >,
1113    ) -> BoxFuture<'a, Result<FetchWorkflowHistoryPageOutput, WorkflowInteractionError>> {
1114        next.run(input)
1115    }
1116
1117    /// Intercept a `signal_workflow` operation.
1118    fn signal_workflow<'a>(
1119        &'a self,
1120        input: SignalWorkflowInput,
1121        next: Next<'a, SignalWorkflowInput, BoxFuture<'a, Result<(), WorkflowInteractionError>>>,
1122    ) -> BoxFuture<'a, Result<(), WorkflowInteractionError>> {
1123        next.run(input)
1124    }
1125
1126    /// Intercept a `query_workflow` operation.
1127    fn query_workflow<'a>(
1128        &'a self,
1129        input: QueryWorkflowInput,
1130        next: Next<
1131            'a,
1132            QueryWorkflowInput,
1133            BoxFuture<'a, Result<QueryWorkflowOutput, WorkflowQueryError>>,
1134        >,
1135    ) -> BoxFuture<'a, Result<QueryWorkflowOutput, WorkflowQueryError>> {
1136        next.run(input)
1137    }
1138
1139    /// Intercept a `start_workflow_update` operation.
1140    fn start_workflow_update<'a>(
1141        &'a self,
1142        input: StartWorkflowUpdateInput,
1143        next: Next<
1144            'a,
1145            StartWorkflowUpdateInput,
1146            BoxFuture<'a, Result<StartWorkflowUpdateOutput, WorkflowUpdateError>>,
1147        >,
1148    ) -> BoxFuture<'a, Result<StartWorkflowUpdateOutput, WorkflowUpdateError>> {
1149        next.run(input)
1150    }
1151
1152    /// Intercept a `poll_workflow_update` operation.
1153    fn poll_workflow_update<'a>(
1154        &'a self,
1155        input: PollWorkflowUpdateInput,
1156        next: Next<
1157            'a,
1158            PollWorkflowUpdateInput,
1159            BoxFuture<'a, Result<PollWorkflowUpdateOutput, WorkflowUpdateError>>,
1160        >,
1161    ) -> BoxFuture<'a, Result<PollWorkflowUpdateOutput, WorkflowUpdateError>> {
1162        next.run(input)
1163    }
1164
1165    /// Intercept a `cancel_workflow` operation.
1166    fn cancel_workflow<'a>(
1167        &'a self,
1168        input: CancelWorkflowInput,
1169        next: Next<'a, CancelWorkflowInput, BoxFuture<'a, Result<(), WorkflowInteractionError>>>,
1170    ) -> BoxFuture<'a, Result<(), WorkflowInteractionError>> {
1171        next.run(input)
1172    }
1173
1174    /// Intercept a `terminate_workflow` operation.
1175    fn terminate_workflow<'a>(
1176        &'a self,
1177        input: TerminateWorkflowInput,
1178        next: Next<'a, TerminateWorkflowInput, BoxFuture<'a, Result<(), WorkflowInteractionError>>>,
1179    ) -> BoxFuture<'a, Result<(), WorkflowInteractionError>> {
1180        next.run(input)
1181    }
1182
1183    /// Intercept a `create_schedule` operation.
1184    fn create_schedule<'a>(
1185        &'a self,
1186        input: CreateScheduleInput,
1187        next: Next<
1188            'a,
1189            CreateScheduleInput,
1190            BoxFuture<'a, Result<CreateScheduleOutput, ScheduleError>>,
1191        >,
1192    ) -> BoxFuture<'a, Result<CreateScheduleOutput, ScheduleError>> {
1193        next.run(input)
1194    }
1195
1196    /// Intercept a `list_schedules_page` operation.
1197    fn list_schedules_page<'a>(
1198        &'a self,
1199        input: ListSchedulesPageInput,
1200        next: Next<
1201            'a,
1202            ListSchedulesPageInput,
1203            BoxFuture<'a, Result<ListSchedulesPageOutput, ScheduleError>>,
1204        >,
1205    ) -> BoxFuture<'a, Result<ListSchedulesPageOutput, ScheduleError>> {
1206        next.run(input)
1207    }
1208
1209    /// Intercept a `describe_schedule` operation.
1210    fn describe_schedule<'a>(
1211        &'a self,
1212        input: DescribeScheduleInput,
1213        next: Next<
1214            'a,
1215            DescribeScheduleInput,
1216            BoxFuture<'a, Result<DescribeScheduleOutput, ScheduleError>>,
1217        >,
1218    ) -> BoxFuture<'a, Result<DescribeScheduleOutput, ScheduleError>> {
1219        next.run(input)
1220    }
1221
1222    /// Intercept an `update_schedule` operation.
1223    fn update_schedule<'a>(
1224        &'a self,
1225        input: UpdateScheduleInput,
1226        next: Next<'a, UpdateScheduleInput, BoxFuture<'a, Result<(), ScheduleError>>>,
1227    ) -> BoxFuture<'a, Result<(), ScheduleError>> {
1228        next.run(input)
1229    }
1230
1231    /// Intercept a `send_schedule_update` operation.
1232    fn send_schedule_update<'a>(
1233        &'a self,
1234        input: SendScheduleUpdateInput,
1235        next: Next<'a, SendScheduleUpdateInput, BoxFuture<'a, Result<(), ScheduleError>>>,
1236    ) -> BoxFuture<'a, Result<(), ScheduleError>> {
1237        next.run(input)
1238    }
1239
1240    /// Intercept a `delete_schedule` operation.
1241    fn delete_schedule<'a>(
1242        &'a self,
1243        input: DeleteScheduleInput,
1244        next: Next<'a, DeleteScheduleInput, BoxFuture<'a, Result<(), ScheduleError>>>,
1245    ) -> BoxFuture<'a, Result<(), ScheduleError>> {
1246        next.run(input)
1247    }
1248
1249    /// Intercept a `pause_schedule` operation.
1250    fn pause_schedule<'a>(
1251        &'a self,
1252        input: PauseScheduleInput,
1253        next: Next<'a, PauseScheduleInput, BoxFuture<'a, Result<(), ScheduleError>>>,
1254    ) -> BoxFuture<'a, Result<(), ScheduleError>> {
1255        next.run(input)
1256    }
1257
1258    /// Intercept an `unpause_schedule` operation.
1259    fn unpause_schedule<'a>(
1260        &'a self,
1261        input: UnpauseScheduleInput,
1262        next: Next<'a, UnpauseScheduleInput, BoxFuture<'a, Result<(), ScheduleError>>>,
1263    ) -> BoxFuture<'a, Result<(), ScheduleError>> {
1264        next.run(input)
1265    }
1266
1267    /// Intercept a `trigger_schedule` operation.
1268    fn trigger_schedule<'a>(
1269        &'a self,
1270        input: TriggerScheduleInput,
1271        next: Next<'a, TriggerScheduleInput, BoxFuture<'a, Result<(), ScheduleError>>>,
1272    ) -> BoxFuture<'a, Result<(), ScheduleError>> {
1273        next.run(input)
1274    }
1275
1276    /// Intercept a `backfill_schedule` operation.
1277    fn backfill_schedule<'a>(
1278        &'a self,
1279        input: BackfillScheduleInput,
1280        next: Next<'a, BackfillScheduleInput, BoxFuture<'a, Result<(), ScheduleError>>>,
1281    ) -> BoxFuture<'a, Result<(), ScheduleError>> {
1282        next.run(input)
1283    }
1284
1285    /// Intercept a `complete_async_activity` operation.
1286    fn complete_async_activity<'a>(
1287        &'a self,
1288        input: CompleteAsyncActivityInput,
1289        next: Next<'a, CompleteAsyncActivityInput, BoxFuture<'a, Result<(), AsyncActivityError>>>,
1290    ) -> BoxFuture<'a, Result<(), AsyncActivityError>> {
1291        next.run(input)
1292    }
1293
1294    /// Intercept a `fail_async_activity` operation.
1295    fn fail_async_activity<'a>(
1296        &'a self,
1297        input: FailAsyncActivityInput,
1298        next: Next<'a, FailAsyncActivityInput, BoxFuture<'a, Result<(), AsyncActivityError>>>,
1299    ) -> BoxFuture<'a, Result<(), AsyncActivityError>> {
1300        next.run(input)
1301    }
1302
1303    /// Intercept a `report_async_activity_cancellation` operation.
1304    fn report_async_activity_cancellation<'a>(
1305        &'a self,
1306        input: ReportAsyncActivityCancellationInput,
1307        next: Next<
1308            'a,
1309            ReportAsyncActivityCancellationInput,
1310            BoxFuture<'a, Result<(), AsyncActivityError>>,
1311        >,
1312    ) -> BoxFuture<'a, Result<(), AsyncActivityError>> {
1313        next.run(input)
1314    }
1315
1316    /// Intercept a `heartbeat_async_activity` operation.
1317    fn heartbeat_async_activity<'a>(
1318        &'a self,
1319        input: HeartbeatAsyncActivityInput,
1320        next: Next<
1321            'a,
1322            HeartbeatAsyncActivityInput,
1323            BoxFuture<'a, Result<ActivityHeartbeatResponse, AsyncActivityError>>,
1324        >,
1325    ) -> BoxFuture<'a, Result<ActivityHeartbeatResponse, AsyncActivityError>> {
1326        next.run(input)
1327    }
1328}
1329
1330macro_rules! interceptor_chain {
1331    ($fn_name:ident, $method:ident, $input:ty, $output:ty) => {
1332        pub(crate) fn $fn_name<'a>(
1333            interceptors: &'a [Arc<dyn ClientInterceptor>],
1334            input: $input,
1335            terminal: Next<'a, $input, $output>,
1336        ) -> $output {
1337            if let Some((interceptor, remaining)) = interceptors.split_first() {
1338                let next = Next::new(move |input| $fn_name(remaining, input, terminal));
1339                interceptor.$method(input, next)
1340            } else {
1341                terminal.run(input)
1342            }
1343        }
1344    };
1345}
1346
1347interceptor_chain!(
1348    call_start_workflow,
1349    start_workflow,
1350    StartWorkflowInput,
1351    BoxFuture<'a, Result<StartWorkflowOutput, WorkflowStartError>>
1352);
1353
1354interceptor_chain!(
1355    call_list_workflows_page,
1356    list_workflows_page,
1357    ListWorkflowsPageInput,
1358    BoxFuture<'a, Result<ListWorkflowsPageOutput, ClientError>>
1359);
1360
1361interceptor_chain!(
1362    call_count_workflows,
1363    count_workflows,
1364    CountWorkflowsInput,
1365    BoxFuture<'a, Result<CountWorkflowsOutput, ClientError>>
1366);
1367
1368interceptor_chain!(
1369    call_describe_workflow,
1370    describe_workflow,
1371    DescribeWorkflowInput,
1372    BoxFuture<'a, Result<DescribeWorkflowOutput, WorkflowInteractionError>>
1373);
1374
1375interceptor_chain!(
1376    call_fetch_workflow_history_page,
1377    fetch_workflow_history_page,
1378    FetchWorkflowHistoryPageInput,
1379    BoxFuture<'a, Result<FetchWorkflowHistoryPageOutput, WorkflowInteractionError>>
1380);
1381
1382interceptor_chain!(
1383    call_signal_workflow,
1384    signal_workflow,
1385    SignalWorkflowInput,
1386    BoxFuture<'a, Result<(), WorkflowInteractionError>>
1387);
1388
1389interceptor_chain!(
1390    call_query_workflow,
1391    query_workflow,
1392    QueryWorkflowInput,
1393    BoxFuture<'a, Result<QueryWorkflowOutput, WorkflowQueryError>>
1394);
1395
1396interceptor_chain!(
1397    call_start_workflow_update,
1398    start_workflow_update,
1399    StartWorkflowUpdateInput,
1400    BoxFuture<'a, Result<StartWorkflowUpdateOutput, WorkflowUpdateError>>
1401);
1402
1403interceptor_chain!(
1404    call_poll_workflow_update,
1405    poll_workflow_update,
1406    PollWorkflowUpdateInput,
1407    BoxFuture<'a, Result<PollWorkflowUpdateOutput, WorkflowUpdateError>>
1408);
1409
1410interceptor_chain!(
1411    call_cancel_workflow,
1412    cancel_workflow,
1413    CancelWorkflowInput,
1414    BoxFuture<'a, Result<(), WorkflowInteractionError>>
1415);
1416
1417interceptor_chain!(
1418    call_terminate_workflow,
1419    terminate_workflow,
1420    TerminateWorkflowInput,
1421    BoxFuture<'a, Result<(), WorkflowInteractionError>>
1422);
1423
1424interceptor_chain!(
1425    call_create_schedule,
1426    create_schedule,
1427    CreateScheduleInput,
1428    BoxFuture<'a, Result<CreateScheduleOutput, ScheduleError>>
1429);
1430
1431interceptor_chain!(
1432    call_list_schedules_page,
1433    list_schedules_page,
1434    ListSchedulesPageInput,
1435    BoxFuture<'a, Result<ListSchedulesPageOutput, ScheduleError>>
1436);
1437
1438interceptor_chain!(
1439    call_describe_schedule,
1440    describe_schedule,
1441    DescribeScheduleInput,
1442    BoxFuture<'a, Result<DescribeScheduleOutput, ScheduleError>>
1443);
1444
1445interceptor_chain!(
1446    call_update_schedule,
1447    update_schedule,
1448    UpdateScheduleInput,
1449    BoxFuture<'a, Result<(), ScheduleError>>
1450);
1451
1452interceptor_chain!(
1453    call_send_schedule_update,
1454    send_schedule_update,
1455    SendScheduleUpdateInput,
1456    BoxFuture<'a, Result<(), ScheduleError>>
1457);
1458
1459interceptor_chain!(
1460    call_delete_schedule,
1461    delete_schedule,
1462    DeleteScheduleInput,
1463    BoxFuture<'a, Result<(), ScheduleError>>
1464);
1465
1466interceptor_chain!(
1467    call_pause_schedule,
1468    pause_schedule,
1469    PauseScheduleInput,
1470    BoxFuture<'a, Result<(), ScheduleError>>
1471);
1472
1473interceptor_chain!(
1474    call_unpause_schedule,
1475    unpause_schedule,
1476    UnpauseScheduleInput,
1477    BoxFuture<'a, Result<(), ScheduleError>>
1478);
1479
1480interceptor_chain!(
1481    call_trigger_schedule,
1482    trigger_schedule,
1483    TriggerScheduleInput,
1484    BoxFuture<'a, Result<(), ScheduleError>>
1485);
1486
1487interceptor_chain!(
1488    call_backfill_schedule,
1489    backfill_schedule,
1490    BackfillScheduleInput,
1491    BoxFuture<'a, Result<(), ScheduleError>>
1492);
1493
1494interceptor_chain!(
1495    call_complete_async_activity,
1496    complete_async_activity,
1497    CompleteAsyncActivityInput,
1498    BoxFuture<'a, Result<(), AsyncActivityError>>
1499);
1500
1501interceptor_chain!(
1502    call_fail_async_activity,
1503    fail_async_activity,
1504    FailAsyncActivityInput,
1505    BoxFuture<'a, Result<(), AsyncActivityError>>
1506);
1507
1508interceptor_chain!(
1509    call_report_async_activity_cancellation,
1510    report_async_activity_cancellation,
1511    ReportAsyncActivityCancellationInput,
1512    BoxFuture<'a, Result<(), AsyncActivityError>>
1513);
1514
1515interceptor_chain!(
1516    call_heartbeat_async_activity,
1517    heartbeat_async_activity,
1518    HeartbeatAsyncActivityInput,
1519    BoxFuture<'a, Result<ActivityHeartbeatResponse, AsyncActivityError>>
1520);