eleven / messenger Public

server: activator replication gets its own litestream meta directory (#729)

litestream derives .<db>-litestream beside the DB; the box-wide backup
replicator uses the same path over the same file, and sharing corrupts
LTX state even sequentially — the fleet flip left a dozen hosts in an
error loop until meta dirs were hand-cleared. SetMetaPath gives the
activator a distinct .activator-<db>-litestream namespace; the class dies.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Paul Campbell 23e538fe4e9ad369d05f93cf1ff4e56fdc246524 parent 23c3b37
1 file changed, +9 −0
  • internal/activator/replica.go +9 −0
diff --git a/internal/activator/replica.go b/internal/activator/replica.go
index cf4a1d8..29d2737 100644
--- a/internal/activator/replica.go
+++ b/internal/activator/replica.go
@@ -13,6 +13,7 @@ import (
"context"
"errors"
"fmt"
+ "path/filepath"
"sync"
"time"
@@ -156,6 +157,14 @@ func (h *HeldLease) Replicate(ctx context.Context, dbPath string) (*LeasedReplic
}
db := litestream.NewDB(dbPath)
+ // The activator's replication state lives in its OWN meta directory —
+ // litestream derives ".<db>-litestream" beside the DB by default, which any
+ // other litestream process over the same file (the box-wide backup
+ // replicator, before or after a handover) also uses. Sharing corrupts LTX
+ // state even SEQUENTIALLY: the fleet-wide flip left a dozen hosts in an
+ // error loop until their meta dirs were cleared by hand. A distinct
+ // namespace ends the class.
+ db.SetMetaPath(filepath.Join(filepath.Dir(dbPath), ".activator-"+filepath.Base(dbPath)+"-litestream"))
client := lss3.NewReplicaClient()
client.Bucket = h.leaser.Bucket
client.Path = h.leaser.Path