Evented KV store with version history, rollback, DSL, and rule-driven state transitions.
This project is licensed under the Apache License 2.0.
Timeline. Diff. Rollback. Auto-transition.
Website · Docs · Contact me with Gmail
- Added a separated
dashboard/frontend (React + Vite) with Docker-style layout. - Added pages:
Connection,Workbench,Data Explorer,Metrics,Import / Export. - Data Explorer timeline now shows
old_valuefor rollback inspection. - Metrics page now supports compact per-metric mini charts and wildcard metric selectors:
*cpu,*mem,*io,*lat,*heap_alloc_bytes,*gc_pause_total_ms.
- Added backend runtime metrics for observability:
- CPU:
cpu_percent,cpu_cores_used - Memory:
memory_alloc_mb,memory_inuse_mb,memory_sys_mb,memory_heap_usage_percent - IO:
io_read_ops_per_sec,io_write_ops_per_sec,io_write_bytes_per_sec,io_write_mb_per_sec - Avg latency:
get_avg_ms,set_avg_ms,append_avg_ms,timeline_avg_ms
- CPU:
- Security hardening for frontend-backend connectivity:
- Removed WS query token auth (
?token=); switched to WS first-frameauth. - Session token storage changed from
localStoragetosessionStoragewith expiry cleanup. - CORS changed to allowlist mode (
localhost:5173,127.0.0.1:5173, plusANHEBRIDGE_CORS_ORIGINS). - Import/Export page adds file type/size checks, confirmation, and duplicate-submit guard.
- Removed WS query token auth (
- Email: realpaerpang@gmail.com
- GitHub: https://github.com/paerx
AnheBridgeDB v1 covers the current MVP path described in docs/:
- append-only segmented event log with compact per-event HMAC auth tag
- WAL + CRC-protected segment records + checkpoint-based recovery
- current-state index + historical timeline reconstruction
GET key,GET key AT ts,GET key ALLTIME,GET key ALLTIME WITH DIFFROLLBACK key VERSION:nandROLLBACK key VERSION:LASTCHECK key ALLTIMEtamper tracing- DSL parser and execution endpoint
- rule engine with
CREATE RULE ... IF UNCHANGED FOR ... THEN TRANSITION - bucket-style persisted task queue and scheduler-driven auto transition
- snapshot + restart recovery for state, rules, and pending tasks
go run ./cmd/server -addr :8080 -data ./data -scheduler-interval 1sSET userBalance:0xabc 100;
SET userBalance:0xabc -10 SEND i=tx-001;
SET userBalance:0xabc 10 RECEIVED i=tx-001;
ASET balance:123 -10 SEND i=tx-002, balance:456 10 RECEIVED i=tx-002;
GET userBalance:0xabc;
AGET userBalance:0xabc balance:123 balance:456;
GET userBalance:0xabc AT '2026-03-13T10:00:00Z';
GET userBalance:0xabc LAST;
GET userBalance:0xabc LAST -1 -1;
GET userBalance:0xabc ALLTIME;
GET userBalance:0xabc ALLTIME WITH DIFF;
GET userBalance:0xabc ALLTIME LIMIT 100 BEFORE VERSION:2000 AFTER VERSION:1500;
SEARCH EVENTS KEY:userBalance:0xabc NAME:SEND DESC LIMIT:20 PAGE:1;
SEARCH EVENTS I:tx-001;
SEARCH EVENTS KEY:userBalance:0xabc NAME:SEND WITH SAME I;
ROLLBACK userBalance:0xabc VERSION:5;
ROLLBACK userBalance:0xabc VERSION:LAST;
CHECK userBalance:0xabc ALLTIME;
CHECK userBalance:0xabc ALLTIME LIMIT 1000;
SNAPSHOT;
VERIFY STORAGE;
COMPACT STORAGE;
CREATE RULE auto_timeout_order
ON PATTERN "OrderStatus:*:wait_for_paid"
IF UNCHANGED FOR 15m
THEN TRANSITION TO "OrderStatus:{id}:timeout";
SHOW RULES;
SHOW RULE auto_timeout_order;
RUN SCHEDULER;SET key value;
SET key delta EVENT;
SET key value EVENT i=business-id;
ASET key value, key value EVENT, key value EVENT i=business-id;
DELETE key;GET key;
GET key RAW;
GET key EXPAND ONLY /checkin,/owner,/rewards;
GET key EXPAND EXCEPT /chests;
AGET key1 key2 key3;
AGET key1 key2 key3 RAW;
AGET key1 key2 key3 EXPAND ONLY /checkin;
GET key AT '2026-03-15T04:00:00Z';
GET key AT '2026-03-15T04:00:00Z' EXPAND ONLY /checkin;
GET key LAST;
GET key LAST EXPAND EXCEPT /chests;
GET key LAST -1 -1;
GET key ALLTIME;
GET key ALLTIME WITH DIFF;
GET key ALLTIME LIMIT 100 BEFORE VERSION:10 AFTER VERSION:5;super value means a string that starts with * and points to another key.
Example:
SET uid-hksn10 {"uid":"uid-hksn10","owner":"0xabc","activated":true};
SET uid-asan10 {"uid":"uid-asan10","owner":"0xdef","activated":false};
SET usersVape ["*uid-hksn10","*uid-asan10"];
GET usersVape;
GET usersVape RAW;
GET usersVape EXPAND ONLY /0;
GET usersVape EXPAND EXCEPT /1;
AGET usersVape uid-hksn10 RAW;Behavior:
GET/AGETexpands super values by default.GET RAWandAGET ... RAWreturn stored raw value without expansion.EXPAND ONLYresolves only the listed JSON Pointer paths; every other*keyremains unchanged and is not read.EXPAND EXCEPTresolves all super values except the listed paths.- multiple paths are comma-separated, for example
EXPAND ONLY /checkin,/owner,/rewards. - array indexes and wildcards are supported, for example
/chests/0and/chests/*. - expansion is read-only: no write-through to referenced keys.
- circular references are rejected with
super_value_cycle_detected. - depth/node/fanout are bounded by performance config.
- missing referenced key is returned as
found=falseentry, not a server crash.
SEARCH EVENTS KEY:balance:1234 NAME:SEND;
SEARCH EVENTS KEY:balance:1234 NAME:SEND DESC LIMIT:20 PAGE:1;
SEARCH EVENTS I:abcd;
SEARCH EVENTS KEY:balance:1234 NAME:SEND WITH SAME I;Search behavior:
NAME:filters by event name using the secondary event-name indexI:filters byidempotency_keyWITH SAME Iexpands the matched result set to every event that shares the same business idempotency keyPAGE:nperforms direct page slicing on the indexed result set
ROLLBACK key VERSION:5;
ROLLBACK key VERSION:LAST;
CHECK key ALLTIME;
CHECK key ALLTIME LIMIT 1000;
SNAPSHOT;
VERIFY STORAGE;
COMPACT STORAGE;CREATE RULE auto_timeout_order
ON PATTERN "OrderStatus:*:wait_for_paid"
IF UNCHANGED FOR 15m
THEN TRANSITION TO "OrderStatus:{id}:timeout";
SHOW RULES;
SHOW RULE auto_timeout_order;
RUN SCHEDULER;Segment rolling is configurable in config.json:
{
"auth": {
"enabled": false,
"token_ttl_minutes": 1440,
"users": [
{
"username": "admin",
"password": "change-me"
}
]
},
"storage": {
"strict_recovery": false,
"segment": {
"max_bytes": 67108864,
"max_records": 30000
}
}
}Both thresholds can be enabled together. A segment rolls when either limit is exceeded.
Automatic backup is opt-in and disabled by default. When enabled, the server rotates the active segment at a durable event boundary and runs backup work in background goroutines. Normal GET/SET/ASET processing does not wait for R2 upload, Lark, or health inspection.
incremental is the recommended mode. It runs every two hours, uploads each immutable event segment only once using a content-addressed R2 object key, saves mutable rule/task/checkpoint files for the current backup, then atomically advances incremental/latest.json. A failed run never replaces the last valid restore pointer.
{
"backup": {
"enabled": true,
"mode": "incremental",
"run_on_start": true,
"interval_seconds": 7200,
"timeout_seconds": 7200,
"spool_dir": "./data/backups",
"keep_local": true,
"local_retention_count": 3,
"upload": {
"enabled": true,
"endpoint": "https://<account-id>.r2.cloudflarestorage.com",
"bucket": "anhe-backups",
"prefix": "production",
"access_key_env": "ANHEBRIDGE_R2_ACCESS_KEY_ID",
"secret_access_key_env": "ANHEBRIDGE_R2_SECRET_ACCESS_KEY",
"max_object_bytes": 5368709120,
"retry_count": 3,
"retry_backoff_ms": 1000
},
"lark": {
"enabled": true,
"webhook_env": "ANHEBRIDGE_LARK_WEBHOOK",
"secret_env": "ANHEBRIDGE_LARK_SECRET",
"notify_success": true
},
"monitor": {
"enabled": true,
"interval_seconds": 60,
"verify_interval_seconds": 86400,
"consecutive_breaches": 3,
"alert_cooldown_seconds": 1800,
"heap_alloc_max_bytes": 8589934592,
"pending_tasks_max": 100000,
"overdue_tasks_max": 1000,
"write_queue_max": 800,
"append_p95_max_ms": 100,
"get_p95_max_ms": 50
}
}
}Secrets are read from environment variables and are never persisted in the backup:
export ANHEBRIDGE_R2_ACCESS_KEY_ID='...'
export ANHEBRIDGE_R2_SECRET_ACCESS_KEY='...'
export ANHEBRIDGE_LARK_WEBHOOK='https://open.feishu.cn/open-apis/bot/v2/hook/...'
export ANHEBRIDGE_LARK_SECRET='...'Threshold value 0 disables that individual alert. Alerts require consecutive_breaches consecutive samples and use alert_cooldown_seconds to prevent notification storms. Full HMAC-chain verification runs separately at verify_interval_seconds; set it to 0 to disable deep verification.
Incremental R2 layout:
incremental/objects/<sha-prefix>/<sha256>.anhe: immutable segment objects shared by backup generationsincremental/backups/<backup-id>/files/...: mutable metadata captured for one generationincremental/manifests/<backup-id>.json: HMAC-signed restore manifest with size and SHA-256 for every fileincremental/latest.json: HMAC-signed pointer updated only after all files and the manifest are durable
The local incremental-state.json avoids hashing stable segments on every run. If it is lost, content-addressed R2 HEAD checks prevent already uploaded segment bodies from being uploaded again.
Archive compaction output is capped at 4 GiB and already compacted archives are not merged again, keeping each incremental object below the default 5 GiB single-upload ceiling.
If mode is full, or R2 upload is disabled, the existing local .tar.gz full-backup path remains available.
Stop the database process before restoring. Restore defaults to the latest completed incremental backup:
go run ./cmd/restore \
-config ./config/config.json \
-data ./data-restored \
-manifest latest \
-workers 4Restore a specific generation by using the manifest object key printed in backup logs:
go run ./cmd/restore \
-config ./config/config.json \
-data ./data-restored \
-manifest 'production/incremental/manifests/20260729T120000.000000000Z-e12345.json'The restore command:
- downloads into a sibling staging directory
- rejects absolute or parent-traversal paths
- verifies every object size and SHA-256
- rebuilds position and latest-key indexes
- opens the staged database with strict HMAC recovery by default
- atomically renames the staged directory into place only after validation
The target must be empty unless -force is passed. With -force, the existing directory is preserved as <data>.pre-restore-<UTC> rather than deleted. Set the same ANHEBRIDGE_HMAC_KEY used by the source database before running verified restore.
The Docker image also includes /usr/local/bin/anhe-restore. Run it from a one-off container with the database service stopped and the data/config volumes mounted; the normal image entrypoint remains anhe-server.
The archive intentionally rebuilds volatile indexes during import rather than copying indexes while they are changing. An R2 or Lark configuration error does not terminate the database; local backup remains active and the failure is recorded in logs and metrics.
To enable auth for dashboard and CLI, set:
{
"auth": {
"enabled": true,
"token_ttl_minutes": 1440,
"users": [
{
"username": "admin",
"password": "change-me"
}
]
}
}You can also set ANHEBRIDGE_AUTH_SECRET in the environment to override the token signing secret.
Performance controls:
{
"performance": {
"event_cache_max_items": 50000,
"event_cache_max_bytes": 134217728,
"key_index_compact_ops": 10000,
"scheduler_workers": 4,
"metrics_sample_interval_seconds": 10,
"snapshot_batch_size": 10000,
"timeline_default_limit": 1000,
"super_value_max_depth": 5,
"super_value_max_fanout": 200,
"super_value_max_nodes": 1000
}
}metrics_sample_interval_seconds is clamped to >= 10s so metrics history sampling stays off the hot path.
Client:
go run ./cmd/client -addr http://127.0.0.1:8080CLI login:
anhe> login
username: admin
password: change-me
The CLI stores the bearer token in ~/.anhebridge_cli_auth.json and automatically attaches it to future requests for the same server address.
Single command:
go run ./cmd/client -addr http://127.0.0.1:8080 -e 'GET user:1 ALLTIME WITH DIFF;'Pipe input:
printf 'SHOW RULES;\n' | go run ./cmd/client -addr http://127.0.0.1:8080Stress test:
go run ./cmd/stress -addr http://127.0.0.1:8080 -mode rw -duration 60s -workers 16 -batch 64 -keys 20000
go run ./cmd/stress -addr http://127.0.0.1:8080 -mode orders -orders 20000 -order-batch 200 -workers 8 -rule-delay 15s
go run ./cmd/stress -addr http://127.0.0.1:8080 -mode mixed -duration 90s -workers 16 -orders 10000For an M4 / 16GB machine, a practical starting point is:
go run ./cmd/server -addr :8080 -data ./data -scheduler-interval 500ms
go run ./cmd/stress -addr http://127.0.0.1:8080 -mode mixed -duration 120s -workers 16 -batch 128 -keys 50000 -orders 20000 -order-batch 200 -rule-delay 15sWhen auth is enabled, all endpoints except /healthz and /auth/login require:
-H 'Authorization: Bearer <token>'Login:
curl -X POST http://localhost:8080/auth/login \
-H 'Content-Type: application/json' \
-d '{"username":"admin","password":"change-me"}'Write:
curl -X PUT http://localhost:8080/kv/user:1 \
-H 'Content-Type: application/json' \
-d '{"name":"tom","state":"active"}'Read latest:
curl http://localhost:8080/kv/user:1Read at time:
curl 'http://localhost:8080/kv/user:1?time=2026-03-14T03:00:00Z'Timeline:
curl http://localhost:8080/kv/user:1/timelineTimeline with diff:
curl 'http://localhost:8080/kv/user:1/timeline?diff=true'Timeline window:
curl 'http://localhost:8080/kv/user:1/timeline?limit=100&before_version=2000&after_version=1500'Delete:
curl -X DELETE http://localhost:8080/kv/user:1Create snapshot:
curl -X POST http://localhost:8080/snapshotStats:
curl http://localhost:8080/statsMetrics:
curl http://localhost:8080/metricsMetrics history OHLC:
curl "http://localhost:8080/metrics/history?metrics=heap_alloc_bytes,pending_tasks&from=2026-03-15T12:00:00Z&to=2026-03-15T13:00:00Z&bucket=1m"Debug perf:
curl http://localhost:8080/debug/perfVerify storage:
curl -X POST http://localhost:8080/admin/verifyCompact storage:
curl -X POST http://localhost:8080/admin/compactExport full backup tarball:
curl http://localhost:8080/admin/export?scope=full -o anhebridgedb-full.tar.gzExport selected segments tarball:
curl "http://localhost:8080/admin/export?scope=segments&segments=segment_000001.anhe,segment_900001.anhe" -o anhebridgedb-segments.tar.gzImport backup tarball:
curl -X POST "http://localhost:8080/admin/import?scope=full" \
-H 'Content-Type: application/gzip' \
--data-binary @anhebridgedb-full.tar.gzImport selected segments tarball:
curl -X POST "http://localhost:8080/admin/import?scope=segments" \
-H 'Content-Type: application/gzip' \
--data-binary @anhebridgedb-segments.tar.gzWebSocket:
ws://localhost:8080/ws?token=<bearer-token>
Example messages:
{"type":"exec","request_id":"1","query":"SHOW METRICS;"}
{"type":"subscribe","topic":"metrics","interval_seconds":10}
{"type":"subscribe","topic":"stats","interval_seconds":30}
{"type":"unsubscribe","topic":"metrics"}
{"type":"ping"}Create rule:
curl -X POST http://localhost:8080/rules \
-H 'Content-Type: application/json' \
-d '{
"id":"auto_timeout_order",
"pattern":"OrderStatus:*:wait_for_paid",
"delay":"15m",
"target":"OrderStatus:{id}:timeout"
}'Execute DSL:
curl -X POST http://localhost:8080/dsl \
-H 'Content-Type: application/json' \
-d '{
"query":"SET OrderStatus:123 {\"state\":\"wait_for_paid\",\"amount\":100}; GET OrderStatus:123 ALLTIME WITH DIFF;"
}'data/
log/segment_000001.anhe
log/segment_000002.anhe
log/segment_000001.manifest.json
log/segment_000002.manifest.json
log/events.wal
log/checkpoint.json
log/archive/segment_000001.anhe
log/archive/segment_000001.manifest.json
log/archive/archive.manifest.json
log/archive/segment_900001.anhe
log/archive/segment_900001.manifest.json
index/positions.anhe
index/latest.snapshot.anhe
index/latest.delta.anhe
snapshot/latest.json
system/rules.json
system/task_buckets/202603140445.anhe
system/task_buckets/202603140446.anhe
AnheBridgeDB stores data as an append-only event stream plus a small set of persisted indexes:
log/segment_xxxxxx.anhe- append-only event segments
- each event record is wrapped with CRC32
- each event stores
event_id,key,operation,old_value,new_value,prev_version_offset, compactauth_tag, and metadata
log/segment_xxxxxx.manifest.json- per-segment manifest
- stores segment-level counters, time range, event-id range, first/last auth tags, and rolling manifest auth
log/events.wal- write-ahead log for crash recovery before segment/index/manifest flush completes
log/checkpoint.json- stores
next_id,current_segment, and latest auth-chain head
- stores
log/archive/- cold segments moved out of the active write path while remaining readable for history queries
- archive compaction can merge many cold segments into a compacted archive segment
archive.manifest.jsonrecords archived and compacted segment lineage
index/positions.anhe- persistent position index
- maps
event_id -> segment + file offset + size
index/latest.snapshot.anhe+index/latest.delta.anhe- compact snapshot plus append-only delta log
- maps
key -> latest_event
snapshot/latest.json- full state snapshot for restart recovery
system/rules.json- rule definitions and counters
system/task_buckets/*.anhe- minute-bucket task files for delayed transitions
flowchart LR
A["DSL / HTTP Write"] --> B["Lock Key Shard"]
B --> C["Build Event"]
C --> D["Write WAL"]
D --> E["Append To Segment"]
E --> F["Append Position Index"]
F --> G["Update Manifest + Checkpoint"]
G --> H["Clear WAL"]
H --> I["Update latest index In Memory"]
I --> J["Apply Current State"]
J --> K["Rule Match"]
K --> L["Persist Task Bucket If Needed"]
flowchart LR
A["Load Snapshot"] --> B["Load Rules"]
B --> C["Load Task Bucket Metadata"]
C --> D["Load positions.anhe"]
D --> E["Load latest snapshot + delta"]
E --> F["Replay WAL If Needed"]
F --> G["Replay Only Events After snapshot.LastEventID"]
G --> H["Warm Bounded Event Cache On Demand"]
flowchart LR
A["Snapshot Establishes Safe Cutoff"] --> B["Archive Cold Active Segments"]
B --> C["Load Archived Segment Manifests"]
C --> D["Merge Archived Events Into Compacted Archive Segment"]
D --> E["Rewrite positions.anhe To New Segment Offsets"]
E --> F["Write Compacted Archive Manifest"]
F --> G["Update archive.manifest.json"]
G --> H["Remove Old Archived Segment Files"]
The runtime uses sharded key locks instead of a single global KV lock:
- the same key is always serialized
- different keys can be read and written in parallel
- batch operations lock involved key shards in sorted order to avoid deadlocks
- event log append is serialized internally so
event_idordering stays stable - metadata persistence such as latest-index delta flush is serialized separately
flowchart LR
A["Request For Key"] --> B["Hash Key To Shard"]
B --> C["Acquire Shard Lock"]
C --> D["Read / Write State"]
D --> E["Persist Event Or Read Result"]
E --> F["Release Shard Lock"]
The rule engine is designed around version checks, not blind timers.
- each scheduled task stores:
entity_keyexpected_versionexpected_statecause_event_id
- when the scheduler executes a task, it first validates that the current record still matches the captured version and state
- if the key has changed since task creation, the task is marked
skipped - if the key is unchanged, a new
AUTO_TRANSITIONevent is appended
This makes delayed transitions naturally idempotent at the state-machine level.
Each event is written with:
auth_tag- compact HMAC-SHA256 tag
- calculated from the current event payload plus the previous global event's
auth_tag
This forms a chained HMAC proof with only one extra field per event. If someone edits an old event directly on disk without the signing secret, CHECK key ALLTIME will surface the mismatch.
CRC adds a second protection layer:
- direct record corruption or partial writes are detected before event decoding
- strict recovery mode can refuse startup on CRC / manifest / auth-chain mismatch
Segment manifests add another verification layer:
- first / last event id
- first / last
auth_tag - record count
- rolling
manifest_auth
flowchart LR
A["CHECK key ALLTIME"] --> B["Walk Key Version Chain"]
B --> C["Recompute auth_tag With Previous Global auth_tag"]
C --> D["Compare Stored auth_tag"]
D --> E["Validate Related Segment Manifest"]
E --> F["Return Issues Or OK"]
flowchart LR
A["Pending Task"] --> B["Load Current Record"]
B --> C{"Version / State Match?"}
C -- "No" --> D["Mark Skipped"]
C -- "Yes" --> E["Append AUTO_TRANSITION Event"]
E --> F["Mark Done"]
Reads use different strategies depending on the query type:
GET key- returns current state directly from the in-memory state map
GET key LAST- starts from
latest_event - follows
prev_version_offset
- starts from
GET key ALLTIME- walks the same version chain until the first version
GET key AT ts- walks the per-key version chain backward until it finds the first event at or before the target timestamp
- if an event body is not already cached, it is loaded from
segment + offsetthroughpositions.anhe - event bodies live in a bounded cache instead of unbounded in-memory growth
flowchart LR
A["GET / GET LAST / GET AT / ALLTIME"] --> B["Resolve latest_event For Key"]
B --> C{"Current Value Query?"}
C -- "Yes" --> D["Return In-Memory State"]
C -- "No" --> E["Follow prev_version_offset Chain"]
E --> F["Load Event By segment + offset"]
F --> G["Return Historical Record / Timeline"]
Rollback never deletes history. It appends a new event that points back to a previous version.
ROLLBACK key VERSION:n- finds the target event
- appends a new
ROLLBACKevent - sets
new_valueto the target version's value
ROLLBACK key VERSION:LAST- resolves the previous version automatically
- then appends the same kind of rollback event
This keeps the audit trail complete and makes rollback itself queryable in timeline history.
flowchart LR
A["ROLLBACK key VERSION:n / LAST"] --> B["Resolve Target Version"]
B --> C["Build ROLLBACK Event"]
C --> D["Set old_value = Current"]
D --> E["Set new_value = Target"]
E --> F["Append Event"]
F --> G["Update Current State"]
Rules are pattern-based delayed transitions.
Example:
CREATE RULE auto_timeout_order
ON PATTERN "OrderStatus:*:wait_for_paid"
IF UNCHANGED FOR 15m
THEN TRANSITION TO "OrderStatus:{id}:timeout";Internal flow:
- a write updates a key such as
OrderStatus:123 - the rule engine extracts the current state from the event value
- if the pattern matches, it creates a delayed task in the target minute bucket
- the scheduler later loads due buckets and validates the task
- if still valid, worker threads append an
AUTO_TRANSITIONevent while same-key writes remain serialized
The server now exposes:
/stats- logical state overview
/metrics- heap usage
- GC pause totals
- event cache size and hit ratio
- get/get-at/timeline/check latency percentiles
- set/aset/append/latest-index-flush latency percentiles
- scheduler backlog and overdue task counts
- segment/index/snapshot/manifest sizes
- recovery timings
- append / latest-index flush timings
- automatic backup run/failure totals, last success time, duration, size
- automatic monitor alert totals
/debug/perf- bucket backlog detail
- segment manifests
- event cache state
- consolidated perf snapshot
/admin/verify- validates manifests
- validates chained HMAC auth tags
- surfaces storage integrity issues before they become silent corruption
/admin/compact- compacts latest index delta into snapshot
- clears old fully-terminal task buckets
- archives cold segments covered by snapshot state
/admin/export- streams a
.tar.gzbackup package - supports
scope=full - supports
scope=segments&segments=segment_000001.anhe,...
- streams a
/admin/import- imports a
.tar.gzbackup package - rebuilds
positions.anheand latest key index after import - returns
restart_required: truebecause in-memory state is not hot-reloaded
- imports a
flowchart LR
A["State Write Event"] --> B["Extract state"]
B --> C{"Rule Pattern Match?"}
C -- "No" --> D["Stop"]
C -- "Yes" --> E["Create Pending Task In Minute Bucket"]
E --> F["Scheduler Loads Due Bucket"]
F --> G{"Version / State Still Match?"}
G -- "No" --> H["Skip Task"]
G -- "Yes" --> I["Append AUTO_TRANSITION Event"]
