WAL Canary Runbook
This runbook defines a safe rollout process for enabling WAL on production indexes.
Scope:
- WAL is opt-in per index through the grouped
wal(...)builder section. - Default remains disabled (
IndexWalConfiguration.EMPTY). - One WAL lives inside each index directory (
<index>/wal).
Goals
- Enable WAL on a small subset of indexes first.
- Detect durability/performance regressions early.
- Roll back quickly to
IndexWalConfiguration.EMPTYwhen risk signals appear.
Preconditions
- Current backup/restore flow is verified for the target index set.
wal-toolsdistribution is available for verification:
Concrete example:
VERSION=1.2.3
RELEASE_DIR=/srv/releases/hestiastore
WAL_TOOLS_DIR=/opt/hestia/wal-tools
cd "$RELEASE_DIR"
sha256sum -c "wal-tools-${VERSION}.zip.sha256"
unzip -o "wal-tools-${VERSION}.zip" -d "$WAL_TOOLS_DIR"
- Monitoring is collecting
SegmentIndex.runtimeMonitoring().snapshot().wal()fields. - Target indexes for canary are chosen (low business criticality first).
Canary Plan
Phase 0 - Baseline (WAL disabled)
Duration: 24h minimum on target indexes.
Collect baseline:
- write latency
wal().pendingSyncBytes()(should be 0 when disabled)wal().syncAverageNanos()(should be 0 when disabled)- index throughput
Phase 1 - Enable WAL on canary indexes only
Use explicit WAL config:
IndexConfiguration<String, String> conf = IndexConfiguration
.<String, String>builder()
.identity(identity -> identity
.name("orders-canary")
.keyClass(String.class)
.valueClass(String.class))
.wal(wal -> wal
.durability(WalDurabilityMode.GROUP_SYNC)
.segmentSizeBytes(64L * 1024L * 1024L)
.groupSyncDelayMillis(5)
.groupSyncMaxBatchBytes(1024 * 1024)
.maxBytesBeforeForcedCheckpoint(512L * 1024L * 1024L)
.corruptionPolicy(WalCorruptionPolicy.TRUNCATE_INVALID_TAIL))
.build();
Open/create the canary index with this config.
Phase 2 - Verify WAL health during rollout
Run WAL verification during rollout windows:
/opt/hestia/wal-tools/bin/wal_verify /path/to/index/wal
/opt/hestia/wal-tools/bin/wal_verify /path/to/index/wal --json
Concrete example:
WAL_VERIFY=/opt/hestia/wal-tools/bin/wal_verify
CANARY_WAL=/srv/hestia/indexes/orders-canary/wal
"$WAL_VERIFY" "$CANARY_WAL"
"$WAL_VERIFY" "$CANARY_WAL" --json
If verification fails (exit code 2), stop rollout and execute rollback.
Use dump for diagnostics:
Concrete example:
Phase 3 - Expand rollout
Expand only if canary passes acceptance criteria for at least 24h.
Recommended expansion:
- 5% of indexes
- 25% of indexes
- 100% of eligible indexes
Pause one full observation window between stages.
Alert Thresholds
Use these as initial operational thresholds (tune by workload).
| Signal | Warning | Rollback Trigger |
|---|---|---|
wal().syncFailureCount() |
any increase | immediate rollback |
wal().corruptionCount() |
any increase | immediate rollback |
wal().truncationCount() |
any increase outside planned restart | immediate rollback |
wal().retainedBytes() |
> 80% of maxBytesBeforeForcedCheckpoint for 10m |
> 100% for 10m |
wal().checkpointLagLsn() |
continuously increasing for 10m | increasing for 30m with no stabilization |
wal().pendingSyncBytes() |
sustained growth for 10m | sustained growth for 30m |
wal().syncAverageNanos() |
> 2x baseline for 15m | > 4x baseline for 15m |
Critical signals (sync failure, corruption, unexpected truncation) are fail-fast.
Rollback Procedure (to IndexWalConfiguration.EMPTY)
- Stop traffic to affected canary indexes (or switch to read-only).
- Take a filesystem backup/snapshot of affected index directories.
- Reopen indexes with WAL disabled override:
IndexConfiguration<String, String> rollbackConf = IndexConfiguration
.<String, String>builder()
.identity(identity -> identity
.name("orders-canary")
.keyClass(String.class)
.valueClass(String.class))
.wal(wal -> wal.disabled())
.build();
try (SegmentIndex<String, String> index = SegmentIndex.open(directory, rollbackConf)) {
index.maintenance().flushAndWait();
}
- Run integrity checks:
index.maintenance().checkAndRepairConsistency()- point-read spot checks on business keys
- Keep
wal/files for incident forensics until postmortem is complete. - Resume traffic only after checks pass.
Canary Acceptance Criteria
Promote to next stage only when all are true:
- No increase in
wal().syncFailureCount(). - No increase in
wal().corruptionCount(). - No unexpected
wal().truncationCount()increments. wal().retainedBytes()remains below forced-checkpoint threshold with headroom.- Write latency SLO remains within agreed variance from baseline.
Incident Data to Capture
For any rollback-triggering event, capture:
wal_verify --jsonoutputwal_dump --jsonoutput around the failing segment- index runtime metrics snapshot around the event window
- precise software version and commit hash