Class RedisOutboxEntry
:entries Hash field for one
outbox event (design doc core storage model). One field per event_id; the
value is this object encoded as JSON.
The Avro payload bytes are carried Base64-encoded because JSON is not
binary-safe — the relay/poller decode them back to byte[] before the
Kafka send. PII is never inlined: per ADR-0002 §3b the events are
pointer-based, so the payload is an Avro envelope referencing aggregate ids,
not raw personal data.
Field semantics mirror OutboxRecord so the two backends present a
uniform lifecycle:
status—PENDING/SENT/FAILED(theARCHIVEDPG state has no Redis analogue; retention HDELs SENT entries instead, refinement #9).retries— incremented on each failed attempt.createdAt— enqueue epoch-ms (informational; the:pendingscore isnextAttemptAt, NOT createdAt, refinement #5).sentAt— set on the PENDING→SENT transition; drives retention eligibility.lastError— truncated failure message (refinement parity withOutboxRecord.LAST_ERROR_MAX_LENGTH).
Instances are immutable; lifecycle transitions are performed in Lua on the
server side (the JSON is re-read + re-written inside the EVAL), so this class
only needs round-trip (de)serialisation + conversion to/from
OutboxRecord for the SPI's findPendingBatch contract.
@JsonInclude(NON_NULL) is load-bearing, not cosmetic. The
Lua transition scripts (outbox-mark-sent.lua, retention-delete-sent.lua)
read the entry back via cjson.decode and test if not
entry.sentAtEpochMs. Lua's cjson decodes a JSON null to the truthy
sentinel cjson.null (NOT Lua nil), so a serialised
"sentAtEpochMs":null would make not entry.sentAtEpochMs false
and break the age check. Omitting null fields entirely keeps the Lua
nil-test correct.
-
Constructor Summary
ConstructorsConstructorDescriptionRedisOutboxEntry(UUID aggregateId, UUID eventId, String topic, int schemaVersion, String payloadBase64, String status, int retries, long createdAtEpochMs, Long sentAtEpochMs, String lastError) Full constructor used by Jackson on deserialisation and by the relay/SPI on construction. -
Method Summary
Modifier and TypeMethodDescriptionbyte[]longintintgetTopic()static RedisOutboxEntrypendingFrom(OutboxRecord record) Builds a freshPENDINGentry from anOutboxRecordthe orchestration layer populated.toRecord()Reconstructs anOutboxRecordview of this entry for theOutboxBackend.findPendingBatch(int)contract.toString()
-
Constructor Details
-
RedisOutboxEntry
public RedisOutboxEntry(UUID aggregateId, UUID eventId, String topic, int schemaVersion, String payloadBase64, String status, int retries, long createdAtEpochMs, Long sentAtEpochMs, String lastError) Full constructor used by Jackson on deserialisation and by the relay/SPI on construction.- Parameters:
aggregateId- aggregate identifier (Kafka partition-key hint)eventId- outbox event id (Hash field key)topic- Kafka topicschemaVersion- Avro schema version mirrored for operator triagepayloadBase64- Base64-encoded Avro payload bytesstatus- lifecycle status string (PENDING / SENT / FAILED)retries- publish-attempt countercreatedAtEpochMs- enqueue time, epoch-mssentAtEpochMs- publish-success time, epoch-ms, ornullwhen not yet sentlastError- truncated failure message, ornull
-
-
Method Details
-
pendingFrom
Builds a freshPENDINGentry from anOutboxRecordthe orchestration layer populated.- Parameters:
record- the PENDING record (aggregateId, eventId, topic, schemaVersion, payloadBytes, createdAt populated); nevernull- Returns:
- a new PENDING entry with retries=0, sentAt=null, lastError=null
-
toRecord
Reconstructs anOutboxRecordview of this entry for theOutboxBackend.findPendingBatch(int)contract. TherecordVersionis left at its default (0) — the Redis backend uses status-guarded Lua transitions, not JPA optimistic locking, so the version field is inert here.- Returns:
- a transient
OutboxRecordmirroring this entry's fields
-
decodePayload
public byte[] decodePayload()- Returns:
- the Avro payload bytes, Base64-decoded from
payloadBase64
-
getAggregateId
-
getEventId
-
getTopic
-
getSchemaVersion
public int getSchemaVersion() -
getPayloadBase64
-
getStatus
-
getRetries
public int getRetries() -
getCreatedAtEpochMs
public long getCreatedAtEpochMs() -
getSentAtEpochMs
-
getLastError
-
toString
-