This guide consolidates the foundational durability work in Bedrock:
- durability profile contract and runtime enforcement modes;
- S3-compatible object storage backend semantics;
- non-blocking shard persistence with explicit durability watermarking;
- WAL trim safety boundaries and recovery behavior;
- telemetry and test gates for operators and maintainers.
The current foundation covers:
- Additive durability profile API:
Bedrock.Durability.profile/1Bedrock.Durability.require/2
- Additive runtime durability mode:
:relaxed(warn + continue):strict(fail startup on profile failures)
- S3-compatible
Bedrock.ObjectStorage.S3backend:- CRUD/list operations
- native conditional semantics (
If-None-Match,If-Match)
- Bounded async persistence queue/worker in Demux shard flow.
- Durable watermark progression only after confirmed object-store writes.
- WAL trimming gated by confirmed monotonic durable watermark.
- Fail-fast corruption handling during object-backed replay.
- WAL commit acknowledgment only after append + fsync on required log replicas.
Demux.Server.push/3routes shard slices without blocking on object-store I/O.- Each
ShardServerenqueues flush batches toPersistenceWorker. - Worker writes chunk objects to object storage.
ShardServeradvances its durable watermark only after confirmed write.Demux.Servercomputes clustermin_durable_version.- Log WAL trimming advances only behind that confirmed minimum boundary.
This preserves hot-path responsiveness while keeping durability and trim behavior explicit and monotonic.
WAL commit ACK semantics are independent from async object persistence:
- transaction commit ACK is gated by log WAL append + fsync;
- object persistence and watermark advancement happen asynchronously afterward;
- WAL trimming remains gated by confirmed durable watermark progression.
Profile checks validate:
- minimum replication parameters (
desired_replication_factor,desired_logs); - persistent coordinator configuration;
- persistent path configuration for coordinator, log, and materializer roles.
Configuration is additive. Runtime default mode is :strict.
Explicit relaxed override for development or single-node rollout:
config :bedrock, MyCluster,
durability_mode: :relaxed,
durability: [
desired_replication_factor: 3,
desired_logs: 3
]Strict mode (default) fails fast when requirements are not met:
config :bedrock, MyCluster,
durability_mode: :strictUse :relaxed only when intentionally accepting profile warnings during staged
rollout.
Use S3 as the Bedrock object store via normalized backend config:
config :bedrock, Bedrock.ObjectStorage,
backend: :s3,
s3: [
bucket: "bedrock",
access_key_id: "minio_key",
secret_access_key: "minio_secret",
scheme: "http://",
region: "local",
host: "127.0.0.1",
port: 9000
]Conditional semantics:
put_if_not_exists/4returns{:error, :already_exists}when the key exists.get_with_version/2returns opaque version tokens from object metadata.put_if_version_matches/5returns{:error, :version_mismatch}on stale tokens.
These are validated in MinIO-backed :s3 tests.
Durability profile:
[:bedrock, :durability, :profile, :ok][:bedrock, :durability, :profile, :failed]
Persistence queue/backpressure:
[:bedrock, :demux, :persistence_queue, :enqueue][:bedrock, :demux, :persistence_queue, :dequeue][:bedrock, :demux, :persistence_queue, :backpressure][:bedrock, :demux, :persistence_queue, :retry_scheduled][:bedrock, :demux, :persistence_queue, :retry_dropped]
Persistence outcomes:
[:bedrock, :demux, :persistence, :write, :ok][:bedrock, :demux, :persistence, :write, :error][:bedrock, :demux, :persistence, :watermark, :advanced]
Run default suite (without S3/distributed tags):
mix testRun MinIO-backed S3 integration coverage:
mix test --include s3 --exclude distributedRun distributed durability suite:
BEDROCK_INCLUDE_DISTRIBUTED=1 mix test --include distributed test/bedrock/distributed/minio_durability_test.exs- Local filesystem remains the default object storage backend.
- S3 migration is additive: enable backend config without removing existing LocalFilesystem paths until cutover is validated.
- Runtime default is
:strict; under-provisioned profiles fail startup unlessdurability_mode: :relaxedis set explicitly. - Use explicit
:relaxedonly for staged rollout, then remove it once profile and durability gates are consistently passing. - Keep WAL trim and durability telemetry on dashboards during the transition.
- MinIO is the current primary S3 validation target; AWS S3 parity hardening is a follow-on track.
- Distributed durability coverage currently focuses on foundational scenarios (restart, transient partition/retry).
- Recovery corruption handling is fail-fast by design; operational runbooks should include explicit remediation for damaged objects.