prosody 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.cargo/config.toml +3 -0
- data/.release-please-manifest.json +1 -1
- data/AGENTS.md +395 -0
- data/ARCHITECTURE.md +14 -4
- data/CHANGELOG.md +28 -0
- data/CLAUDE.md +1 -0
- data/CONFIGURATION.md +167 -0
- data/Cargo.lock +1115 -645
- data/Cargo.toml +7 -6
- data/README.md +436 -146
- data/Rakefile +11 -1
- data/examples/keyed_state.rb +70 -0
- data/examples/keyed_state.rbs +18 -0
- data/examples/keyed_state_windowing.rb +55 -0
- data/examples/keyed_state_windowing.rbs +16 -0
- data/ext/prosody/Cargo.toml +1 -0
- data/ext/prosody/src/admin.rs +1 -5
- data/ext/prosody/src/bridge/mod.rs +17 -32
- data/ext/prosody/src/client/config.rs +501 -28
- data/ext/prosody/src/client/mod.rs +167 -74
- data/ext/prosody/src/client/request.rs +132 -0
- data/ext/prosody/src/client/support.rs +122 -0
- data/ext/prosody/src/handler/context.rs +150 -5
- data/ext/prosody/src/handler/message.rs +67 -0
- data/ext/prosody/src/handler/mod.rs +115 -85
- data/ext/prosody/src/handler/state/mod.rs +488 -0
- data/ext/prosody/src/handler/state/registration.rs +104 -0
- data/ext/prosody/src/handler/state/scan.rs +218 -0
- data/ext/prosody/src/lib.rs +15 -3
- data/ext/prosody/src/published.rs +273 -0
- data/ext/prosody/src/scheduler/mod.rs +2 -2
- data/ext/prosody/src/scheduler/processor.rs +2 -2
- data/ext/prosody/src/scheduler/result.rs +7 -4
- data/ext/prosody/src/util.rs +86 -5
- data/lib/prosody/configuration.rb +71 -11
- data/lib/prosody/handler.rb +65 -8
- data/lib/prosody/native_stubs.rb +550 -9
- data/lib/prosody/request.rb +45 -0
- data/lib/prosody/state.rb +816 -0
- data/lib/prosody/version.rb +1 -1
- data/lib/prosody.rb +6 -0
- data/release-please-config.json +4 -0
- data/sig/configuration.rbs +70 -11
- data/sig/handler.rbs +17 -5
- data/sig/processor.rbs +28 -12
- data/sig/prosody.rbs +53 -7
- data/sig/request.rbs +66 -0
- data/sig/sentry.rbs +6 -0
- data/sig/state.rbs +390 -0
- data/steep_expectations.yml +57 -0
- data/typecheck/payload_types.rb +54 -0
- data/typecheck/payload_types.rbs +22 -0
- data/typecheck_negative/payload_types.rb +20 -0
- data/typecheck_negative/payload_types.rbs +9 -0
- metadata +32 -9
data/CONFIGURATION.md
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Configuration
|
|
2
|
+
|
|
3
|
+
Configure via constructor options or environment variables. Options fall back to environment variables when unset.
|
|
4
|
+
|
|
5
|
+
The Ruby client reports values it cannot convert to Prosody types. Prosody validates configuration semantics when the client is built.
|
|
6
|
+
|
|
7
|
+
## Core
|
|
8
|
+
|
|
9
|
+
| Option / Environment Variable | Description | Default |
|
|
10
|
+
|-----------------------------------------|---------------------------------------------------|--------------|
|
|
11
|
+
| `bootstrap_servers` / `PROSODY_BOOTSTRAP_SERVERS` | Kafka servers to connect to | - |
|
|
12
|
+
| `group_id` / `PROSODY_GROUP_ID` | Consumer group name | - |
|
|
13
|
+
| `subscribed_topics` / `PROSODY_SUBSCRIBED_TOPICS` | Topics to read from | - |
|
|
14
|
+
| `allowed_events` / `PROSODY_ALLOWED_EVENTS` | Only process events matching these prefixes | (all) |
|
|
15
|
+
| `source_system` / `PROSODY_SOURCE_SYSTEM` | Tag for outgoing messages (prevents reprocessing)| `<group_id>` |
|
|
16
|
+
| `mock` / `PROSODY_MOCK` | Use in-memory Kafka for testing | false |
|
|
17
|
+
| `mode` / - | Processing mode: `pipeline`, `low_latency`, or `best_effort` | `pipeline` |
|
|
18
|
+
| - / `PROSODY_LOG` | Rust log filter, such as `info` or `prosody=debug` | `info` |
|
|
19
|
+
|
|
20
|
+
## Requests
|
|
21
|
+
|
|
22
|
+
Requests work with the defaults on one network. Without a network name, peers always use the direct listener address.
|
|
23
|
+
With a network name, peers with the same name use the direct address. Other peers use the advertised connect URI.
|
|
24
|
+
Use a different bind address for each client that shares a host.
|
|
25
|
+
|
|
26
|
+
| Option / Environment Variable | Description | Default |
|
|
27
|
+
|--------------------------------|-------------|---------|
|
|
28
|
+
| `peer_bind_address` / `PROSODY_PEER_BIND_ADDRESS` | Socket address for the peer gRPC listener | Default network interface address on port 9099 |
|
|
29
|
+
| `peer_advertised_connect` / `PROSODY_PEER_ADVERTISED_CONNECT` | gRPC connect URI that peers on another network use | (none) |
|
|
30
|
+
| `peer_network_name` / `PROSODY_PEER_NETWORK_NAME` | Nonempty network name for direct peer routes | (none) |
|
|
31
|
+
| `peer_cache_capacity` / `PROSODY_PEER_CACHE_CAPACITY` | Maximum channels and peer records in each peer cache | 256 |
|
|
32
|
+
| `peer_registration_ttl` / `PROSODY_PEER_REGISTRATION_TTL` | Directory lease duration; use 5 seconds through 20 years | 30s |
|
|
33
|
+
|
|
34
|
+
Set `subsystem` to make this client answer requests. Without it, the client consumes messages but does not answer requests.
|
|
35
|
+
|
|
36
|
+
## Consumer
|
|
37
|
+
|
|
38
|
+
| Option / Environment Variable | Description | Default |
|
|
39
|
+
|-----------------------------------------|------------------------------------------------------|------------------------|
|
|
40
|
+
| `max_concurrency` / `PROSODY_MAX_CONCURRENCY` | Max messages being processed simultaneously | 32 |
|
|
41
|
+
| `max_uncommitted` / `PROSODY_MAX_UNCOMMITTED` | Max queued messages before pausing consumption | 64 |
|
|
42
|
+
| `timeout` / `PROSODY_TIMEOUT` | Cancel handler if it runs longer than this | 80% of stall threshold |
|
|
43
|
+
| `commit_interval` / `PROSODY_COMMIT_INTERVAL` | How often to save progress to Kafka | 1s |
|
|
44
|
+
| `poll_interval` / `PROSODY_POLL_INTERVAL` | How often to fetch new messages from Kafka | 100ms |
|
|
45
|
+
| `shutdown_timeout` / `PROSODY_SHUTDOWN_TIMEOUT` | Shutdown budget; handlers run freely until cancellation fires near the end of the timeout | 30s |
|
|
46
|
+
| `stall_threshold` / `PROSODY_STALL_THRESHOLD` | Report unhealthy if no progress for this long | 5m |
|
|
47
|
+
| `probe_port` / `PROSODY_PROBE_PORT` | HTTP port for health checks; use `false`, `:disabled`, or the environment value `none` to disable | 8000 |
|
|
48
|
+
| - / `PROSODY_STATISTICS_INTERVAL` | How often librdkafka reports client statistics; must be between 1ms and 24h | 5s |
|
|
49
|
+
| `failure_topic` / `PROSODY_FAILURE_TOPIC` | Send unprocessable messages here (dead letter queue) | - |
|
|
50
|
+
| `idempotence_cache_size` / `PROSODY_IDEMPOTENCE_CACHE_SIZE` | Global shared cache capacity across all partitions for message deduplication. Consumer deduplication is mandatory and cannot be disabled, so this must be at least 1; setting it to 0 in the client configuration is rejected | 8192 |
|
|
51
|
+
| `idempotence_version` / `PROSODY_IDEMPOTENCE_VERSION` | Version string for cache-busting dedup hashes | 1 |
|
|
52
|
+
| `idempotence_ttl` / `PROSODY_IDEMPOTENCE_TTL` | TTL for dedup records in Cassandra | 7d (604800 seconds) |
|
|
53
|
+
| `slab_size` / `PROSODY_SLAB_SIZE` | Timer storage granularity (rarely needs changing) | 1h |
|
|
54
|
+
| `message_spans` / `PROSODY_MESSAGE_SPANS` | Span linking for message execution: `child` (child-of) or `follows_from` | `child` |
|
|
55
|
+
| `timer_spans` / `PROSODY_TIMER_SPANS` | Span linking for timer execution: `child` (child-of) or `follows_from` | `follows_from` |
|
|
56
|
+
|
|
57
|
+
## Producer
|
|
58
|
+
|
|
59
|
+
| Option / Environment Variable | Description | Default |
|
|
60
|
+
|-----------------------------------------|---------------------------------|---------|
|
|
61
|
+
| `send_timeout` / `PROSODY_SEND_TIMEOUT` | Give up sending after this long | 1s |
|
|
62
|
+
|
|
63
|
+
## Retry
|
|
64
|
+
|
|
65
|
+
Retry backoff applies in pipeline and low-latency modes. `max_retries` controls how many retries low-latency mode performs before routing the failure to `failure_topic`. Pipeline mode uses deferral and does not use this limit.
|
|
66
|
+
|
|
67
|
+
| Option / Environment Variable | Description | Default |
|
|
68
|
+
|-----------------------------------------|-----------------------------------|---------|
|
|
69
|
+
| `max_retries` / `PROSODY_MAX_RETRIES` | Low-latency retries before routing to the failure topic | 3 |
|
|
70
|
+
| `retry_base` / `PROSODY_RETRY_BASE` | Wait this long before first retry | 20ms |
|
|
71
|
+
| `max_retry_delay` / `PROSODY_RETRY_MAX_DELAY` | Never wait longer than this | 5m |
|
|
72
|
+
|
|
73
|
+
## Deferral (Pipeline Mode)
|
|
74
|
+
|
|
75
|
+
| Option / Environment Variable | Description | Default |
|
|
76
|
+
|-----------------------------------------|---------------------------------------------------|---------|
|
|
77
|
+
| `defer_enabled` / `PROSODY_DEFER_ENABLED` | Enable deferral for new messages | true |
|
|
78
|
+
| `defer_base` / `PROSODY_DEFER_BASE` | Wait this long before first deferred retry | 1s |
|
|
79
|
+
| `defer_max_delay` / `PROSODY_DEFER_MAX_DELAY` | Never wait longer than this | 24h |
|
|
80
|
+
| `defer_failure_threshold` / `PROSODY_DEFER_FAILURE_THRESHOLD` | Disable deferral when failure rate exceeds this | 0.9 |
|
|
81
|
+
| `defer_failure_window` / `PROSODY_DEFER_FAILURE_WINDOW` | Measure failure rate over this time window | 5m |
|
|
82
|
+
| `defer_store_cache_size` / `PROSODY_DEFER_STORE_CACHE_SIZE` | Maximum deferred store cache entries per Cassandra defer store | 8192 |
|
|
83
|
+
|
|
84
|
+
## Kafka Message Loader (All Modes)
|
|
85
|
+
|
|
86
|
+
The shared loader resolves Kafka messages for deferral and keyed state:
|
|
87
|
+
|
|
88
|
+
| Option / Environment Variable | Description | Default |
|
|
89
|
+
|--------------------------------|-------------|---------|
|
|
90
|
+
| `loader_cache_size` / `PROSODY_LOADER_CACHE_SIZE` | Maximum messages retained by the shared Kafka loader | 1024 |
|
|
91
|
+
| `loader_seek_timeout` / `PROSODY_LOADER_SEEK_TIMEOUT` | Timeout for Kafka loader seek operations | 30s |
|
|
92
|
+
| `loader_discard_threshold` / `PROSODY_LOADER_DISCARD_THRESHOLD` | Sequential-read distance before the loader seeks | 100 |
|
|
93
|
+
|
|
94
|
+
## Monopolization Detection (Pipeline Mode)
|
|
95
|
+
|
|
96
|
+
| Option / Environment Variable | Description | Default |
|
|
97
|
+
|-----------------------------------------|-----------------------------------------|---------|
|
|
98
|
+
| `monopolization_enabled` / `PROSODY_MONOPOLIZATION_ENABLED` | Enable hot key protection | true |
|
|
99
|
+
| `monopolization_threshold` / `PROSODY_MONOPOLIZATION_THRESHOLD` | Max handler time as fraction of window | 0.9 |
|
|
100
|
+
| `monopolization_window` / `PROSODY_MONOPOLIZATION_WINDOW` | Measurement window | 5m |
|
|
101
|
+
| `monopolization_cache_size` / `PROSODY_MONOPOLIZATION_CACHE_SIZE` | Max distinct keys to track | 8192 |
|
|
102
|
+
|
|
103
|
+
## Fair Scheduling (All Modes)
|
|
104
|
+
|
|
105
|
+
| Option / Environment Variable | Description | Default |
|
|
106
|
+
|-----------------------------------------|------------------------------------------------------------------|---------|
|
|
107
|
+
| `scheduler_failure_weight` / `PROSODY_SCHEDULER_FAILURE_WEIGHT` | Fraction of processing time reserved for retries | 0.3 |
|
|
108
|
+
| `scheduler_max_wait` / `PROSODY_SCHEDULER_MAX_WAIT` | Messages waiting this long get maximum priority | 2m |
|
|
109
|
+
| `scheduler_wait_weight` / `PROSODY_SCHEDULER_WAIT_WEIGHT` | Priority boost for waiting messages (higher = more aggressive) | 200.0 |
|
|
110
|
+
| `scheduler_cache_size` / `PROSODY_SCHEDULER_CACHE_SIZE` | Max distinct keys to track | 8192 |
|
|
111
|
+
|
|
112
|
+
## Telemetry
|
|
113
|
+
|
|
114
|
+
Prosody emits message, timer, and producer lifecycle events to a Kafka topic for observability:
|
|
115
|
+
|
|
116
|
+
| Option / Environment Variable | Description | Default |
|
|
117
|
+
|-----------------------------------------|------------------------------------------------|----------------------------|
|
|
118
|
+
| `telemetry_topic` / `PROSODY_TELEMETRY_TOPIC` | Kafka topic to produce telemetry events to | `prosody.telemetry-events` |
|
|
119
|
+
| `telemetry_enabled` / `PROSODY_TELEMETRY_ENABLED` | Enable or disable the telemetry emitter | true |
|
|
120
|
+
|
|
121
|
+
Mock mode disables telemetry automatically, regardless of `telemetry_enabled`.
|
|
122
|
+
|
|
123
|
+
## Cassandra
|
|
124
|
+
|
|
125
|
+
Persistent storage for timers, deferral, deduplication, and keyed state. It is not needed when `mock: true`.
|
|
126
|
+
|
|
127
|
+
| Option / Environment Variable | Description | Default |
|
|
128
|
+
|-----------------------------------------|------------------------------------|---------|
|
|
129
|
+
| `cassandra_nodes` / `PROSODY_CASSANDRA_NODES` | Servers to connect to (host:port) | - |
|
|
130
|
+
| `cassandra_keyspace` / `PROSODY_CASSANDRA_KEYSPACE` | Keyspace name | prosody |
|
|
131
|
+
| `cassandra_user` / `PROSODY_CASSANDRA_USER` | Username | - |
|
|
132
|
+
| `cassandra_password` / `PROSODY_CASSANDRA_PASSWORD` | Password | - |
|
|
133
|
+
| `cassandra_datacenter` / `PROSODY_CASSANDRA_DATACENTER` | Prefer this datacenter for queries | - |
|
|
134
|
+
| `cassandra_rack` / `PROSODY_CASSANDRA_RACK` | Prefer this rack for queries | - |
|
|
135
|
+
| `cassandra_retention` / `PROSODY_CASSANDRA_RETENTION` | Delete data older than this | 1y |
|
|
136
|
+
|
|
137
|
+
## Keyed State
|
|
138
|
+
|
|
139
|
+
Register keyed-state collections before you subscribe. Persistence is backed by Cassandra and is not needed when `mock: true`. See [Keyed State](README.md#keyed-state) for handler usage. Where an option and an environment variable are paired, an explicitly set option wins. Otherwise, the environment variable applies, then the default.
|
|
140
|
+
|
|
141
|
+
| Option / Environment Variable | Description | Default |
|
|
142
|
+
|-------------------------------|-------------|---------|
|
|
143
|
+
| `state_collections` / - | Keyed-state collections to register before subscribe (array of definitions or config hashes; duplicate names rejected) | (none) |
|
|
144
|
+
| `subsystem` / `PROSODY_SUBSYSTEM` | Subsystem name used to advertise JSON collections whose definitions set `published: true` | (none) |
|
|
145
|
+
| `state_cache_dir` / `PROSODY_STATE_CACHE_DIR` | Disk workspace for the local keyed-state cache; each live client needs its own directory. Set a mounted path in production | per-client temp dir |
|
|
146
|
+
| `state_owned_cache_size` / `PROSODY_STATE_OWNED_CACHE_SIZE` | Capacity of the owning keyed-state cache; accepts sizes such as `64 MiB` or `500 MB` | storage-engine default |
|
|
147
|
+
| `state_read_cache_size` / `PROSODY_STATE_READ_CACHE_SIZE` | Capacity of the published-state read cache; accepts sizes such as `1 MiB` | `state_owned_cache_size` or `PROSODY_STATE_OWNED_CACHE_SIZE` when set; otherwise 1 MiB |
|
|
148
|
+
| `state_read_cache` / `PROSODY_STATE_READ_CACHE_TTL` | Default published-read cache TTL. Use `false` or the environment value `none` to bypass the cache | 5s |
|
|
149
|
+
| `state_recovery_delay` / `PROSODY_STATE_RECOVERY_DELAY` | Whole-second delay between staging a provisional cell and the recovery sweep; every collection TTL must strictly exceed it | 30s |
|
|
150
|
+
|
|
151
|
+
Prefer the definition constructors from the [API reference](README.md#api-reference). They serialize into `state_collections`, so you can reuse the same object with `context.state`. Each entry has these fields:
|
|
152
|
+
|
|
153
|
+
Published collections require `subsystem`. Keep it configured for one deployment after removing `published: true` so readers can observe the collection's retirement.
|
|
154
|
+
|
|
155
|
+
| Field | Description | Default |
|
|
156
|
+
|-------|-------------|---------|
|
|
157
|
+
| `name` | Collection name; non-empty and unique within the client | (required) |
|
|
158
|
+
| `kind` | `"value"`, `"map"`, or `"deque"` | (required) |
|
|
159
|
+
| `payload` | `"json"` (JSON values) or `"message"` (the full Kafka message the handler received) | (required) |
|
|
160
|
+
| `ttl_seconds` | Per-write TTL in whole seconds (at least 1; must exceed the recovery delay) | (none) |
|
|
161
|
+
| `read_uncommitted` | Opt out of transactional staging | false |
|
|
162
|
+
| `published` | Allow read-only access from other consumer groups; JSON collections only | false |
|
|
163
|
+
| `read_cache` | Published-read cache override: a positive duration, `false`, or inherit when omitted | inherit |
|
|
164
|
+
| `keyset_limit` | Map-only; ordered-scan bound in `0..=4096` (`0` disables ordered-scan tracking) | 128 |
|
|
165
|
+
| `capacity` | Deque-only window bound (at least 1); keeps at most N slots, enforced lazily on push. Runtime-only and mutable across deploys — not persisted | unbounded |
|
|
166
|
+
|
|
167
|
+
Constructors set these via keyword arguments (`ttl:`, `keyset_limit:`, `capacity:`, `read_uncommitted:`, `published:`, `read_cache:`). `read_cache` is a positive duration in seconds, `false` to bypass the cache, or `nil` to inherit the client default.
|