|
morph 0.1.0
Asynchronous bridge between GUI thread and business models
|
Moves committed-but-unrelayed rows from a model's own outbox table to a durable IActionLog, then marks them relayed in the model's own store. More...
#include <outbox.hpp>
Public Member Functions | |
| OutboxRelayResult | relay () |
| Moves every row drainOutbox() currently reports to sink, then marks the whole batch relayed via markRelayed. | |
Public Attributes | |
| std::function< std::vector< LogEntry >()> | drainOutbox |
| Pulls committed-but-unrelayed rows from the model's own store. Must be non-destructive: the same rows are re-drained until markRelayed records them, including across process restarts. | |
| std::function< void(std::span< const LogEntry >)> | markRelayed |
Marks rows relayed in the model's own store (by identity or LogEntry::idempotencyKey) so a later drainOutbox() call no longer returns them. | |
| std::shared_ptr< IActionLog > | sink |
| Durable audit sink rows are forwarded to. | |
Moves committed-but-unrelayed rows from a model's own outbox table to a durable IActionLog, then marks them relayed in the model's own store.
Closes the "two independent writes" gap between a model's own transactional store and the action log: a store-backed model writes its business tables and an outbox row (shaped like LogEntry, including a stable idempotencyKey) in one local transaction — see IModelHolder::setOutboxManaged — and OutboxRelay is the separate, asynchronous step that moves that row into the real durable sink.
drainOutbox/markRelayed are injected callables against the model's own store, exactly as morph::offline::ReconnectCoordinator::Deps and morph::offline::SyncWorker::ReplayFunction inject their side effects — morph::journal never touches the model's database. Mirroring ReconnectCoordinator::Deps, a null member is logged (via morph::log::logError) at the start of every relay() call but is not rejected — invoking a null member still throws (std::bad_function_call) or crashes as usual.
Definition at line 67 of file outbox.hpp.
|
inline |
Moves every row drainOutbox() currently reports to sink, then marks the whole batch relayed via markRelayed.
A no-op (returns {.relayed = 0} without touching sink or calling markRelayed) if drainOutbox() returns no rows.
markRelayed runs only after sink->flush() returns normally. An IActionLog that cannot make the batch durable throws (see IActionLog::flush), which propagates out of here before the rows are marked — so they stay in the outbox and a later relay() retries them. This is what keeps the relay at-least-once instead of at-most-once: were the failure swallowed, the rows would be recorded as relayed while nothing reached the sink, and nothing would ever surface the loss.
Runs on sink's owner (see IActionLog::owner()): sink->flush() answers only there, which is what lets its failure reach this call.
| NullSinkError | if sink is null and drainOutbox() reports at least one row — thrown before sink is ever dereferenced, so no row is lost or marked relayed. A null sink with nothing to relay is still a no-op, exactly like an empty outbox with a real sink: nothing would touch sink either way. |
| std::exception | propagated from sink->append() or sink->flush(); the batch is left unmarked and therefore retryable. |
Definition at line 106 of file outbox.hpp.
| std::function<std::vector<LogEntry>()> morph::journal::OutboxRelay::drainOutbox |
Pulls committed-but-unrelayed rows from the model's own store. Must be non-destructive: the same rows are re-drained until markRelayed records them, including across process restarts.
Definition at line 71 of file outbox.hpp.
| std::function<void(std::span<const LogEntry>)> morph::journal::OutboxRelay::markRelayed |
Marks rows relayed in the model's own store (by identity or LogEntry::idempotencyKey) so a later drainOutbox() call no longer returns them.
Definition at line 76 of file outbox.hpp.
| std::shared_ptr<IActionLog> morph::journal::OutboxRelay::sink |
Durable audit sink rows are forwarded to.
Definition at line 79 of file outbox.hpp.