Oracle Coherence Community Edition Sink
The Oracle Coherence Community Edition sink is a first-party, experimental sink for storing one complete normalized nats-sinks event as the JSON value of one Oracle Coherence key/value entry.
It is useful when a deployment needs a low-latency Oracle Coherence Community Edition data grid view of events while preserving the same core delivery rule used by the other built-in sinks:
Commit first. ACK last. Design for redelivery.
The sink is intentionally conservative. It does not treat Coherence as a relational database, does not build dynamic cache names from messages, and does not let message metadata choose arbitrary modules, serializers, or methods. It opens one configured cache or map, derives deterministic keys from approved idempotency metadata, writes complete JSON-compatible values, and returns success only after the Coherence client operation completes.
Status
The connector is built in and available as sink.type: "coherence", but it is
marked experimental in the connector registry. The local unit tests and the
container-backed e2e flow prove the nats-sinks integration contract. They do
not prove that a given production Oracle Coherence cluster has persistence,
backup, recovery, replication, authorization, TLS, or operational durability
configured correctly.
Operators should use the sink as an ACK-gated durable custody target only after they have reviewed and tested the Oracle Coherence Community Edition cluster policy that backs the configured cache or map. Until then, it is often better to use the sink as an optional fan-out target next to a required Oracle Database, Oracle MySQL, file, or encrypted edge spool target.
Install
The base package does not install the Oracle Coherence Python client. Install the optional extra when the sink will connect to Oracle Coherence:
python -m pip install "nats-sinks[coherence]"
Expected package metadata includes the optional dependency:
coherence-client>=2,<3
Minimal Configuration
{
"nats": {
"url": "nats://localhost:4222",
"stream": "EVENTS",
"consumer": "coherence-sink",
"subject": "events.>"
},
"sink": {
"type": "coherence",
"address": "127.0.0.1:1408",
"cache_name": "nats_sinks_events"
}
}
Validate the configuration without opening Oracle Coherence:
nats-sink validate examples/oracle-coherence-basic/config.json
Expected output:
Configuration is valid.
Active sink: coherence
ACK policy: commit-then-acknowledge
Full Configuration Example
{
"sink": {
"type": "coherence",
"address": "127.0.0.1:1408",
"scope": "",
"cache_name": "mission_event_cache",
"storage": "cache",
"serializer": "json",
"key_strategy": "stream_sequence",
"key_prefix": "mission-demo",
"duplicate_policy": "skip_existing",
"payload_mode": "json_or_envelope",
"ttl_seconds": 86400,
"max_key_bytes": 512,
"max_value_bytes": 1048576,
"request_timeout_seconds": 10,
"ready_timeout_seconds": 30,
"session_disconnect_seconds": 30,
"durability": "operator_confirmed"
}
}
| Field | Required | Default | Valid values | Description |
|---|---|---|---|---|
type |
yes | none | coherence |
Selects the Oracle Coherence Community Edition sink. |
address |
no | 127.0.0.1:1408 |
host:port without scheme or userinfo. |
Coherence gRPC endpoint. Credentials and URLs are intentionally not accepted in this field. |
scope |
no | empty string | Plain bounded text. | Optional Coherence scope. |
cache_name |
no | nats_sinks_events |
Letters, numbers, dots, underscores, or hyphens; up to 128 characters. | Named cache or map receiving event values. |
storage |
no | cache |
cache or map |
cache uses Session.get_cache(...); map uses Session.get_map(...). |
serializer |
no | json |
json |
Coherence client serializer format. Other serializers are rejected. |
key_strategy |
no | idempotency_key |
idempotency_key, stream_sequence, message_id, payload_sha256 |
Determines the deterministic K/V key. |
key_prefix |
no | none | Letters, numbers, dots, underscores, colons, or hyphens; up to 128 characters. | Optional namespace prefix prepended to every generated key. |
duplicate_policy |
no | skip_existing |
skip_existing, replace, fail_existing |
Behavior when the key already exists. |
payload_mode |
no | json_or_envelope |
Core payload storage mode. | Valid JSON is stored as JSON; text or binary payloads can be wrapped in the standard envelope. |
ttl_seconds |
no | none | 1 to 31536000; cache only. |
Optional cache TTL. Rejected when storage is map. |
max_key_bytes |
no | 512 |
64 to 4096 |
Maximum UTF-8 key size after prefixing. |
max_value_bytes |
no | 1048576 |
1 to 16777216 |
Maximum JSON value size before the client write is attempted. |
request_timeout_seconds |
no | 10 |
>0 to 300 |
Per startup and write timeout used by nats-sinks. |
ready_timeout_seconds |
no | 30 |
0 to 300 |
Passed to the Coherence client session options. |
session_disconnect_seconds |
no | 30 |
0 to 300 |
Passed to the Coherence client session options. |
durability |
no | operator_confirmed |
operator_confirmed |
Records that the operator owns the Coherence durability review. |
Stored Value Shape
The value is a single JSON-compatible object. It preserves the normalized event, payload, headers, standard NATS metadata, priority, classification, labels, mission metadata, data-centric security labels, and custody metadata.
Example value:
{
"schema": "nats_sinks.coherence.event.v1",
"schema_version": 1,
"subject": "events.created",
"stream": "EVENTS",
"stream_sequence": 42,
"consumer": "coherence-sink",
"consumer_sequence": 7,
"message_id": "event-42",
"priority": "high",
"classification": "NATO UNCLASSIFIED",
"labels": "sensor;audit",
"labels_list": ["sensor", "audit"],
"payload": {
"event_id": "event-42",
"status": "created"
},
"payload_info": {
"original_format": "json",
"wrapped": false,
"sha256": "example-redacted",
"size_bytes": 42
},
"headers": {
"Nats-Msg-Id": "event-42"
},
"mission_metadata": {
"phase": "find"
},
"security_labels": {
"classification": "NATO UNCLASSIFIED"
},
"custody": null,
"metadata": {
"stream": "EVENTS",
"consumer": "coherence-sink"
}
}
Payload bytes are not logged by default. The example uses fake values and a redacted hash placeholder.
Key Strategies
| Strategy | Key form | Notes |
|---|---|---|
idempotency_key |
stream-sequence:<stream>:<sequence>, then message ID, then payload hash fallback. |
Recommended default. Uses the core envelope idempotency helper. |
stream_sequence |
stream-sequence:<stream>:<sequence> |
Fails closed when stream metadata is missing. |
message_id |
message-id:<message_id> |
Fails closed when no message ID is available. |
payload_sha256 |
payload-sha256:<subject>:<sha256> |
Available for simple replay scenarios, but avoid it when payload encryption is enabled because ciphertext is intentionally non-deterministic. |
Do not use priority, classification, labels, or mission metadata as keys. They are operational metadata, not duplicate-detection identifiers.
Duplicate Policies
| Policy | Coherence operation | Behavior |
|---|---|---|
skip_existing |
put_if_absent |
Existing key is treated as a successful prior write. This is the default redelivery-safe behavior. |
replace |
put |
Existing value is overwritten. Use only when replacing committed values is acceptable. |
fail_existing |
put_if_absent |
Existing key raises a permanent sink error. Use only for flows where duplicate redelivery should go to DLQ or operator review. |
Fan-Out Example
The Coherence sink can be used as a required or optional child sink in active fan-out. This example requires Oracle Database before ACK and gives the Coherence side copy a bounded grace window:
{
"sink": {
"type": "fanout"
},
"sinks": {
"oracle_primary": {
"type": "oracle",
"dsn": "tcps://database.example.invalid/service",
"user": "app_user",
"password_env": "NATS_SINKS_ORACLE_PASSWORD",
"table": "NATS_SINK_EVENTS"
},
"coherence_read_model": {
"type": "coherence",
"address": "127.0.0.1:1408",
"cache_name": "mission_read_model",
"duplicate_policy": "skip_existing"
}
},
"routing": {
"enabled": true,
"routes": [
{
"name": "events_to_oracle_and_coherence",
"match": {
"subject": "events.>"
},
"targets": [
"oracle_primary",
{
"sink": "coherence_read_model",
"required": false
}
]
}
]
}
}
Because coherence_read_model is optional and the named sink type is known,
the loader applies the Coherence optional ACK-gate defaults:
minimum_wait_ms=1000
timeout_ms=5000
Local E2E Test
The repository includes a local Oracle Coherence Community Edition test backend at Oracle Coherence CE Test Backend. Run the sink e2e flow from an isolated environment that has Docker and the optional Coherence Python client:
python scripts/run-coherence-sink-e2e.py
Expected output:
. [100%]
1 passed
Oracle Coherence sink e2e test passed.
The script builds the local test image, starts a short-lived Coherence
container on a random loopback port, runs
tests/integration/test_coherence_sink_e2e.py, reads the stored JSON value back
through the Coherence client, removes the test key, and removes the container
by default.
When Docker is not available, the integration test stays skipped unless explicitly enabled:
python -m pytest tests/integration/test_coherence_sink_e2e.py -q
Expected output:
s [100%]
1 skipped
Security Notes
- Treat cache names, key prefixes, TTLs, serializer mode, duplicate policy, and value size limits as configuration trust boundaries.
- Keep Coherence security, TLS, persistence, backups, and cluster authorization in the Coherence deployment. The sink does not grant or manage those controls.
- Do not put credentials, endpoints with userinfo, payloads, message IDs, classification values, labels, or subjects into public issue comments, evidence, or metrics labels.
- Keep the Coherence Python client behind the optional
coherenceextra so the base package stays small and dependency review stays explicit. - Use
skip_existingor another reviewed idempotency strategy before making the sink a required ACK-gated destination.