You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+11-3Lines changed: 11 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -29,14 +29,14 @@ style C fill:#e1f5fe
29
29
30
30
### Stream Management
31
31
32
-
Streams are automatically tracked and cleaned up after inactivity (configurable via `CLEANUP_STREAM_IDLE_SEC`, default 300s).
32
+
Streams are automatically tracked and cleaned up after inactivity (configurable via `CLEANUP_STREAM_IDLE_SEC`, default 120s).
33
33
This prevents memory leaks from:
34
34
35
35
- Crashed or disconnected publishers
36
36
- Streams that never reach Phase::End
37
37
- Network failures during publishing
38
38
39
-
A cleanup worker runs periodically (configurable via `CLEANUP_WORKER_INTERVAL_SEC`, default 300s), deleting streams that haven't received any publishes within the inactivity threshold. Active streams (receiving regular publishes) are kept alive indefinitely, supporting long-running or continuous streaming use cases.
39
+
A cleanup worker runs periodically (configurable via `CLEANUP_WORKER_INTERVAL_SEC`, default 120s), deleting streams that haven't received any publishes within the inactivity threshold. Active streams (receiving regular publishes) are kept alive indefinitely, supporting long-running or continuous streaming use cases.
40
40
41
41
**Note:** While streams themselves are unbounded in duration, client connections (on the Gateway service) may have separate timeout limits. This allows clients to reconnect to ongoing streams as needed.
42
42
@@ -76,12 +76,20 @@ The `payload` field contains your application data and is typically used with DE
76
76
77
77
**Size Limits:**
78
78
79
-
- Maximum message size: 32KB (entire PublishRequest protobuf)
79
+
- Maximum message size: 16KB (entire PublishRequest protobuf)
80
80
- Messages exceeding this limit receive a 413 Payload Too Large response
81
81
- For larger data, split into multiple DELTA messages
82
82
83
83
The payload must be a valid JSON-like structure in the form of a `google/protobuf/struct.proto`.
84
84
85
+
**Rate Limits:**
86
+
87
+
- Maximum 20 requests per second per channel
88
+
- Exceeding returns `429 Too Many Requests` with `Retry-After` header
89
+
- High-frequency publishers should batch messages
90
+
91
+
**Retention:** Streams hold up to approximately 1200 messages. At maximum publish rate, this provides ~60 seconds of history to consumers to catch up after brief disconnections.
Copy file name to clipboardExpand all lines: services/publish/README.md
+22-4Lines changed: 22 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,7 +8,7 @@ Each publish updates a stream's activity timestamp in Redis. This allows automat
8
8
9
9
### Cleanup Worker
10
10
11
-
A background worker runs periodically (configurable via `CLEANUP_WORKER_INTERVAL_SEC`, default 300s) and deletes streams with no activity for a configurable duration (via `CLEANUP_STREAM_IDLE_SEC`, default 300s).
11
+
A background worker runs periodically (configurable via `CLEANUP_WORKER_INTERVAL_SEC`, default 120s) and deletes streams with no activity for a configurable duration (via `CLEANUP_STREAM_IDLE_SEC`, default 120s).
12
12
13
13
### Phase::End Behavior
14
14
@@ -22,18 +22,34 @@ This prevents memory leaks from crashed clients or incomplete streams while allo
22
22
23
23
## API Limits
24
24
25
+
### Rate Limiting
26
+
27
+
Publishers are limited to 20 requests per second using a fixed-window counter in Redis.
28
+
29
+
- Key: `rate_limit:channel:{org_id}:{channel_id}`
30
+
- Window: 1 second
31
+
- Enforced via a Lua script for atomicity
32
+
33
+
Rate limiting runs before tracking/publishing to avoid wasted work. The `Retry-After` header tells clients when to retry.
34
+
35
+
Rate limiting fails closed intentionally since if Redis is having issues with rate limits, it likely isn't going to be able to handle the streams.
36
+
37
+
**Relationship to stream size:**
38
+
39
+
At 20/sec with 1200 message streams, consumers have ~60 seconds to recover from disconnections.
40
+
25
41
### Message Size
26
42
27
-
Publish requests are limited to 32KB (configurable via `MAX_MESSAGE_SIZE_BYTES`).
43
+
Publish requests are limited to 16KB.
28
44
Requests exceeding this limit are rejected with `413 Payload Too Large`.
29
45
30
-
Combined with the stream length limit of 500 messages, this bounds maximum stream size to approximately 16MB per stream.
46
+
Combined with the stream length limit of 1200 messages, this bounds maximum stream size to approximately 19.2MB per stream.
31
47
32
48
Publishers handling large data should chunk it into multiple DELTA messages within the START/DELTA/END streaming pattern.
33
49
34
50
### Stream Length
35
51
36
-
Streams are automatically trimmed to approximately 500 messages (configurable via `MAX_STREAM_LEN`). Older messages are removed as new ones arrive.
52
+
Streams are automatically trimmed to approximately 1200 messages. Older messages are removed as new ones arrive.
37
53
38
54
## Design Decisions
39
55
@@ -63,3 +79,5 @@ Both `CLEANUP_WORKER_INTERVAL_SEC` and `CLEANUP_STREAM_IDLE_SEC` can be tuned in
63
79
### Known Edge Cases
64
80
65
81
-**Sorted sets bloat**: If untrack operations consistently fail, the sorted sets accumulate entries for already deleted streams. The worker will attempt to delete non-existent streams (harmless) but the sorted sets grow. If this becomes a problem, we can add a periodic SCAN to remove ghost entries.
82
+
83
+
-**Rate Limit Leak**: If EXPIRE fails after INCR succeeds, the rate limit key persists without a TTL. This is unlikely but not impossible.
0 commit comments