|
| 1 | +# Plugins |
| 2 | + |
| 3 | +Create plugins for instrumenting durable execution lifecycle events. Each SDK |
| 4 | +calls plugin hooks at invocation, operation, and user-function boundaries, so |
| 5 | +you can integrate external tooling, such as observability platforms, without |
| 6 | +changing your handler logic. For example, you can use a plugin to emit a metric |
| 7 | +or trace span each time an operation runs. Errors thrown by a plugin are caught |
| 8 | +and logged, and never affect the execution outcome. |
| 9 | + |
| 10 | +!!! note "Experimental feature" |
| 11 | + |
| 12 | + The plugin interface is currently experimental and may change in a |
| 13 | + future release. Feedback is welcome, please share your input through our |
| 14 | + [GitHub Discussion](https://github.com/aws/aws-durable-execution-docs/discussions/206). |
| 15 | + |
| 16 | +## Define a plugin |
| 17 | + |
| 18 | +A plugin implements any of the following lifecycle hooks, and the SDK calls |
| 19 | +them as the execution runs. Every hook is optional, so implement only the |
| 20 | +ones you need. |
| 21 | + |
| 22 | +The following example plugin shows how to implement every available hook. |
| 23 | + |
| 24 | +=== "TypeScript" |
| 25 | + |
| 26 | + ```typescript |
| 27 | + --8<-- "examples/typescript/sdk-reference/plugins/complete-plugin.ts" |
| 28 | + ``` |
| 29 | + |
| 30 | +=== "Python" |
| 31 | + |
| 32 | + ```python |
| 33 | + --8<-- "examples/python/sdk-reference/plugins/complete-plugin.py" |
| 34 | + ``` |
| 35 | + |
| 36 | +=== "Java" |
| 37 | + |
| 38 | + ```java |
| 39 | + --8<-- "examples/java/sdk-reference/plugins/complete-plugin.java" |
| 40 | + ``` |
| 41 | + |
| 42 | +The hooks fire at three boundaries: invocation, operation, and the user |
| 43 | +function. Each hook receives an info object describing that event, including |
| 44 | +fields like operation identity, timestamps, or error details. |
| 45 | + |
| 46 | +### Invocation hooks |
| 47 | + |
| 48 | +Invocation hooks run when a Lambda invocation of the execution starts or ends. |
| 49 | +The SDK passes an `isFirstInvocation` flag to the start hook, which indicates |
| 50 | +whether this is the execution's first invocation or a replay. |
| 51 | + |
| 52 | +=== "TypeScript" |
| 53 | + |
| 54 | + ```typescript |
| 55 | + --8<-- "examples/typescript/sdk-reference/plugins/invocation-hooks.ts" |
| 56 | + ``` |
| 57 | + |
| 58 | + `onInvocationStart` and `onInvocationEnd` both return `Promise<void>`, and |
| 59 | + the SDK awaits them before continuing the execution. |
| 60 | + |
| 61 | +=== "Python" |
| 62 | + |
| 63 | + ```python |
| 64 | + --8<-- "examples/python/sdk-reference/plugins/invocation-hooks.py" |
| 65 | + ``` |
| 66 | + |
| 67 | +=== "Java" |
| 68 | + |
| 69 | + ```java |
| 70 | + --8<-- "examples/java/sdk-reference/plugins/invocation-hooks.java" |
| 71 | + ``` |
| 72 | + |
| 73 | + The SDK awaits `onInvocationEnd` before continuing the execution. All other |
| 74 | + hooks are fire-and-forget. |
| 75 | + |
| 76 | +### Operation hooks |
| 77 | + |
| 78 | +Operation hooks run when a durable operation, such as a step or wait, starts |
| 79 | +or reaches a terminal status. |
| 80 | + |
| 81 | +=== "TypeScript" |
| 82 | + |
| 83 | + ```typescript |
| 84 | + --8<-- "examples/typescript/sdk-reference/plugins/operation-hooks.ts" |
| 85 | + ``` |
| 86 | + |
| 87 | + The `isReplay` field on `OperationInfo` indicates whether the hook is |
| 88 | + firing for the first time or during a replay. |
| 89 | + |
| 90 | +=== "Python" |
| 91 | + |
| 92 | + ```python |
| 93 | + --8<-- "examples/python/sdk-reference/plugins/operation-hooks.py" |
| 94 | + ``` |
| 95 | + |
| 96 | +=== "Java" |
| 97 | + |
| 98 | + ```java |
| 99 | + --8<-- "examples/java/sdk-reference/plugins/operation-hooks.java" |
| 100 | + ``` |
| 101 | + |
| 102 | +### User-function hooks |
| 103 | + |
| 104 | +User-function hooks run when the code you supply for an operation begins or |
| 105 | +finishes, on that operation's thread. |
| 106 | + |
| 107 | +=== "TypeScript" |
| 108 | + |
| 109 | + ```typescript |
| 110 | + --8<-- "examples/typescript/sdk-reference/plugins/user-function-hooks.ts" |
| 111 | + ``` |
| 112 | + |
| 113 | + These hooks fire around each step or wait-for-condition attempt. Child |
| 114 | + context functions are instrumented through `wrapChildContextFn`, a |
| 115 | + TypeScript-only hook described in |
| 116 | + [TypeScript-only hooks](#typescript-only-hooks). |
| 117 | + |
| 118 | +=== "Python" |
| 119 | + |
| 120 | + ```python |
| 121 | + --8<-- "examples/python/sdk-reference/plugins/user-function-hooks.py" |
| 122 | + ``` |
| 123 | + |
| 124 | + These hooks fire around step attempts, child context functions, and |
| 125 | + wait-for-condition checks. |
| 126 | + |
| 127 | +=== "Java" |
| 128 | + |
| 129 | + ```java |
| 130 | + --8<-- "examples/java/sdk-reference/plugins/user-function-hooks.java" |
| 131 | + ``` |
| 132 | + |
| 133 | + These hooks fire around step attempts, child context functions, and |
| 134 | + wait-for-condition checks. |
| 135 | + |
| 136 | +## Use a plugin |
| 137 | + |
| 138 | +Provide plugins in the durable handler configuration. The SDK calls each plugin |
| 139 | +in the order you provide. |
| 140 | + |
| 141 | +=== "TypeScript" |
| 142 | + |
| 143 | + ```typescript |
| 144 | + --8<-- "examples/typescript/sdk-reference/plugins/use-plugin.ts" |
| 145 | + ``` |
| 146 | + |
| 147 | +=== "Python" |
| 148 | + |
| 149 | + ```python |
| 150 | + --8<-- "examples/python/sdk-reference/plugins/use-plugin.py" |
| 151 | + ``` |
| 152 | + |
| 153 | +=== "Java" |
| 154 | + |
| 155 | + ```java |
| 156 | + --8<-- "examples/java/sdk-reference/plugins/use-plugin.java" |
| 157 | + ``` |
| 158 | + |
| 159 | +## Logging from a plugin |
| 160 | + |
| 161 | +A plugin can add custom fields to log entries so that logs emitted during the |
| 162 | +execution carry extra context. |
| 163 | + |
| 164 | +=== "TypeScript" |
| 165 | + |
| 166 | + `enrichLogContext` is called for each log entry, and the fields it returns |
| 167 | + are added to that entry. The enrichment applies wherever the SDK logs. See |
| 168 | + [Logging](../observability/logging.md) for more about the SDK logger. |
| 169 | + |
| 170 | + ```typescript |
| 171 | + --8<-- "examples/typescript/sdk-reference/plugins/log-enrichment-hook.ts" |
| 172 | + ``` |
| 173 | + |
| 174 | +=== "Python" |
| 175 | + |
| 176 | + A plugin can enrich logs by installing a standard `logging.Filter` on the |
| 177 | + root logger, usually in its constructor. The filter runs for every log |
| 178 | + record on the emitting thread, so it can add fields that reflect the |
| 179 | + plugin's current state. See |
| 180 | + [Logging](../observability/logging.md) for more about the SDK logger. |
| 181 | + |
| 182 | + ```python |
| 183 | + --8<-- "examples/python/sdk-reference/plugins/log-enrichment.py" |
| 184 | + ``` |
| 185 | + |
| 186 | +=== "Java" |
| 187 | + |
| 188 | + The `onUserFunctionStart` and `onUserFunctionEnd` hooks run on the same |
| 189 | + thread as the user function, so a plugin can add fields to the SLF4J MDC in |
| 190 | + those hooks and the logs the function emits include those fields. See |
| 191 | + [Logging](../observability/logging.md) for more information. |
| 192 | + |
| 193 | + ```java |
| 194 | + --8<-- "examples/java/sdk-reference/plugins/log-enrichment.java" |
| 195 | + ``` |
| 196 | + |
| 197 | +## TypeScript-only hooks |
| 198 | + |
| 199 | +!!! warning "TypeScript only" |
| 200 | + |
| 201 | + These hooks exist only in the TypeScript SDK. The Python and Java plugin |
| 202 | + interfaces provide observer hooks only, and these methods will not be added |
| 203 | + to them. |
| 204 | + |
| 205 | +The TypeScript SDK adds wrapper hooks and a checkpoint-change hook. These hooks |
| 206 | +were added to match the callback style common in JavaScript. |
| 207 | + |
| 208 | +### Wrapper hooks |
| 209 | + |
| 210 | +Wrapper hooks run code around a unit of work. `wrapInvocation` wraps the whole |
| 211 | +invocation, `wrapChildContextFn` wraps a child context function, and |
| 212 | +`wrapOperationAttemptFn` wraps a single step or wait-for-condition attempt. Use |
| 213 | +them to run setup and teardown around the work, such as establishing context |
| 214 | +that the wrapped code runs within. |
| 215 | + |
| 216 | +```typescript |
| 217 | +--8<-- "examples/typescript/sdk-reference/plugins/wrapper-hooks.ts" |
| 218 | +``` |
| 219 | + |
| 220 | +### Checkpoint-change hook |
| 221 | + |
| 222 | +`onOperationChange` fires when a checkpoint response reports that operations |
| 223 | +changed status. It receives the operations that changed and a snapshot of all |
| 224 | +operations. |
| 225 | + |
| 226 | +```typescript |
| 227 | +--8<-- "examples/typescript/sdk-reference/plugins/checkpoint-change-hook.ts" |
| 228 | +``` |
0 commit comments