Skip to content

Commit c9bc35e

Browse files
committed
docs: document platform-level cancellation via external signal
Add documentation for the `signal` option on `newTurn()`, which lets the server pass `req.signal` to abort turns on request cancellation or serverless function timeout. Updates cancel feature page (new section), turns concept page (abort signal section), and server transport internals (newTurn description).
1 parent 9bb7f9e commit c9bc35e

File tree

3 files changed

+24
-3
lines changed

3 files changed

+24
-3
lines changed

docs/concepts/turns.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,13 @@ On the client, each `send()` call returns its own `ActiveTurn`. Cancellation is
110110

111111
## The abort signal
112112

113-
Each server-side turn exposes an `AbortSignal` that fires when the turn is cancelled:
113+
Each server-side turn exposes an `AbortSignal` that fires when the turn is cancelled. The signal has two sources: Ably cancel messages from clients, and an optional external signal (typically `req.signal`) for platform-level cancellation like request cancellation or serverless function timeout.
114114

115115
```typescript
116116
const turn = transport.newTurn({
117117
turnId,
118118
clientId,
119+
signal: req.signal, // platform-level cancellation (optional)
119120
onCancel: async (request) => {
120121
// Return false to reject the cancel (turn continues)
121122
// Return true to allow it (abortSignal fires)
@@ -132,6 +133,8 @@ const turn = transport.newTurn({
132133
const result = streamText({ model, messages, abortSignal: turn.abortSignal });
133134
```
134135

135-
The `onCancel` hook lets you authorize cancellation - useful for preventing one user from cancelling another user's turn. The `onAbort` hook runs after the signal fires, giving you a chance to write final data before the stream closes.
136+
The `onCancel` hook lets you authorize cancellation - useful for preventing one user from cancelling another user's turn. It only fires for Ably cancel messages, not for the external signal. The `onAbort` hook runs after the signal fires from either source, giving you a chance to write final data before the stream closes.
137+
138+
See [Platform-level cancellation](../features/cancel.md#platform-level-cancellation) for details on the `signal` option.
136139

137140
For the internal mechanics, see [TurnManager](../internals/transport-components.md#turnmanager) and [pipeStream](../internals/transport-components.md#pipestream) for how abort signals flow through the system, and [Wire protocol](../internals/wire-protocol.md#turn-lifecycle-over-the-wire) for the message sequence on the channel.

docs/features/cancel.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,24 @@ sequenceDiagram
102102

103103
The client closes its local streams immediately on cancel - it doesn't wait for the server to confirm. The server-side turn ends with `reason: 'cancelled'`, which all clients see via turn lifecycle events.
104104

105+
## Platform-level cancellation
106+
107+
Ably cancel messages are the primary cancellation path, but the server may also need to abort a turn when the platform signals shutdown - the HTTP request is cancelled, or a serverless function hits its execution timeout.
108+
109+
Pass the platform's abort signal to `newTurn()` via the `signal` option:
110+
111+
```typescript
112+
const turn = transport.newTurn({
113+
turnId,
114+
clientId,
115+
signal: req.signal, // fires on request cancellation or function timeout
116+
});
117+
```
118+
119+
When the external signal fires, it aborts the turn through the same path as an Ably cancel message - `turn.abortSignal` fires, `streamText` stops generation, and `pipeStream` closes the stream. The `onCancel` hook is **not** called for platform-level signals (it only fires for Ably cancel messages), but `onAbort` runs normally.
120+
121+
Internally, `AbortSignal.any()` composes the external signal with the turn's own abort controller, so either source triggers the same downstream abort.
122+
105123
## Cancel on close
106124

107125
Cancel active turns as part of transport teardown:

docs/internals/server-transport.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ sequenceDiagram
4040

4141
Synchronous - no channel activity. Creates a `Turn` object and registers it for cancel routing immediately, so early cancels (arriving before `start()`) fire the abort signal.
4242

43-
Each turn gets its own `AbortController`. The `abortSignal` property exposes it so the server app can pass it to LLM calls.
43+
Each turn gets its own `AbortController`. If `opts.signal` is provided (typically `req.signal` from the HTTP request), `AbortSignal.any()` composes it with the controller's signal into a single composite signal. The `abortSignal` property exposes this composite signal so the server app can pass it to LLM calls. Either source - an Ably cancel message or the external signal - triggers the same downstream abort.
4444

4545
### start
4646

0 commit comments

Comments
 (0)