mammoth 0.5.1 → 0.7.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/CHANGELOG.md +29 -1
- data/README.md +33 -1
- data/config/mammoth.example.yml +38 -0
- data/config/mammoth.schema.json +115 -1
- data/lib/mammoth/application.rb +43 -22
- data/lib/mammoth/capabilities.rb +59 -0
- data/lib/mammoth/cli.rb +5 -4
- data/lib/mammoth/commands/status_command.rb +28 -0
- data/lib/mammoth/dead_letter_commands.rb +92 -13
- data/lib/mammoth/dead_letter_store.rb +48 -17
- data/lib/mammoth/delivered_envelope_store.rb +15 -2
- data/lib/mammoth/delivery_worker.rb +35 -6
- data/lib/mammoth/destinations/adapter.rb +20 -0
- data/lib/mammoth/destinations/registry.rb +46 -0
- data/lib/mammoth/destinations/webhook_adapter.rb +29 -0
- data/lib/mammoth/node_identity.rb +54 -0
- data/lib/mammoth/observability_server.rb +2 -0
- data/lib/mammoth/observability_snapshot.rb +41 -7
- data/lib/mammoth/operational_state/adapter.rb +37 -0
- data/lib/mammoth/operational_state/registry.rb +46 -0
- data/lib/mammoth/operational_state/sqlite_adapter.rb +44 -0
- data/lib/mammoth/registry.rb +46 -0
- data/lib/mammoth/route_filter.rb +49 -0
- data/lib/mammoth/runtimes/adapter.rb +23 -0
- data/lib/mammoth/runtimes/concurrent_adapter.rb +31 -0
- data/lib/mammoth/runtimes/inline_adapter.rb +40 -0
- data/lib/mammoth/runtimes/registry.rb +46 -0
- data/lib/mammoth/status.rb +55 -13
- data/lib/mammoth/version.rb +1 -1
- data/lib/mammoth.rb +19 -0
- metadata +16 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5fe6f64a39d214c62e11a29fccb091f58cd2a1b8038a0bb803c39c4e018b09b3
|
|
4
|
+
data.tar.gz: f557c7288df617029808c327b656a8b7cb1f7689eb7f4b6d99032b01bcc0535e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fe49156b57ff2355fd0e78368cd613fa3fa5dcf5d0a5ebf423ec799558b61a70da7529a123f5b254b904a93e7c7355a049b115308eb051e211894b84443f3444
|
|
7
|
+
data.tar.gz: 7b24591aa6f3996e51b5762022f680f212cbb1e8412e0e90ff42e34c3485d9f18fb2f4f4c9b9ca4420a697767400a2d37b6ebc600d203e7c4f5f0fbe5e904da2
|
data/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,34 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## Unreleased
|
|
3
|
+
## 0.7.0 Unreleased
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Added explicit adapter registries for operational state, destinations, and delivery runtimes.
|
|
8
|
+
- Added the built-in SQLite operational state adapter.
|
|
9
|
+
- Added the built-in webhook destination adapter registration.
|
|
10
|
+
- Added inline and concurrent runtime adapter registration.
|
|
11
|
+
- Added optional node identity configuration for future control-plane integration.
|
|
12
|
+
- Added local capability reporting for state, destination, runtime, and relay features.
|
|
13
|
+
- Added a reusable status command object behind the CLI status command.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- Bumped Mammoth version to `0.7.0`.
|
|
18
|
+
|
|
19
|
+
## 0.6.0
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- Added fanout route filters by schema, table, and operation for webhook destinations.
|
|
24
|
+
- Added destination `enabled` controls for config-driven delivery cutovers.
|
|
25
|
+
- Added per-destination retry policy overrides for `max_attempts` and `schedule_seconds`.
|
|
26
|
+
- Added dead-letter replay filters by destination, status, and failed-at time window.
|
|
27
|
+
- Added destination-labeled Prometheus metrics for dead-letter and delivered-envelope counts.
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- Bumped Mammoth version to `0.6.0`.
|
|
4
32
|
|
|
5
33
|
## 0.5.1
|
|
6
34
|
|
data/README.md
CHANGED
|
@@ -47,14 +47,18 @@ https://kanutocd.github.io/mammoth/Mammoth.html
|
|
|
47
47
|
- dead letter persistence
|
|
48
48
|
- webhook delivery sink
|
|
49
49
|
- webhook fanout to multiple destinations
|
|
50
|
+
- fanout route filters by schema, table, and operation
|
|
51
|
+
- per-destination enable/disable and retry policy controls
|
|
50
52
|
- delivery worker with retry, checkpoint, and DLQ handling
|
|
51
|
-
- dead-letter inspection and replay commands
|
|
53
|
+
- dead-letter inspection and filtered replay commands
|
|
52
54
|
- CDC-core event serialization boundary
|
|
53
55
|
- CDC Ecosystem source-adapter integration boundary
|
|
54
56
|
- Docker image support
|
|
55
57
|
- public Helm chart support
|
|
56
58
|
- unit and e2e test tasks
|
|
57
59
|
- health and metrics endpoints
|
|
60
|
+
- explicit extension registries for state, destination, and runtime adapters
|
|
61
|
+
- node identity and local capability reporting
|
|
58
62
|
|
|
59
63
|
## Boundary
|
|
60
64
|
|
|
@@ -64,6 +68,16 @@ Mammoth does not own pgoutput protocol parsing, value decoding, source
|
|
|
64
68
|
normalization, ordering policy, or runtime execution. Those belong to the
|
|
65
69
|
upstream CDC Ecosystem components.
|
|
66
70
|
|
|
71
|
+
## Extensions
|
|
72
|
+
|
|
73
|
+
Mammoth OSS exposes small adapter registries for future extensions:
|
|
74
|
+
|
|
75
|
+
- operational state adapters
|
|
76
|
+
- destination adapters
|
|
77
|
+
- runtime adapters
|
|
78
|
+
|
|
79
|
+
See [`docs/EXTENSIONS.md`](docs/EXTENSIONS.md).
|
|
80
|
+
|
|
67
81
|
## Configuration
|
|
68
82
|
|
|
69
83
|
Mammoth configuration is YAML-backed and IDE-friendly.
|
|
@@ -78,6 +92,24 @@ Validate configuration:
|
|
|
78
92
|
bundle exec ./exe/mammoth validate config/mammoth.example.yml
|
|
79
93
|
```
|
|
80
94
|
|
|
95
|
+
Fanout destinations can be routed and tuned independently:
|
|
96
|
+
|
|
97
|
+
```yaml
|
|
98
|
+
destinations:
|
|
99
|
+
- name: audit_webhook
|
|
100
|
+
type: webhook
|
|
101
|
+
enabled: true
|
|
102
|
+
url: https://audit.example.com/cdc
|
|
103
|
+
timeout_seconds: 5
|
|
104
|
+
route:
|
|
105
|
+
schemas: [public]
|
|
106
|
+
tables: [orders]
|
|
107
|
+
operations: [insert, update]
|
|
108
|
+
retry:
|
|
109
|
+
max_attempts: 3
|
|
110
|
+
schedule_seconds: [1, 10]
|
|
111
|
+
```
|
|
112
|
+
|
|
81
113
|
## CLI
|
|
82
114
|
|
|
83
115
|
```bash
|
data/config/mammoth.example.yml
CHANGED
|
@@ -34,6 +34,19 @@ mammoth:
|
|
|
34
34
|
# production_mammoth
|
|
35
35
|
name: local_mammoth
|
|
36
36
|
|
|
37
|
+
node:
|
|
38
|
+
# Optional local node identity for status output and future control-plane
|
|
39
|
+
# agents. Omit this section to default node_id to the host name and node_name
|
|
40
|
+
# to mammoth.name.
|
|
41
|
+
node_id: local-mammoth-1
|
|
42
|
+
node_name: local-mammoth-dev
|
|
43
|
+
fleet_id: local-dev
|
|
44
|
+
environment: development
|
|
45
|
+
labels:
|
|
46
|
+
region: local
|
|
47
|
+
metadata:
|
|
48
|
+
owner: platform
|
|
49
|
+
|
|
37
50
|
postgres:
|
|
38
51
|
# PostgreSQL host reachable from the Mammoth process or pod.
|
|
39
52
|
#
|
|
@@ -275,6 +288,7 @@ webhook:
|
|
|
275
288
|
# destinations:
|
|
276
289
|
# - name: primary_webhook
|
|
277
290
|
# type: webhook
|
|
291
|
+
# enabled: true
|
|
278
292
|
# url: https://example.com/webhooks/postgres
|
|
279
293
|
# timeout_seconds: 5
|
|
280
294
|
# header_env:
|
|
@@ -284,8 +298,28 @@ webhook:
|
|
|
284
298
|
# secret_env: MAMMOTH_PRIMARY_WEBHOOK_SIGNING_SECRET
|
|
285
299
|
# - name: audit_webhook
|
|
286
300
|
# type: webhook
|
|
301
|
+
# enabled: true
|
|
287
302
|
# url: https://audit.example.com/cdc
|
|
288
303
|
# timeout_seconds: 5
|
|
304
|
+
#
|
|
305
|
+
# # Optional route filter. Omit route to receive every event/envelope.
|
|
306
|
+
# # For transaction delivery, a destination matches when any event in the
|
|
307
|
+
# # transaction matches; Mammoth still delivers the full transaction envelope.
|
|
308
|
+
# route:
|
|
309
|
+
# schemas:
|
|
310
|
+
# - public
|
|
311
|
+
# tables:
|
|
312
|
+
# - orders
|
|
313
|
+
# operations:
|
|
314
|
+
# - insert
|
|
315
|
+
# - update
|
|
316
|
+
#
|
|
317
|
+
# # Optional per-destination retry override. Omit to use top-level retry.
|
|
318
|
+
# retry:
|
|
319
|
+
# max_attempts: 3
|
|
320
|
+
# schedule_seconds:
|
|
321
|
+
# - 1
|
|
322
|
+
# - 10
|
|
289
323
|
|
|
290
324
|
retry:
|
|
291
325
|
# Maximum delivery attempts before the event/envelope is moved to the dead
|
|
@@ -310,6 +344,10 @@ sqlite:
|
|
|
310
344
|
# records here. In Kubernetes, back this path with a PersistentVolumeClaim.
|
|
311
345
|
path: data/mammoth.db
|
|
312
346
|
|
|
347
|
+
operational_state:
|
|
348
|
+
# Mammoth OSS 0.7.0 ships the sqlite operational state adapter.
|
|
349
|
+
adapter: sqlite
|
|
350
|
+
|
|
313
351
|
observability:
|
|
314
352
|
# Bind host for the optional health, readiness, and metrics server.
|
|
315
353
|
host: 0.0.0.0
|
data/config/mammoth.schema.json
CHANGED
|
@@ -40,6 +40,47 @@
|
|
|
40
40
|
},
|
|
41
41
|
"description": "Mammoth instance identity and operator-facing metadata."
|
|
42
42
|
},
|
|
43
|
+
"node": {
|
|
44
|
+
"type": "object",
|
|
45
|
+
"additionalProperties": false,
|
|
46
|
+
"properties": {
|
|
47
|
+
"node_id": {
|
|
48
|
+
"type": "string",
|
|
49
|
+
"minLength": 1,
|
|
50
|
+
"description": "Stable node identifier used by status output and future control-plane agents."
|
|
51
|
+
},
|
|
52
|
+
"node_name": {
|
|
53
|
+
"type": "string",
|
|
54
|
+
"minLength": 1,
|
|
55
|
+
"description": "Human-readable node name."
|
|
56
|
+
},
|
|
57
|
+
"fleet_id": {
|
|
58
|
+
"type": "string",
|
|
59
|
+
"minLength": 1,
|
|
60
|
+
"description": "Optional fleet identifier for grouping Mammoth nodes."
|
|
61
|
+
},
|
|
62
|
+
"environment": {
|
|
63
|
+
"type": "string",
|
|
64
|
+
"minLength": 1,
|
|
65
|
+
"description": "Optional deployment environment such as development, staging, or production."
|
|
66
|
+
},
|
|
67
|
+
"labels": {
|
|
68
|
+
"type": "object",
|
|
69
|
+
"additionalProperties": {
|
|
70
|
+
"type": "string"
|
|
71
|
+
},
|
|
72
|
+
"description": "Operator-defined node labels."
|
|
73
|
+
},
|
|
74
|
+
"metadata": {
|
|
75
|
+
"type": "object",
|
|
76
|
+
"additionalProperties": {
|
|
77
|
+
"type": "string"
|
|
78
|
+
},
|
|
79
|
+
"description": "Operator-defined node metadata."
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
"description": "Optional local node identity. Mammoth OSS uses this for status and future extension surfaces only."
|
|
83
|
+
},
|
|
43
84
|
"postgres": {
|
|
44
85
|
"type": "object",
|
|
45
86
|
"additionalProperties": false,
|
|
@@ -223,7 +264,11 @@
|
|
|
223
264
|
"enum": [
|
|
224
265
|
"webhook"
|
|
225
266
|
],
|
|
226
|
-
"description": "Destination adapter type. Mammoth OSS 0.
|
|
267
|
+
"description": "Destination adapter type. Mammoth OSS 0.7.0 supports webhook destinations."
|
|
268
|
+
},
|
|
269
|
+
"enabled": {
|
|
270
|
+
"type": "boolean",
|
|
271
|
+
"description": "When false, Mammoth skips this destination, advances local progress for the work item, and does not attempt delivery."
|
|
227
272
|
},
|
|
228
273
|
"url": {
|
|
229
274
|
"type": "string",
|
|
@@ -281,6 +326,61 @@
|
|
|
281
326
|
}
|
|
282
327
|
},
|
|
283
328
|
"description": "Optional HMAC-SHA256 request signing for this webhook destination."
|
|
329
|
+
},
|
|
330
|
+
"route": {
|
|
331
|
+
"type": "object",
|
|
332
|
+
"additionalProperties": false,
|
|
333
|
+
"properties": {
|
|
334
|
+
"schemas": {
|
|
335
|
+
"type": "array",
|
|
336
|
+
"minItems": 1,
|
|
337
|
+
"items": {
|
|
338
|
+
"type": "string",
|
|
339
|
+
"minLength": 1
|
|
340
|
+
},
|
|
341
|
+
"description": "PostgreSQL schemas this destination should receive. Omit to match every schema."
|
|
342
|
+
},
|
|
343
|
+
"tables": {
|
|
344
|
+
"type": "array",
|
|
345
|
+
"minItems": 1,
|
|
346
|
+
"items": {
|
|
347
|
+
"type": "string",
|
|
348
|
+
"minLength": 1
|
|
349
|
+
},
|
|
350
|
+
"description": "PostgreSQL tables this destination should receive. Omit to match every table."
|
|
351
|
+
},
|
|
352
|
+
"operations": {
|
|
353
|
+
"type": "array",
|
|
354
|
+
"minItems": 1,
|
|
355
|
+
"items": {
|
|
356
|
+
"type": "string",
|
|
357
|
+
"minLength": 1
|
|
358
|
+
},
|
|
359
|
+
"description": "CDC operations this destination should receive, such as insert, update, or delete. Omit to match every operation."
|
|
360
|
+
}
|
|
361
|
+
},
|
|
362
|
+
"description": "Optional destination route filter. Event delivery matches one event; transaction delivery matches when any event in the transaction matches and delivers the full envelope."
|
|
363
|
+
},
|
|
364
|
+
"retry": {
|
|
365
|
+
"type": "object",
|
|
366
|
+
"additionalProperties": false,
|
|
367
|
+
"properties": {
|
|
368
|
+
"max_attempts": {
|
|
369
|
+
"type": "integer",
|
|
370
|
+
"minimum": 1,
|
|
371
|
+
"description": "Destination-specific maximum delivery attempts before dead-lettering. Defaults to the top-level retry.max_attempts."
|
|
372
|
+
},
|
|
373
|
+
"schedule_seconds": {
|
|
374
|
+
"type": "array",
|
|
375
|
+
"minItems": 1,
|
|
376
|
+
"items": {
|
|
377
|
+
"type": "integer",
|
|
378
|
+
"minimum": 1
|
|
379
|
+
},
|
|
380
|
+
"description": "Destination-specific retry backoff schedule in seconds. Defaults to the top-level retry.schedule_seconds."
|
|
381
|
+
}
|
|
382
|
+
},
|
|
383
|
+
"description": "Optional retry policy override for this destination."
|
|
284
384
|
}
|
|
285
385
|
}
|
|
286
386
|
},
|
|
@@ -326,6 +426,20 @@
|
|
|
326
426
|
},
|
|
327
427
|
"description": "SQLite operational store settings for checkpoints, attempts, and dead-letter records."
|
|
328
428
|
},
|
|
429
|
+
"operational_state": {
|
|
430
|
+
"type": "object",
|
|
431
|
+
"additionalProperties": false,
|
|
432
|
+
"properties": {
|
|
433
|
+
"adapter": {
|
|
434
|
+
"type": "string",
|
|
435
|
+
"enum": [
|
|
436
|
+
"sqlite"
|
|
437
|
+
],
|
|
438
|
+
"description": "Operational state adapter. Mammoth OSS 0.7.0 ships the sqlite adapter."
|
|
439
|
+
}
|
|
440
|
+
},
|
|
441
|
+
"description": "Operational state adapter selection. SQLite remains the default OSS adapter."
|
|
442
|
+
},
|
|
329
443
|
"logging": {
|
|
330
444
|
"type": "object",
|
|
331
445
|
"additionalProperties": false,
|
data/lib/mammoth/application.rb
CHANGED
|
@@ -10,7 +10,7 @@ module Mammoth
|
|
|
10
10
|
# injected CDC work source rather than owning upstream CDC source-adapter
|
|
11
11
|
# lifecycle decisions.
|
|
12
12
|
class Application
|
|
13
|
-
attr_reader :config, :
|
|
13
|
+
attr_reader :config, :state_adapter, :consumer, :delivery_worker, :checkpoint_store
|
|
14
14
|
|
|
15
15
|
# @param config [Mammoth::Configuration] loaded configuration
|
|
16
16
|
# @param source [#each, nil] injectable event source for tests and demos
|
|
@@ -18,12 +18,17 @@ module Mammoth
|
|
|
18
18
|
# @param sleeper [#call] retry sleep strategy
|
|
19
19
|
def initialize(config, source: nil, sink: nil, sleeper: Kernel.method(:sleep))
|
|
20
20
|
@config = config
|
|
21
|
-
@
|
|
22
|
-
@checkpoint_store =
|
|
21
|
+
@state_adapter = build_state_adapter
|
|
22
|
+
@checkpoint_store = state_adapter.checkpoint_store
|
|
23
23
|
@consumer = ReplicationConsumer.new(source: source || build_source, delivery_unit: delivery_unit)
|
|
24
24
|
@delivery_worker = sink ? build_delivery_worker(sink: sink, sleeper: sleeper) : build_configured_delivery_worker(sleeper:)
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
+
# @return [Mammoth::SQLiteStore] underlying SQLite store for compatibility
|
|
28
|
+
def sqlite_store
|
|
29
|
+
state_adapter.respond_to?(:sqlite_store) ? state_adapter.sqlite_store : nil
|
|
30
|
+
end
|
|
31
|
+
|
|
27
32
|
# Start the application runtime and deliver consumed CDC work.
|
|
28
33
|
#
|
|
29
34
|
# @return [Integer] number of processed work units
|
|
@@ -54,13 +59,7 @@ module Mammoth
|
|
|
54
59
|
private
|
|
55
60
|
|
|
56
61
|
def process_work(runtime, work)
|
|
57
|
-
|
|
58
|
-
runtime.process_many([work])
|
|
59
|
-
elsif transaction_delivery?
|
|
60
|
-
delivery_worker.deliver_transaction(work)
|
|
61
|
-
else
|
|
62
|
-
delivery_worker.deliver(work)
|
|
63
|
-
end
|
|
62
|
+
runtime.process_many([work])
|
|
64
63
|
end
|
|
65
64
|
|
|
66
65
|
def process_batch(runtime, batch)
|
|
@@ -73,9 +72,8 @@ module Mammoth
|
|
|
73
72
|
end
|
|
74
73
|
|
|
75
74
|
def build_runtime
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
ConcurrentDeliveryRuntime.new(
|
|
75
|
+
Runtimes::Registry.build(
|
|
76
|
+
runtime_adapter,
|
|
79
77
|
processor: DeliveryProcessor.new(delivery_worker:, delivery_unit: delivery_unit),
|
|
80
78
|
concurrency: runtime_concurrency,
|
|
81
79
|
timeout: runtime_timeout,
|
|
@@ -87,34 +85,57 @@ module Mammoth
|
|
|
87
85
|
Sources::Postgres.new(config, checkpoint_store: checkpoint_store)
|
|
88
86
|
end
|
|
89
87
|
|
|
90
|
-
def build_delivery_worker(sink:, sleeper:)
|
|
88
|
+
def build_delivery_worker(sink:, sleeper:, delivery_policy: {})
|
|
91
89
|
DeliveryWorker.from_config(
|
|
92
90
|
config,
|
|
93
91
|
sink: sink,
|
|
94
92
|
checkpoint_store: checkpoint_store,
|
|
95
|
-
dead_letter_store:
|
|
96
|
-
sleeper: sleeper
|
|
93
|
+
dead_letter_store: state_adapter.dead_letter_store,
|
|
94
|
+
sleeper: sleeper,
|
|
95
|
+
delivery_policy: delivery_policy
|
|
97
96
|
)
|
|
98
97
|
end
|
|
99
98
|
|
|
100
99
|
def build_configured_delivery_worker(sleeper:)
|
|
101
|
-
workers =
|
|
100
|
+
workers = destination_specs.map do |spec|
|
|
101
|
+
build_delivery_worker(sink: spec.fetch(:sink), sleeper:, delivery_policy: spec.fetch(:delivery_policy))
|
|
102
|
+
end
|
|
102
103
|
return workers.fetch(0) if workers.one?
|
|
103
104
|
|
|
104
105
|
FanoutDeliveryWorker.new(workers)
|
|
105
106
|
end
|
|
106
107
|
|
|
107
|
-
def
|
|
108
|
+
def destination_specs
|
|
108
109
|
destinations = config.data["destinations"]
|
|
109
|
-
|
|
110
|
+
unless destinations
|
|
111
|
+
delivery_policy = {} # : Hash[String, untyped]
|
|
112
|
+
return [{ sink: WebhookSink.from_config(config), delivery_policy: delivery_policy }]
|
|
113
|
+
end
|
|
110
114
|
|
|
111
115
|
destinations.map.with_index(1) do |destination, index|
|
|
112
|
-
|
|
116
|
+
{
|
|
117
|
+
sink: Destinations::Registry.build(destination, label: "destinations[#{index - 1}]"),
|
|
118
|
+
delivery_policy: destination_delivery_policy(destination)
|
|
119
|
+
}
|
|
113
120
|
end
|
|
114
121
|
end
|
|
115
122
|
|
|
116
|
-
def
|
|
117
|
-
|
|
123
|
+
def destination_delivery_policy(destination)
|
|
124
|
+
retry_config = destination["retry"] || {}
|
|
125
|
+
{
|
|
126
|
+
"enabled" => destination.fetch("enabled", true),
|
|
127
|
+
"max_attempts" => retry_config.fetch("max_attempts", config.dig("retry", "max_attempts")),
|
|
128
|
+
"schedule_seconds" => retry_config.fetch("schedule_seconds", config.dig("retry", "schedule_seconds")),
|
|
129
|
+
"route_filter" => RouteFilter.new(destination["route"])
|
|
130
|
+
}
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def build_state_adapter
|
|
134
|
+
OperationalState::Registry.build(operational_state_adapter, config)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def operational_state_adapter
|
|
138
|
+
config.dig("operational_state", "adapter") || "sqlite"
|
|
118
139
|
end
|
|
119
140
|
|
|
120
141
|
def delivery_unit
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mammoth
|
|
4
|
+
# Reports local Mammoth capabilities without inspecting private internals.
|
|
5
|
+
class Capabilities
|
|
6
|
+
# Built-in OSS data-plane feature capabilities.
|
|
7
|
+
FEATURES = %w[
|
|
8
|
+
checkpointing
|
|
9
|
+
delivery_ledger
|
|
10
|
+
dead_letters
|
|
11
|
+
replay
|
|
12
|
+
health
|
|
13
|
+
metrics
|
|
14
|
+
routing
|
|
15
|
+
fanout
|
|
16
|
+
].freeze
|
|
17
|
+
|
|
18
|
+
attr_reader :config
|
|
19
|
+
|
|
20
|
+
# @param config [Mammoth::Configuration] loaded configuration
|
|
21
|
+
def initialize(config)
|
|
22
|
+
@config = config
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# @param config [Mammoth::Configuration] loaded configuration
|
|
26
|
+
# @return [Hash] JSON-friendly capabilities
|
|
27
|
+
def self.call(config)
|
|
28
|
+
new(config).to_h
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# @return [Hash] JSON-friendly capabilities
|
|
32
|
+
def to_h
|
|
33
|
+
{
|
|
34
|
+
operational_state: operational_state_adapter,
|
|
35
|
+
destinations: destination_types,
|
|
36
|
+
runtimes: Runtimes::Registry.names,
|
|
37
|
+
runtime: runtime_adapter,
|
|
38
|
+
features: FEATURES
|
|
39
|
+
}
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def operational_state_adapter
|
|
45
|
+
config.dig("operational_state", "adapter") || "sqlite"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def runtime_adapter
|
|
49
|
+
config.dig("runtime", "adapter") || "inline"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def destination_types
|
|
53
|
+
destinations = config.data["destinations"]
|
|
54
|
+
return [config.dig("webhook", "type") || "webhook"] unless destinations
|
|
55
|
+
|
|
56
|
+
destinations.map { |destination| destination.fetch("type", "webhook") }.uniq.sort
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
data/lib/mammoth/cli.rb
CHANGED
|
@@ -24,9 +24,11 @@ module Mammoth
|
|
|
24
24
|
" mammoth status CONFIG",
|
|
25
25
|
" mammoth start CONFIG",
|
|
26
26
|
" mammoth deliver-sample CONFIG EVENT_JSON",
|
|
27
|
-
" mammoth dead-letters list CONFIG [--status STATUS] [--
|
|
27
|
+
" mammoth dead-letters list CONFIG [--status STATUS] [--destination NAME] " \
|
|
28
|
+
"[--failed-after ISO8601] [--failed-before ISO8601] [--limit N]",
|
|
28
29
|
" mammoth dead-letters show CONFIG ID",
|
|
29
|
-
" mammoth dead-letters replay CONFIG [ID ...]"
|
|
30
|
+
" mammoth dead-letters replay CONFIG [ID ...] [--destination NAME] [--status STATUS] " \
|
|
31
|
+
"[--failed-after ISO8601] [--failed-before ISO8601] [--limit N]",
|
|
30
32
|
" mammoth observability CONFIG"
|
|
31
33
|
].join("\n")
|
|
32
34
|
|
|
@@ -100,8 +102,7 @@ module Mammoth
|
|
|
100
102
|
def status
|
|
101
103
|
config = load_config
|
|
102
104
|
store = SQLiteStore.connect(config.dig("sqlite", "path"))
|
|
103
|
-
|
|
104
|
-
0
|
|
105
|
+
Commands::StatusCommand.new(config, sqlite_store: store).call
|
|
105
106
|
end
|
|
106
107
|
|
|
107
108
|
def start
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mammoth
|
|
4
|
+
# Local command objects shared by CLI and future control-plane agents.
|
|
5
|
+
module Commands
|
|
6
|
+
# Reusable local command object for status inspection.
|
|
7
|
+
class StatusCommand
|
|
8
|
+
attr_reader :config, :sqlite_store, :output
|
|
9
|
+
|
|
10
|
+
# @param config [Mammoth::Configuration] loaded configuration
|
|
11
|
+
# @param sqlite_store [Mammoth::SQLiteStore, nil] optional operational store
|
|
12
|
+
# @param output [#puts] output stream
|
|
13
|
+
def initialize(config, sqlite_store: nil, output: $stdout)
|
|
14
|
+
@config = config
|
|
15
|
+
@sqlite_store = sqlite_store
|
|
16
|
+
@output = output
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Execute the status command.
|
|
20
|
+
#
|
|
21
|
+
# @return [Integer] process-style status code
|
|
22
|
+
def call
|
|
23
|
+
Status.call(config, sqlite_store: sqlite_store, output: output)
|
|
24
|
+
0
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|