@@ -94,6 +94,7 @@ informal introduction to the features and their implementation.
9494 - [ Heartbeating and Cancellation] ( #heartbeating-and-cancellation )
9595 - [ Worker Shutdown] ( #worker-shutdown )
9696 - [ Testing] ( #testing-1 )
97+ - [ Interceptors] ( #interceptors )
9798 - [ Nexus] ( #nexus )
9899 - [ Workflow Replay] ( #workflow-replay )
99100 - [ Observability] ( #observability )
@@ -1310,6 +1311,68 @@ affect calls activity code might make to functions on the `temporalio.activity`
13101311* ` worker_shutdown() ` can be invoked to simulate a worker shutdown during execution of the activity
13111312
13121313
1314+ ### Interceptors
1315+
1316+ The behavior of the SDK can be customized in many useful ways by modifying inbound and outbound calls using
1317+ interceptors. This is similar to the use of middleware in other frameworks.
1318+
1319+ There are five categories of inbound and outbound calls that you can modify in this way:
1320+
1321+ 1 . Outbound client calls, such as ` start_workflow() ` , ` signal_workflow() ` , ` list_workflows() ` , ` update_schedule() ` , etc.
1322+
1323+ 2 . Inbound workflow calls: ` execute_workflow() ` , ` handle_signal() ` , ` handle_update_handler() ` , etc
1324+
1325+ 3 . Outbound workflow calls: ` start_activity() ` , ` start_child_workflow() ` , ` start_nexus_operation() ` , etc
1326+
1327+ 4 . Inbound call to execute an activity: ` execute_activity() `
1328+
1329+ 5 . Outbound activity calls: ` info() ` and ` hearbeat() `
1330+
1331+
1332+ To modify outbound client calls, define a class inheriting from
1333+ [ ` client.Interceptor ` ] ( https://python.temporal.io/temporalio.client.Interceptor.html ) , and implement the method
1334+ ` intercept_client() ` to return an instance of
1335+ [ ` OutboundInterceptor ` ] ( https://python.temporal.io/temporalio.client.OutboundInterceptor.html ) that implements the
1336+ subset of outbound client calls that you wish to modify.
1337+
1338+ Then, pass a list containing an instance of your ` client.Interceptor ` class as the
1339+ ` interceptors ` argument of [ ` Client.connect() ` ] ( https://python.temporal.io/temporalio.client.Client.html#connect ) .
1340+
1341+ The purpose of the interceptor framework is that the methods you implement on your interceptor classes can perform
1342+ arbitrary side effects and/or arbitrary modifications to the data, before it is received by the SDK's "real"
1343+ implementation. The ` interceptors ` list can contain multiple interceptors. In this case they form a chain: a method
1344+ implemented on an interceptor instance in the list can perform side effects, and modify the data, before passing it on
1345+ to the corresponding method on the next interceptor in the list. Your interceptor classes need not implement every
1346+ method; the default implementation is always to pass the data on to the next method in the interceptor chain.
1347+
1348+ The remaining four categories are worker calls. To modify these, define a class inheriting from
1349+ [ ` worker.Interceptor ` ] ( https://python.temporal.io/temporalio.worker.Interceptor.html ) and implement methods on that
1350+ class to define the
1351+ [ ` ActivityInboundInterceptor ` ] ( https://python.temporal.io/temporalio.worker.ActivityInboundInterceptor.html ) ,
1352+ [ ` ActivityOutboundInterceptor ` ] ( https://python.temporal.io/temporalio.worker.ActivityOutboundInterceptor.html ) ,
1353+ [ ` WorkflowInboundInterceptor ` ] ( https://python.temporal.io/temporalio.worker.WorkflowInboundInterceptor.html ) , and
1354+ [ ` WorkflowOutboundInterceptor ` ] ( https://python.temporal.io/temporalio.worker.WorkflowOutboundInterceptor.html ) classes
1355+ that you wish to use to effect your modifications. Then, pass a list containing an instance of your ` worker.Interceptor `
1356+ class as the ` interceptors ` argument of ` Client.connect() ` .
1357+
1358+ You can also pass worker interceptors as the ` interceptor ` argument to the
1359+ [ ` Worker() ` ] ( https://python.temporal.io/temporalio.worker.Worker.html ) constructor but, if you do, do not pass the same
1360+ ones to ` Client.connect() ` . Finally, for convenience, it's common to define a class inheriting from _ both_
1361+ ` client.Interceptor ` and ` worker.Interceptor ` (their method sets do not overlap), and define all your interceptor
1362+ customizations in the methods of that class.
1363+
1364+ This is best explained by example. The [ Context Propagation Interceptor
1365+ Sample] ( https://github.com/temporalio/samples-python/tree/main/context_propagation ) is a good starting point. In
1366+ [ context_propagation/interceptor.py] ( https://github.com/temporalio/samples-python/blob/main/context_propagation/interceptor.py )
1367+ a class is defined that inherits from both ` client.Interceptor ` and ` worker.Interceptor ` . It implements the various
1368+ methods such that the outbound client and workflow calls set a certain key in the outbound ` headers ` field, and the
1369+ inbound workflow and activity calls retrieve the header value from the inbound workflow/activity input data. An instance
1370+ of this interceptor class is passed to ` Client.connect ` when [ starting the
1371+ worker] ( https://github.com/temporalio/samples-python/blob/main/context_propagation/worker.py ) and when connecting the
1372+ client in the [ workflow starter
1373+ code] ( https://github.com/temporalio/samples-python/blob/main/context_propagation/starter.py ) .
1374+
1375+
13131376### Nexus
13141377
13151378⚠️ ** Nexus support is currently at an experimental release stage. Backwards-incompatible changes are anticipated until a stable release is announced.** ⚠️
0 commit comments