| Safe Haskell | None |
|---|---|
| Language | GHC2024 |
Keiro.Inbox.Types
Description
Shared types for the idempotent integration-event inbox.
The inbox lives in the consuming bounded context. When a Kafka consumer receives an integration event, the inbox records a stable external identity for that message and runs the local handler in the same transaction. Duplicate redeliveries (Kafka offset retry, rebalance, producer republish) become observable as duplicates instead of re-running the handler.
Synopsis
- newtype RetryDelay = RetryDelay {}
- data InboxDedupePolicy
- data InboxPersistence
- data InboxStatus
- data InboxResult a
- data InboxError = DedupePolicyUnsatisfied !InboxDedupePolicy
- data InboxRow = InboxRow {
- source :: !Text
- dedupeKey :: !Text
- event :: !IntegrationEvent
- kafka :: !(Maybe KafkaDeliveryRef)
- status :: !InboxStatus
- attemptCount :: !Int
- receivedAt :: !UTCTime
- completedAt :: !(Maybe UTCTime)
- failedAt :: !(Maybe UTCTime)
- lastError :: !(Maybe Text)
- data KafkaDeliveryRef = KafkaDeliveryRef {}
- inboxStatusText :: InboxStatus -> Text
- parseInboxStatus :: Text -> Either Text InboxStatus
- dedupeKeyFor :: InboxDedupePolicy -> IntegrationEvent -> Maybe KafkaDeliveryRef -> Either InboxError Text
Documentation
newtype RetryDelay #
Delay before retry.
Constructors
| RetryDelay | |
Fields | |
Instances
| Show RetryDelay # | |
Defined in Shibuya.Core.Ack Methods showsPrec :: Int -> RetryDelay -> ShowS # show :: RetryDelay -> String # showList :: [RetryDelay] -> ShowS # | |
| Eq RetryDelay # | |
Defined in Shibuya.Core.Ack | |
data InboxDedupePolicy Source #
Which identity is used as the inbox primary key for an
IntegrationEvent.
PreferIntegrationMessageId(default) — use the application-levelmessageIdminted at the producer's outbox enqueue. EP-19 / EP-20 keep this id stable across publish retries, so it is the natural primary dedupe key for Kafka-delivered events.PreferSourceEventIdentity— use thesourceEventIdof the private event that produced this integration event. Useful when a producer may emit the same logical fact under differentmessageIds (e.g. schema-upgrade republish), and the consumer wants those republishes collapsed to a single handler run.KafkaDeliveryIdentity— use the Kafka topic-partition-offset triple as the dedupe key. Fallback only when neithermessageIdnor source identity is available. This identifies one broker delivery, not one logical producer message: if a producer republishes the same logical message, Kafka assigns a new offset and this policy will not collapse the republish.CustomDedupeKey— caller supplies the key. Use only when the other policies cannot represent the identity scheme; the consuming service owns key collision resistance.
Constructors
| PreferIntegrationMessageId | |
| PreferSourceEventIdentity | |
| KafkaDeliveryIdentity | |
| CustomDedupeKey !Text |
Instances
data InboxPersistence Source #
How much of the integration-event envelope the inbox persists on the success path.
The failure path always persists the full envelope because a failed inbox row is the operator's dead-letter record.
Constructors
| PersistFullEnvelope | |
| PersistDedupeOnly |
Instances
| Generic InboxPersistence Source # | |||||
Defined in Keiro.Inbox.Types Associated Types
Methods from :: InboxPersistence -> Rep InboxPersistence x # to :: Rep InboxPersistence x -> InboxPersistence # | |||||
| Show InboxPersistence Source # | |||||
Defined in Keiro.Inbox.Types Methods showsPrec :: Int -> InboxPersistence -> ShowS # show :: InboxPersistence -> String # showList :: [InboxPersistence] -> ShowS # | |||||
| Eq InboxPersistence Source # | |||||
Defined in Keiro.Inbox.Types Methods (==) :: InboxPersistence -> InboxPersistence -> Bool # (/=) :: InboxPersistence -> InboxPersistence -> Bool # | |||||
| type Rep InboxPersistence Source # | |||||
data InboxStatus Source #
Lifecycle state of an inbox row.
InboxProcessing— legacy on-disk state from older wrappers and reserved for future async paths. Current single-transaction intake inserts fresh successful rows directly asInboxCompleted.InboxCompleted— handler ran to completion; terminal.InboxFailed— handler signaled a permanent failure; terminal. The caller is responsible for operator action (dead-letter, manual retry).
Constructors
| InboxProcessing | |
| InboxCompleted | |
| InboxFailed |
Instances
| Generic InboxStatus Source # | |||||
Defined in Keiro.Inbox.Types Associated Types
| |||||
| Show InboxStatus Source # | |||||
Defined in Keiro.Inbox.Types Methods showsPrec :: Int -> InboxStatus -> ShowS # show :: InboxStatus -> String # showList :: [InboxStatus] -> ShowS # | |||||
| Eq InboxStatus Source # | |||||
Defined in Keiro.Inbox.Types | |||||
| type Rep InboxStatus Source # | |||||
Defined in Keiro.Inbox.Types type Rep InboxStatus = D1 ('MetaData "InboxStatus" "Keiro.Inbox.Types" "keiro-0.11.0.0-inplace" 'False) (C1 ('MetaCons "InboxProcessing" 'PrefixI 'False) (U1 :: Type -> Type) :+: (C1 ('MetaCons "InboxCompleted" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "InboxFailed" 'PrefixI 'False) (U1 :: Type -> Type))) | |||||
data InboxResult a Source #
The classified outcome of runInboxTransaction.
- 'InboxProcessed a' — first delivery; handler ran and returned
a. InboxDuplicate— a previous delivery already completed; handler not run.InboxInProgress— a previous attempt is currently in-flight, or a legacyprocessingrow was read. Current single-transaction intake does not commitprocessingrows. Treat as transient.InboxPreviouslyFailed— a previous attempt recorded a permanent failure. Operator should review before reprocessing.
Constructors
| InboxProcessed !a | |
| InboxDuplicate | |
| InboxInProgress | |
| InboxPreviouslyFailed !(Maybe Text) | |
| InboxHandlerFailed !Text !Int |
Instances
| Generic (InboxResult a) Source # | |||||
Defined in Keiro.Inbox.Types Associated Types
Methods from :: InboxResult a -> Rep (InboxResult a) x # to :: Rep (InboxResult a) x -> InboxResult a # | |||||
| Show a => Show (InboxResult a) Source # | |||||
Defined in Keiro.Inbox.Types Methods showsPrec :: Int -> InboxResult a -> ShowS # show :: InboxResult a -> String # showList :: [InboxResult a] -> ShowS # | |||||
| Eq a => Eq (InboxResult a) Source # | |||||
Defined in Keiro.Inbox.Types Methods (==) :: InboxResult a -> InboxResult a -> Bool # (/=) :: InboxResult a -> InboxResult a -> Bool # | |||||
| type Rep (InboxResult a) Source # | |||||
Defined in Keiro.Inbox.Types type Rep (InboxResult a) = D1 ('MetaData "InboxResult" "Keiro.Inbox.Types" "keiro-0.11.0.0-inplace" 'False) ((C1 ('MetaCons "InboxProcessed" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 a)) :+: C1 ('MetaCons "InboxDuplicate" 'PrefixI 'False) (U1 :: Type -> Type)) :+: (C1 ('MetaCons "InboxInProgress" 'PrefixI 'False) (U1 :: Type -> Type) :+: (C1 ('MetaCons "InboxPreviouslyFailed" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 (Maybe Text))) :+: C1 ('MetaCons "InboxHandlerFailed" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Text) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Int))))) | |||||
data InboxError Source #
Errors surfaced by the inbox wrapper that originate from the inbox itself rather than from the supplied handler.
Constructors
| DedupePolicyUnsatisfied !InboxDedupePolicy | The integration event lacked the field required by the chosen policy. |
Instances
| Generic InboxError Source # | |||||
Defined in Keiro.Inbox.Types Associated Types
| |||||
| Show InboxError Source # | |||||
Defined in Keiro.Inbox.Types Methods showsPrec :: Int -> InboxError -> ShowS # show :: InboxError -> String # showList :: [InboxError] -> ShowS # | |||||
| Eq InboxError Source # | |||||
Defined in Keiro.Inbox.Types | |||||
| type Rep InboxError Source # | |||||
Defined in Keiro.Inbox.Types type Rep InboxError = D1 ('MetaData "InboxError" "Keiro.Inbox.Types" "keiro-0.11.0.0-inplace" 'False) (C1 ('MetaCons "DedupePolicyUnsatisfied" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 InboxDedupePolicy))) | |||||
One row read back from keiro_inbox.
Rows written with PersistDedupeOnly decode with an empty
IntegrationEvent payloadBytes, no attributes, no trace context, and
no schema reference. Identity, routing, source-event ids, occurrence
time, and Kafka delivery metadata are still preserved.
Constructors
| InboxRow | |
Fields
| |
Instances
| Generic InboxRow Source # | |||||
Defined in Keiro.Inbox.Types Associated Types
| |||||
| Show InboxRow Source # | |||||
| Eq InboxRow Source # | |||||
| type Rep InboxRow Source # | |||||
Defined in Keiro.Inbox.Types type Rep InboxRow = D1 ('MetaData "InboxRow" "Keiro.Inbox.Types" "keiro-0.11.0.0-inplace" 'False) (C1 ('MetaCons "InboxRow" 'PrefixI 'True) (((S1 ('MetaSel ('Just "source") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Text) :*: S1 ('MetaSel ('Just "dedupeKey") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Text)) :*: (S1 ('MetaSel ('Just "event") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 IntegrationEvent) :*: (S1 ('MetaSel ('Just "kafka") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 (Maybe KafkaDeliveryRef)) :*: S1 ('MetaSel ('Just "status") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 InboxStatus)))) :*: ((S1 ('MetaSel ('Just "attemptCount") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Int) :*: S1 ('MetaSel ('Just "receivedAt") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 UTCTime)) :*: (S1 ('MetaSel ('Just "completedAt") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 (Maybe UTCTime)) :*: (S1 ('MetaSel ('Just "failedAt") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 (Maybe UTCTime)) :*: S1 ('MetaSel ('Just "lastError") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 (Maybe Text))))))) | |||||
data KafkaDeliveryRef Source #
Optional Kafka-delivery metadata recorded alongside an inbox row.
Used by KafkaDeliveryIdentity to compute the dedupe key, and stored on
the row regardless of policy so operators can correlate the inbox
record with Kafka logs. Not part of the EP-19 envelope.
Instances
| Generic KafkaDeliveryRef Source # | |||||
Defined in Keiro.Inbox.Types Associated Types
Methods from :: KafkaDeliveryRef -> Rep KafkaDeliveryRef x # to :: Rep KafkaDeliveryRef x -> KafkaDeliveryRef # | |||||
| Show KafkaDeliveryRef Source # | |||||
Defined in Keiro.Inbox.Types Methods showsPrec :: Int -> KafkaDeliveryRef -> ShowS # show :: KafkaDeliveryRef -> String # showList :: [KafkaDeliveryRef] -> ShowS # | |||||
| Eq KafkaDeliveryRef Source # | |||||
Defined in Keiro.Inbox.Types Methods (==) :: KafkaDeliveryRef -> KafkaDeliveryRef -> Bool # (/=) :: KafkaDeliveryRef -> KafkaDeliveryRef -> Bool # | |||||
| type Rep KafkaDeliveryRef Source # | |||||
Defined in Keiro.Inbox.Types type Rep KafkaDeliveryRef = D1 ('MetaData "KafkaDeliveryRef" "Keiro.Inbox.Types" "keiro-0.11.0.0-inplace" 'False) (C1 ('MetaCons "KafkaDeliveryRef" 'PrefixI 'True) (S1 ('MetaSel ('Just "topic") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Text) :*: (S1 ('MetaSel ('Just "partition") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Int64) :*: S1 ('MetaSel ('Just "offset") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Int64)))) | |||||
inboxStatusText :: InboxStatus -> Text Source #
parseInboxStatus :: Text -> Either Text InboxStatus Source #
dedupeKeyFor :: InboxDedupePolicy -> IntegrationEvent -> Maybe KafkaDeliveryRef -> Either InboxError Text Source #
Compute the inbox dedupe key for an integration event under the
given policy plus optional Kafka delivery context. Returns Left when
the policy demands a field the envelope does not carry (for example,
PreferSourceEventIdentity on an envelope with no
sourceEventId).