API Reference
This page is a compact reference for the public API exposed by the sync module. It lists the main types, configuration structures, methods, and namespaces used by the offline-first operation pipeline.
For conceptual explanations and workflow examples, read the earlier pages first. This page is meant for lookup once the model is already understood.
Public header
Use the public module header in normal application code:
#include <vix/sync.hpp>This header includes the public sync components:
Operation
RetryPolicy
Outbox
OutboxStore
FileOutboxStore
SendResult
ISyncTransport
SyncWorker
SyncEngine
Wal
WalReader
WalRecord
WalWriterFor examples that print output, include:
#include <vix/print.hpp>Namespaces
The sync module is organized into a few focused namespaces.
| Namespace | Purpose |
|---|---|
vix::sync | Core operation and retry types. |
vix::sync::outbox | Durable outbox and outbox store interfaces. |
vix::sync::engine | Sync workers, engine, transport, and send result. |
vix::sync::wal | Write-ahead log records, reader, writer, and WAL. |
vix::sync::OperationStatus
OperationStatus represents the durable lifecycle state of a sync operation.
enum class OperationStatus : std::uint8_t
{
Pending = 0,
InFlight,
Done,
Failed,
PermanentFailed
};| Value | Meaning |
|---|---|
Pending | Operation is stored and waiting to be processed. |
InFlight | Operation has been claimed by a worker. |
Done | Operation completed successfully. |
Failed | Operation failed, but may be retried. |
PermanentFailed | Operation failed and should not be retried. |
vix::sync::Operation
Operation is the durable unit of work stored in the outbox and processed by the sync engine.
struct Operation
{
std::string id;
std::string kind;
std::string target;
std::string payload;
std::string idempotency_key;
std::int64_t created_at_ms{0};
std::int64_t updated_at_ms{0};
std::uint32_t attempt{0};
std::int64_t next_retry_at_ms{0};
OperationStatus status{OperationStatus::Pending};
std::string last_error;
bool is_done() const noexcept;
bool is_pending() const noexcept;
bool is_failed() const noexcept;
void fail(std::string err, std::int64_t now_ms);
void done(std::int64_t now_ms);
};Fields
| Field | Purpose |
|---|---|
id | Local operation identifier. |
kind | Logical operation type, such as message.send. |
target | Destination understood by the transport. |
payload | Opaque application payload. |
idempotency_key | Stable key used by the receiver to deduplicate retries. |
created_at_ms | Creation timestamp in milliseconds. |
updated_at_ms | Last update timestamp in milliseconds. |
attempt | Number of delivery attempts recorded for the operation. |
next_retry_at_ms | Time when the operation becomes eligible for retry. |
status | Current lifecycle status. |
last_error | Last recorded error message. |
Helpers
bool is_done() const noexcept;
bool is_pending() const noexcept;
bool is_failed() const noexcept;These helpers check the current status.
void fail(std::string err, std::int64_t now_ms);
void done(std::int64_t now_ms);These methods update the in-memory operation value. When the operation is already stored in an outbox, prefer Outbox::fail() and Outbox::complete() so the persistent store is updated.
vix::sync::RetryPolicy
RetryPolicy computes retry timing for retryable failures.
struct RetryPolicy
{
std::uint32_t max_attempts{8};
std::int64_t base_delay_ms{500};
std::int64_t max_delay_ms{30'000};
double factor{2.0};
double jitter_ratio{0.2};
bool can_retry(std::uint32_t attempt) const noexcept;
std::int64_t compute_delay_ms(std::uint32_t attempt) const noexcept;
};Fields
| Field | Purpose |
|---|---|
max_attempts | Maximum number of retry attempts allowed by the policy. |
base_delay_ms | Delay used as the base for the first retry. |
max_delay_ms | Maximum retry delay. |
factor | Exponential backoff multiplier. |
jitter_ratio | Jitter setting exposed to higher-level scheduling logic. |
Methods
bool can_retry(std::uint32_t attempt) const noexcept;Returns true when the given attempt count is still within the retry limit.
std::int64_t compute_delay_ms(std::uint32_t attempt) const noexcept;Returns the deterministic exponential backoff delay for the attempt. The delay is clamped between base_delay_ms and max_delay_ms.
compute_delay_ms() does not apply randomness. The jitter_ratio field is available for higher-level code that wants to apply jitter explicitly.
vix::sync::outbox::ListOptions
ListOptions controls how an OutboxStore lists operations.
struct ListOptions
{
std::size_t limit{50};
std::int64_t now_ms{0};
bool only_ready{true};
bool include_inflight{false};
};| Field | Purpose |
|---|---|
limit | Maximum number of operations to return. |
now_ms | Current time used for readiness checks. |
only_ready | Excludes operations waiting for a future retry time. |
include_inflight | Includes operations currently marked as InFlight. |
vix::sync::outbox::OutboxStore
OutboxStore is the abstract persistence interface used by Outbox.
class OutboxStore
{
public:
virtual ~OutboxStore() = default;
virtual void put(const vix::sync::Operation &op) = 0;
virtual std::optional<vix::sync::Operation>
get(const std::string &id) = 0;
virtual std::vector<vix::sync::Operation>
list(const ListOptions &opt) = 0;
virtual bool claim(
const std::string &id,
const std::string &owner,
std::int64_t now_ms
) = 0;
virtual bool mark_done(
const std::string &id,
std::int64_t now_ms
) = 0;
virtual bool mark_failed(
const std::string &id,
const std::string &error,
std::int64_t now_ms,
std::int64_t next_retry_at_ms
) = 0;
virtual std::size_t prune_done(
std::int64_t older_than_ms
) = 0;
virtual bool mark_permanent_failed(
const std::string &id,
const std::string &error,
std::int64_t now_ms
) = 0;
virtual std::size_t requeue_inflight_older_than(
std::int64_t now_ms,
std::int64_t timeout_ms
) = 0;
};Methods
| Method | Purpose |
|---|---|
put | Inserts or updates an operation. |
get | Retrieves an operation by id. |
list | Lists operations matching ListOptions. |
claim | Marks an operation as in-flight and assigns an owner. |
mark_done | Marks an operation as completed. |
mark_failed | Marks an operation as failed with a retry time. |
prune_done | Removes completed operations older than a cutoff. |
mark_permanent_failed | Marks an operation as permanently failed. |
requeue_inflight_older_than | Requeues old in-flight operations after a timeout. |
Custom stores should implement this interface when the default file-backed store is not enough.
vix::sync::outbox::FileOutboxStore
FileOutboxStore is the default JSON-backed implementation of OutboxStore.
class FileOutboxStore final : public OutboxStore
{
public:
struct Config
{
std::filesystem::path file_path{"./.vix/outbox.json"};
bool pretty_json{false};
bool fsync_on_write{false};
};
explicit FileOutboxStore(Config cfg);
void put(const vix::sync::Operation &op) override;
std::optional<vix::sync::Operation>
get(const std::string &id) override;
std::vector<vix::sync::Operation>
list(const ListOptions &opt) override;
bool claim(
const std::string &id,
const std::string &owner,
std::int64_t now_ms
) override;
bool mark_done(
const std::string &id,
std::int64_t now_ms
) override;
bool mark_failed(
const std::string &id,
const std::string &error,
std::int64_t now_ms,
std::int64_t next_retry_at_ms
) override;
std::size_t prune_done(
std::int64_t older_than_ms
) override;
bool mark_permanent_failed(
const std::string &id,
const std::string &error,
std::int64_t now_ms
) override;
std::size_t requeue_inflight_older_than(
std::int64_t now_ms,
std::int64_t timeout_ms
) override;
};Configuration
| Field | Purpose |
|---|---|
file_path | JSON file used to persist operations. |
pretty_json | Writes formatted JSON for easier inspection. |
fsync_on_write | Durability policy option carried by the store config. |
Example
auto store = std::make_shared<vix::sync::outbox::FileOutboxStore>(
vix::sync::outbox::FileOutboxStore::Config{
.file_path = "./.vix/outbox.json",
.pretty_json = true
}
);vix::sync::outbox::Outbox
Outbox is the high-level durable queue used by application code and sync workers.
class Outbox
{
public:
struct Config
{
std::string owner{"vix-sync"};
RetryPolicy retry{};
bool auto_generate_ids{true};
bool auto_generate_idempotency_key{true};
};
Outbox(Config cfg, std::shared_ptr<OutboxStore> store);
std::string enqueue(
vix::sync::Operation op,
std::int64_t now_ms
);
std::vector<vix::sync::Operation> peek_ready(
std::int64_t now_ms,
std::size_t limit = 50
);
bool claim(
const std::string &id,
std::int64_t now_ms
);
bool complete(
const std::string &id,
std::int64_t now_ms
);
bool fail(
const std::string &id,
const std::string &error,
std::int64_t now_ms,
bool retryable = true
);
std::shared_ptr<OutboxStore> store() const noexcept;
const Config &config() const noexcept;
};Configuration
| Field | Purpose |
|---|---|
owner | Logical owner used when claiming operations. |
retry | Retry policy used for retryable failures. |
auto_generate_ids | Generates an operation id when Operation::id is empty. |
auto_generate_idempotency_key | Generates an idempotency key when missing. |
Methods
| Method | Purpose |
|---|---|
enqueue | Persists an operation and returns its id. |
peek_ready | Returns operations ready for processing without claiming them. |
claim | Claims an operation using the configured owner. |
complete | Marks an operation as done. |
fail | Records a retryable or permanent failure. |
store | Returns the underlying store. |
config | Returns the outbox configuration. |
Example
vix::sync::Operation op;
op.kind = "message.send";
op.target = "/api/messages";
op.payload = R"({"text":"hello"})";
const auto id = outbox.enqueue(op, now_ms);vix::sync::engine::SendResult
SendResult is returned by transports after a delivery attempt.
struct SendResult
{
bool ok{false};
bool retryable{true};
std::string error;
};| Field | Purpose |
|---|---|
ok | True when the operation was delivered successfully. |
retryable | True when a failed delivery may be retried. |
error | Diagnostic error message for failed delivery attempts. |
vix::sync::engine::ISyncTransport
ISyncTransport is the abstract delivery boundary used by workers.
class ISyncTransport
{
public:
virtual ~ISyncTransport() = default;
virtual SendResult send(
const vix::sync::Operation &op
) = 0;
};Example
class AppTransport final : public vix::sync::engine::ISyncTransport
{
public:
vix::sync::engine::SendResult
send(const vix::sync::Operation &op) override
{
return {
.ok = true,
.retryable = false,
.error = {}
};
}
};The transport owns protocol-specific delivery. The worker owns operation lifecycle updates.
vix::sync::engine::SyncWorker
SyncWorker processes ready operations from an outbox.
class SyncWorker
{
public:
struct Config
{
std::size_t batch_limit{25};
std::int64_t idle_sleep_ms{250};
std::int64_t offline_sleep_ms{500};
std::int64_t inflight_timeout_ms{10'000};
};
SyncWorker(
Config cfg,
std::shared_ptr<vix::sync::outbox::Outbox> outbox,
std::shared_ptr<vix::net::NetworkProbe> probe,
std::shared_ptr<ISyncTransport> transport
);
std::size_t tick(std::int64_t now_ms);
};Configuration
| Field | Purpose |
|---|---|
batch_limit | Maximum operations processed per tick. |
idle_sleep_ms | Timing value used by higher-level orchestration. |
offline_sleep_ms | Offline timing value carried by worker configuration. |
inflight_timeout_ms | Timeout for requeueing old in-flight operations. |
Method
std::size_t tick(std::int64_t now_ms);Processes a batch of ready operations for the given time. The method returns a best-effort count of processed operations.
During a tick, the worker can requeue old in-flight operations, check network availability through NetworkProbe, claim ready operations, send them through the transport, and update the outbox.
vix::sync::engine::SyncEngine
SyncEngine coordinates one or more sync workers.
class SyncEngine
{
public:
struct Config
{
std::size_t worker_count{1};
std::int64_t idle_sleep_ms{250};
std::int64_t offline_sleep_ms{500};
std::size_t batch_limit{25};
std::int64_t inflight_timeout_ms{10'000};
};
SyncEngine(
Config cfg,
std::shared_ptr<vix::sync::outbox::Outbox> outbox,
std::shared_ptr<vix::net::NetworkProbe> probe,
std::shared_ptr<ISyncTransport> transport
);
~SyncEngine();
std::size_t tick(std::int64_t now_ms);
void start();
void stop();
bool running() const noexcept;
};Configuration
| Field | Purpose |
|---|---|
worker_count | Number of worker instances created by the engine. |
idle_sleep_ms | Sleep duration when the background loop is idle. |
offline_sleep_ms | Offline timing value propagated to worker configuration. |
batch_limit | Maximum operations pulled per worker batch. |
inflight_timeout_ms | Timeout for requeueing old in-flight operations. |
Methods
std::size_t tick(std::int64_t now_ms);Runs one engine iteration and returns the number of operations processed by workers.
void start();Starts the internal background loop. Calling start() while already running has no effect.
void stop();Stops the background loop and joins the engine thread. Calling stop() while not running has no effect.
bool running() const noexcept;Returns whether the engine background loop is currently running.
Example
vix::sync::engine::SyncEngine engine(
vix::sync::engine::SyncEngine::Config{
.worker_count = 1,
.batch_limit = 10
},
outbox,
probe,
transport
);
const auto processed = engine.tick(now_ms);vix::sync::wal::RecordType
RecordType identifies the kind of record stored in the write-ahead log.
enum class RecordType : std::uint8_t
{
PutOperation = 1,
MarkDone = 2,
MarkFailed = 3,
};| Value | Meaning |
|---|---|
PutOperation | A new operation was added. |
MarkDone | An operation completed successfully. |
MarkFailed | An operation failed and may include retry information. |
vix::sync::wal::WalRecord
WalRecord is a single append-only record in the WAL.
struct WalRecord
{
std::string id;
RecordType type{RecordType::PutOperation};
std::int64_t ts_ms{0};
std::vector<std::uint8_t> payload;
std::string error;
std::int64_t next_retry_at_ms{0};
};| Field | Purpose |
|---|---|
id | Identifier of the affected operation. |
type | WAL record type. |
ts_ms | Record timestamp in milliseconds. |
payload | Opaque payload bytes. |
error | Optional error message for failure records. |
next_retry_at_ms | Retry timestamp used by failure records. |
vix::sync::wal::WalWriter
WalWriter appends records to a WAL file.
class WalWriter
{
public:
struct Config
{
std::filesystem::path file_path;
bool fsync_on_write{false};
};
explicit WalWriter(Config cfg);
~WalWriter();
std::int64_t append(const WalRecord &rec);
void flush();
};Methods
| Method | Purpose |
|---|---|
append | Appends a record and returns its file offset. |
flush | Flushes buffered output. |
Example
vix::sync::wal::WalWriter writer(
vix::sync::wal::WalWriter::Config{
.file_path = "./.vix/wal.log"
}
);
vix::sync::wal::WalRecord rec;
rec.id = "op-1";
rec.type = vix::sync::wal::RecordType::PutOperation;
const auto offset = writer.append(rec);vix::sync::wal::WalReader
WalReader reads WAL records sequentially.
class WalReader
{
public:
explicit WalReader(std::filesystem::path file_path);
void seek(std::int64_t offset);
std::optional<WalRecord> next();
std::int64_t current_offset() const noexcept;
};Methods
| Method | Purpose |
|---|---|
seek | Moves the reader to a byte offset in the WAL file. |
next | Reads the next record, or returns std::nullopt. |
current_offset | Returns the current reader offset. |
Example
vix::sync::wal::WalReader reader("./.vix/wal.log");
reader.seek(0);
while (auto rec = reader.next())
{
vix::print("record", rec->id);
}vix::sync::wal::Wal
Wal is a convenience wrapper around WalWriter and WalReader.
class Wal
{
public:
struct Config
{
std::filesystem::path file_path{"./.vix/wal.log"};
bool fsync_on_write{false};
};
explicit Wal(Config cfg);
std::int64_t append(const WalRecord &rec);
std::int64_t replay(
std::int64_t from_offset,
const std::function<void(const WalRecord &)> &on_record
);
};Methods
| Method | Purpose |
|---|---|
append | Appends one record and returns the record offset. |
replay | Reads records from an offset and calls a callback for each one. |
Example
vix::sync::wal::Wal wal(
vix::sync::wal::Wal::Config{
.file_path = "./.vix/wal.log"
}
);
wal.replay(
0,
[](const vix::sync::wal::WalRecord &rec) {
vix::print("replayed", rec.id);
}
);Direct headers
For most application code, prefer:
#include <vix/sync.hpp>Direct headers are available when a file intentionally depends on a narrower part of the module.
<vix/sync/Operation.hpp>
<vix/sync/RetryPolicy.hpp>
<vix/sync/engine/SyncEngine.hpp>
<vix/sync/engine/SyncWorker.hpp>
<vix/sync/outbox/Outbox.hpp>
<vix/sync/outbox/OutboxStore.hpp>
<vix/sync/outbox/FileOutboxStore.hpp>
<vix/sync/wal/Wal.hpp>
<vix/sync/wal/WalReader.hpp>
<vix/sync/wal/WalRecord.hpp>
<vix/sync/wal/WalWriter.hpp>Link target
Link the module with:
target_link_libraries(my_app
PRIVATE
vix::sync
)Use PUBLIC only when your public headers expose sync types.
Summary
The sync API is centered on a small set of durable synchronization concepts. Operation describes the work, Outbox persists and coordinates it, OutboxStore provides the storage contract, ISyncTransport performs delivery, and SyncEngine drives workers over time. The WAL types provide a lower-level append-only log for custom recovery designs.
For normal application code, include <vix/sync.hpp>, create an outbox with a store, provide a transport, and let the engine process operations with tick() or start().