Skip to content

Commit 1fec723

Browse files
authored
Add documentation of interceptors to README (#970)
1 parent f4ca16d commit 1fec723

File tree

1 file changed

+65
-0
lines changed

1 file changed

+65
-0
lines changed

README.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)