Skip to content

Commit 67e7f4b

Browse files
author
rivet-docs-sync[bot]
committed
docs(actors): sync from rivet-dev/actors@89c31e9
1 parent c0bdc4b commit 67e7f4b

14 files changed

Lines changed: 263 additions & 17 deletions

File tree

vendor/actors/docs/content/docs/general/environment-variables.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ These variables configure how clients connect to your actors.
3838
| `RIVET_RUN_ENGINE_HOST` | Host to bind the spawned local engine process to. Defaults to `127.0.0.1`. |
3939
| `RIVET_RUN_ENGINE_PORT` | Port to bind the spawned local engine process to. Defaults to `6420`. |
4040
| `RIVET_RUN_ENGINE_VERSION` | Version of engine to download |
41+
| `RIVET_RUN_SERVICES` | Set to `1` to run Services with a local Engine, or `0` to disable it. By default, Services follows RivetKit's local-Engine decision. |
42+
| `RIVET_SERVICES_BINARY` | Path to a local `rivet-services` binary. |
4143

4244
## Inspector
4345

vendor/actors/docs/content/docs/limits.mdx

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,9 @@ These limits affect actions that do not use `.connect()` and [low-level HTTP req
5353
| Name | Soft Limit | Hard Limit | Description |
5454
|------|------------|------------|-------------|
5555
| Max request body size || 20 MiB | Maximum size of HTTP request bodies. |
56-
| Max response body size || 20 MiB | Maximum size of HTTP response bodies. |
57-
| Request timeout | 60 seconds || Maximum time for an `onRequest` handler to complete. Defaults to `actionTimeout`; configure with `actionTimeout`. |
58-
59-
### Actions
60-
61-
| Name | Soft Limit | Hard Limit | Description |
62-
|------|------------|------------|-------------|
63-
| Max actions per actor | 128 | None | Maximum number of action handlers defined on one actor. Nested action groups count each leaf handler. Configurable via `maxActions`. |
56+
| Max buffered response body size || 20 MiB | Maximum size of a non-streaming HTTP response. Streaming responses may transfer more than 20 MiB over their lifetime and are flow controlled instead of buffered in full. |
57+
| Response start timeout || 5 minutes by default | Maximum time for `onRequest` to return response headers. It does not limit the lifetime of a response stream after the headers arrive. Self-hosted operators can configure `pegboard.gateway_response_start_timeout_ms`. |
58+
| Streaming response idle timeout || None by default | Rivet does not close an otherwise healthy stream because no body chunk was produced. Other proxies and hosting platforms may impose their own idle timeouts, so SSE handlers should send periodic comment heartbeats. |
6459

6560
### Networking
6661

@@ -145,7 +140,8 @@ See [Actor Input](/actors/docs/input) for details.
145140
| Name | Soft Limit | Hard Limit | Description |
146141
|------|------------|------------|-------------|
147142
| Action timeout | 60 seconds || Timeout for RPC actions. Configurable via `actionTimeout`. |
148-
| On request timeout | 60 seconds || Timeout for raw `onRequest` handlers. Defaults to `actionTimeout`; configure with `actionTimeout`. |
143+
| Raw HTTP response start timeout || 5 minutes by default | Time allowed for a raw `onRequest` handler to return response headers. `actionTimeout` does not apply to raw HTTP handlers, and a streaming response has no fixed total-duration timeout after it starts. Self-hosted operators can configure `pegboard.gateway_response_start_timeout_ms`. |
144+
| Raw HTTP stream idle timeout || None by default | Time allowed between response chunks. Self-hosted operators can configure `pegboard.gateway_response_chunk_idle_timeout_ms`; send SSE heartbeats more frequently than that value when enabled. |
149145
| On before connect timeout | 5 seconds || Timeout for the `onBeforeConnect` hook. Configurable via `onBeforeConnectTimeout`. |
150146
| Create vars timeout | 5 seconds || Timeout for `createVars` hook. Configurable via `createVarsTimeout`. |
151147
| Create conn state timeout | 5 seconds || Timeout for `createConnState` hook. Configurable via `createConnStateTimeout`. |

vendor/actors/docs/content/docs/request-handler.mdx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,17 @@ The `onRequest` handler processes HTTP requests sent to your actor. It receives
2626

2727
See also the [raw fetch handler example](https://github.com/rivet-dev/rivet/tree/main/examples/raw-fetch-handler).
2828

29+
## Streaming Responses & Server-Sent Events
30+
31+
Return a `Response` with a `ReadableStream` body to stream data as it becomes available. For server-sent events (SSE), set `Content-Type` to `text/event-stream` and format each event as one or more fields followed by a blank line.
32+
33+
<CodeGroup>
34+
<CodeSnippet file="examples/docs/actors-request-handler/sse.ts" title="actor.ts" />
35+
<CodeSnippet file="examples/docs/actors-request-handler/sse-client.ts" title="client.ts" />
36+
</CodeGroup>
37+
38+
Rivet keeps the actor and request lifecycle active until the response stream closes, errors, or the client disconnects. The request's `AbortSignal` is aborted when the downstream client disconnects, so stop producers and release request-scoped resources when `request.signal` fires. Also implement the stream's `cancel()` callback for cleanup.
39+
2940
## Sending Requests To Actors
3041

3142
### Via RivetKit Client
@@ -87,7 +98,6 @@ The `onRequest` handler is WinterTC compliant and will work with existing librar
8798

8899
## Limitations
89100

90-
- Does not support streaming responses & server-sent events at the moment. See the [tracking issue](https://github.com/rivet-dev/rivet/issues/3529).
91101
- `OPTIONS` requests currently are handled by Rivet and are not passed to `onRequest`
92102

93103
## Advanced
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
---
2+
title: "Durable Streams"
3+
description: "Run the Durable Streams protocol locally and deploy it with Rivet."
4+
---
5+
6+
[Durable Streams](https://github.com/durable-streams/durable-streams) is a protocol for append-only streams with catch-up reads, live updates, and resumable offsets. Rivet provides an implementation backed by Rivet Actors.
7+
8+
## Quickstart
9+
10+
<Steps>
11+
12+
<Step title="Run locally">
13+
14+
Start the local Rivet control plane and Services:
15+
16+
```sh
17+
npx @rivet-dev/services dev
18+
```
19+
20+
The command prints the local URL when it is ready. Durable Streams is available at `http://127.0.0.1:8642/durable-streams/v1/stream/<path>`.
21+
22+
</Step>
23+
24+
<Step title="Connect to a stream">
25+
26+
<Tabs>
27+
28+
<Tab title="TypeScript client">
29+
30+
Install the official client:
31+
32+
```sh
33+
npm install @durable-streams/client
34+
```
35+
36+
<CodeSnippet file="examples/docs/actors-integrations-durable-streams/client.ts" title="client.ts" />
37+
38+
</Tab>
39+
40+
<Tab title="HTTP">
41+
42+
Create a stream, append a record, and read its contents:
43+
44+
```sh
45+
curl -i -X PUT \
46+
-H 'content-type: application/json' \
47+
--data '[{"message":"hello"}]' \
48+
http://127.0.0.1:8642/durable-streams/v1/stream/demo
49+
50+
curl -i -X POST \
51+
-H 'content-type: application/json' \
52+
--data '{"message":"world"}' \
53+
http://127.0.0.1:8642/durable-streams/v1/stream/demo
54+
55+
curl 'http://127.0.0.1:8642/durable-streams/v1/stream/demo?offset=-1'
56+
```
57+
58+
</Tab>
59+
60+
</Tabs>
61+
62+
</Step>
63+
64+
<Step title="Deploy">
65+
66+
Set up the `services` pool in [Rivet Cloud](https://dashboard.rivet.dev/), or follow the [self-hosting guide in the Durable Streams README](https://github.com/rivet-dev/rivet-durable-streams#self-hosted).
67+
68+
</Step>
69+
70+
</Steps>

vendor/actors/docs/sidebar.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,10 @@
423423
{
424424
"title": "Integrations",
425425
"pages": [
426+
{
427+
"title": "Durable Streams",
428+
"href": "/actors/integrations/durable-streams"
429+
},
426430
{
427431
"title": "Flue",
428432
"href": "/actors/integrations/flue"

vendor/actors/engine/artifacts/config-schema.json

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,17 @@
7373
}
7474
]
7575
},
76+
"features": {
77+
"default": null,
78+
"anyOf": [
79+
{
80+
"$ref": "#/definitions/Features"
81+
},
82+
{
83+
"type": "null"
84+
}
85+
]
86+
},
7687
"guard": {
7788
"default": null,
7889
"anyOf": [
@@ -465,6 +476,24 @@
465476
}
466477
]
467478
},
479+
"Features": {
480+
"type": "object",
481+
"properties": {
482+
"guard_gateway_v3": {
483+
"description": "Controls routing to the streaming Guard Gateway V3 implementation.",
484+
"default": null,
485+
"anyOf": [
486+
{
487+
"$ref": "#/definitions/GuardGatewayV3"
488+
},
489+
{
490+
"type": "null"
491+
}
492+
]
493+
}
494+
},
495+
"additionalProperties": false
496+
},
468497
"FileSystem": {
469498
"type": "object",
470499
"required": [
@@ -675,6 +704,35 @@
675704
},
676705
"additionalProperties": false
677706
},
707+
"GuardGatewayV3": {
708+
"type": "object",
709+
"properties": {
710+
"mode": {
711+
"default": "off",
712+
"allOf": [
713+
{
714+
"$ref": "#/definitions/GuardGatewayV3Mode"
715+
}
716+
]
717+
},
718+
"percentage": {
719+
"default": 0,
720+
"type": "integer",
721+
"format": "uint8",
722+
"maximum": 100.0,
723+
"minimum": 0.0
724+
}
725+
},
726+
"additionalProperties": false
727+
},
728+
"GuardGatewayV3Mode": {
729+
"type": "string",
730+
"enum": [
731+
"off",
732+
"opportunistic",
733+
"on"
734+
]
735+
},
678736
"Https": {
679737
"type": "object",
680738
"required": [
@@ -1008,6 +1066,24 @@
10081066
"format": "uint",
10091067
"minimum": 0.0
10101068
},
1069+
"gateway_http_response_body_channel_capacity": {
1070+
"description": "Number of body chunks buffered between a streaming response handler and its HTTP client.",
1071+
"type": [
1072+
"integer",
1073+
"null"
1074+
],
1075+
"format": "uint",
1076+
"minimum": 0.0
1077+
},
1078+
"gateway_http_response_queue_max_messages": {
1079+
"description": "Maximum number of envoy response messages buffered per HTTP request.",
1080+
"type": [
1081+
"integer",
1082+
"null"
1083+
],
1084+
"format": "uint",
1085+
"minimum": 0.0
1086+
},
10111087
"gateway_hws_max_pending_size": {
10121088
"description": "Max pending message buffer size for hibernating WebSockets in bytes.",
10131089
"type": [
@@ -1026,6 +1102,15 @@
10261102
"format": "uint64",
10271103
"minimum": 0.0
10281104
},
1105+
"gateway_response_chunk_idle_timeout_ms": {
1106+
"description": "Timeout between streaming HTTP response chunks in milliseconds.\n\nDisabled when unset so long-lived streams such as SSE may remain idle.",
1107+
"type": [
1108+
"integer",
1109+
"null"
1110+
],
1111+
"format": "uint64",
1112+
"minimum": 0.0
1113+
},
10291114
"gateway_response_start_timeout_ms": {
10301115
"description": "Timeout for response to start in milliseconds.",
10311116
"type": [
@@ -1035,6 +1120,15 @@
10351120
"format": "uint64",
10361121
"minimum": 0.0
10371122
},
1123+
"gateway_streaming_http_response_queue_max_bytes": {
1124+
"description": "Maximum streaming response bytes buffered per HTTP request.",
1125+
"type": [
1126+
"integer",
1127+
"null"
1128+
],
1129+
"format": "uint",
1130+
"minimum": 0.0
1131+
},
10381132
"gateway_tunnel_ping_timeout_ms": {
10391133
"description": "Tunnel ping timeout in milliseconds.",
10401134
"type": [
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { DurableStream } from "@durable-streams/client";
2+
3+
const stream = await DurableStream.create({
4+
url: "http://127.0.0.1:8642/durable-streams/v1/stream/demo",
5+
contentType: "application/json",
6+
});
7+
8+
await stream.append(JSON.stringify({ message: "hello" }));

vendor/actors/examples/docs/actors-limits/actor-options.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { actor } from "rivetkit";
22

33
const myActor = actor({
44
options: {
5-
maxActions: 128,
65
maxQueueSize: 1000,
76
actionTimeout: 60_000,
87
stateSaveInterval: 1_000,
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { createClient } from "rivetkit/client";
2+
import type { registry } from "./sse-server";
3+
4+
const client = createClient<typeof registry>("http://localhost:6420");
5+
const notifications = client.notifications.getOrCreate(["status"]);
6+
const response = await notifications.fetch("/", {
7+
headers: { Accept: "text/event-stream" },
8+
});
9+
10+
if (!response.ok || !response.body) {
11+
throw new Error(`SSE request failed with status ${response.status}`);
12+
}
13+
14+
const reader = response.body.getReader();
15+
const decoder = new TextDecoder();
16+
let pending = "";
17+
18+
for (;;) {
19+
const chunk = await reader.read();
20+
if (chunk.done) break;
21+
22+
pending += decoder.decode(chunk.value, { stream: true });
23+
for (;;) {
24+
const boundary = pending.indexOf("\n\n");
25+
if (boundary === -1) break;
26+
const event = pending.slice(0, boundary);
27+
pending = pending.slice(boundary + 2);
28+
console.log(event);
29+
}
30+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { setup } from "rivetkit";
2+
import { notificationsActor } from "./sse";
3+
4+
export const registry = setup({
5+
use: { notifications: notificationsActor },
6+
});
7+
8+
registry.start();

0 commit comments

Comments
 (0)