Event-Driven Sync
Sync S3 and R2 vaults from provider event notifications - AWS S3 to Amazon SQS and Cloudflare R2 to Cloudflare Queues - instead of scanning buckets.
Event-Driven Sync
With event-driven sync, files written to a vault's bucket by other applications (the AWS CLI, rclone, a camera upload, a backup job) reach the vault within seconds, and only the objects that changed are fetched. The provider notifies a Vaulthalla-owned queue; Vaulthalla records each event durably, updates the vault's remote index, and syncs just those keys. No bucket listing is repeated.
| Provider | Path | Needs |
|---|---|---|
| AWS S3 | bucket notification → Amazon SQS Standard queue → Vaulthalla | an administrative credential with the SQS permissions in Managed Upstream Buckets |
| Cloudflare R2 | event notification rule → Cloudflare Queue (HTTP pull) → Vaulthalla | an administrative credential with a Cloudflare API token (R2) |
No Worker, Lambda or public webhook endpoint is deployed; Vaulthalla pulls from the queue.
Turn It On
For an existing S3 vault whose credential has provider administration enabled:
1vh upstream events enable <vault>2vh upstream events enable <vault> --prefix photos/ --foreign-objects ignore3vh upstream events status <vault>
Or when creating a vault: vh vault create ... --bucket-mode create --events, or the event-sync option under the
advanced settings of New vault. For an existing vault: the vault's Settings → Event-driven sync.
Vaulthalla then:
- Creates or reuses one queue per account (AWS: per account and region,
vaulthalla-events-<region>; R2:vaulthalla-events-r2), with a dead-letter queue, message retention and a visibility timeout. On AWS it adds a queue policy statement (vaulthalla-s3-publish) that allows Amazon S3 to publish from the subscribed buckets only. On R2 it adds an HTTP pull consumer. - Adds one notification rule to the bucket for object creation, overwrite and removal (including lifecycle
expirations), named
vaulthalla-<id>. - Starts consuming the queue.
Other Applications' Rules
Bucket notification rules belong to everyone who uses the bucket. Vaulthalla reads the existing configuration, keeps
every rule that isn't vaulthalla-* exactly as it is, and on teardown removes only its own. On AWS the notification
document is replaced as a whole on every write, so Vaulthalla re-reads and merges it each time and checks the result.
If another application's rule already covers the same events and prefix, the provider rejects the overlap; Vaulthalla
reports the conflict and changes nothing. A queue that already has a Worker consumer on R2 is left alone and reported.
What Happens To An Event
- Durable first. Each event is written to the inbox in the database before its queue message is acknowledged. A crash or a database outage at any point means the message is delivered again, not lost.
- Duplicates (providers deliver at least once) are recognised and recorded once.
- Order. Events for one key are applied newest-wins: AWS sequencers when present, otherwise event time to the millisecond. A late, older event never overwrites newer state. When nothing orders a create and a removal of one key (same millisecond, no sequencer), the provider decides: one HEAD says whether the object exists.
- Targeted sync. Changed keys are applied to the vault's remote index and a sync pass runs for just those keys, under the vault's request and price budgets. A new or overwritten object costs about one HEAD and one GET; a removal costs one HEAD.
- Removals. A removal notification is only believed once a HEAD confirms the object is gone (404): a forged or
misordered notification, or a provider outage, never deletes anything; a failed HEAD is retried later. A confirmed
deletion removes the vault's file only if it is unchanged since the two sides last agreed; a file changed in the
vault meanwhile is kept and uploaded again. Under
mirrorwithkeep_local, the vault stays authoritative and deleted objects are uploaded again. - Vaulthalla's own writes. Notifications about objects Vaulthalla itself uploaded or deleted are recognised and
don't cause another transfer, including the vault's own index manifest under
.vaulthalla/. - One sync per vault at a time. Event passes and scheduled passes never overlap; events that arrive meanwhile wait, and a scheduled pass that is waiting goes first.
- Messages that can't be read are not acknowledged: after several deliveries they move to the dead-letter queue.
- Gaps. When the event stream may have lost messages (messages in the dead-letter queue, no successful poll for longer than the queue keeps messages, events that couldn't be stored before their last delivery), events alone no longer keep the vault current: they are held, the next sync pass lists the bucket once, and events older than that listing are dropped as superseded. Status shows the dead-letter queue depth.
Objects Uploaded Directly To The Bucket
Objects Vaulthalla writes carry Vaulthalla metadata (and, with upstream encryption on, are encrypted with the vault key). An object some other tool uploaded has none and is plaintext:
- With
--foreign-objects importit is imported as a vault file and sealed locally, including when it overwrites a file the vault already has. Each import into a vault that encrypts upstream is logged. This is the default for vaults that don't encrypt upstream and for adopted buckets (adoption accepted their foreign objects). - With
--foreign-objects ignore, new objects without Vaulthalla metadata are skipped (one HEAD each to tell them apart) and counted in the status, and a metadata-free object over an encrypted file is treated as below. This is the default for vaults that encrypt upstream. - Without an importing subscription, a vault that encrypts upstream treats a metadata-free object, or one relabelled
vh-encrypted: false, over one of its encrypted files as tampering: it fails authentication and the vault keeps its copy. An object that claims to be Vaulthalla-encrypted but fails authentication is never imported.
Status And Repair
1vh upstream events status2vh upstream events status <vault>
Status shows the subscription state (pending, active, failed, removing), the queue and its health (last poll,
last event, backlog, consecutive failures and the last error), and the inbox (pending, applied, failed, handled and own
writes in the last 24 hours). The same appears in the vault's Settings → Event-driven sync.
-
Queue or provider outage: Vaulthalla backs off (up to 5 minutes between polls), marks the queue
degradedafter repeated failures, and recovers by itself. Messages stay in the queue meanwhile. -
Failed provisioning (a missing permission, a conflicting rule): fix the cause, then
1vh upstream events repair <vault>Repair re-creates whatever is missing and re-arms the subscription; it is safe to run any time.
-
Missed events (a queue deleted outside Vaulthalla, retention expired): run a full reconcile, which is always available as recovery:
1vh vault sync reconcile <vault> --allow-list-scan
Turn It Off
1vh upstream events disable <vault>
This removes Vaulthalla's rule from the bucket and, when no other subscription uses it and Vaulthalla created it, the queue. Scheduled sync continues as before. Deleting a vault turns its subscription off; restoring the vault turns it back on.
Protected Buckets
Event subscriptions can't be created on protected buckets. Protecting a bucket that already has one stops all processing for it; its events stay in the inbox, unapplied.
Importing Event Files By Hand
vh vault sync events <vault> --file s3-events.json feeds saved S3 event notifications (or an SQS message dump)
through the same pipeline. Because removals can delete files, it needs what configuring events needs:
admin.upstream.configure, the vault's sync.config.edit and the right to use the vault's API key. See
Sync.
