@@ -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,70 @@ 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 ` heartbeat() `
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 the [ ` Worker() ` ] ( https://python.temporal.io/temporalio.worker.Worker.html )
1357+ constructor.
1358+
1359+ It often happens that your worker and client interceptors will share code because they implement closely related logic.
1360+ For convenience, you can create an interceptor class that inherits from _ both_ ` client.Interceptor ` and
1361+ ` worker.Interceptor ` (their method sets do not overlap). You can then pass this in the ` interceptors ` argument of
1362+ ` Client.connect() ` when starting your worker _ as well as_ in your client/starter code. If you do this, your worker will
1363+ automatically pick up the interceptors from its underlying client (and you should not pass them directly to the
1364+ ` Worker() ` constructor).
1365+
1366+ This is best explained by example. The [ Context Propagation Interceptor
1367+ Sample] ( https://github.com/temporalio/samples-python/tree/main/context_propagation ) is a good starting point. In
1368+ [ context_propagation/interceptor.py] ( https://github.com/temporalio/samples-python/blob/main/context_propagation/interceptor.py )
1369+ a class is defined that inherits from both ` client.Interceptor ` and ` worker.Interceptor ` . It implements the various
1370+ methods such that the outbound client and workflow calls set a certain key in the outbound ` headers ` field, and the
1371+ inbound workflow and activity calls retrieve the header value from the inbound workflow/activity input data. An instance
1372+ of this interceptor class is passed to ` Client.connect() ` when [ starting the
1373+ worker] ( https://github.com/temporalio/samples-python/blob/main/context_propagation/worker.py ) and when connecting the
1374+ client in the [ workflow starter
1375+ code] ( https://github.com/temporalio/samples-python/blob/main/context_propagation/starter.py ) .
1376+
1377+
13131378### Nexus
13141379
13151380⚠️ ** Nexus support is currently at an experimental release stage. Backwards-incompatible changes are anticipated until a stable release is announced.** ⚠️
0 commit comments