rebuildGraph Advisory Lock
RebuildGraph() in api/internal/wiki/wiki.go uses a PostgreSQL advisory lock to serialize concurrent rebuilds across instances.
Why
A sync.Map TTL (used for lint cooldown) only prevents re-runs within a single instance. At horizontal scale, two instances could run RebuildGraph simultaneously — both listing all pages, both writing links — producing a confused link graph if either sees a partial view.
Advisory locks are DB-scoped and survive instance restarts. pg_try_advisory_lock is non-blocking: if the lock is held, the call returns false immediately rather than waiting.
Lock key
The project UUID is converted to an int64 lock key via rebuildGraphLockKey():
func rebuildGraphLockKey(projectID string) int64 {
raw := strings.ReplaceAll(projectID, "-", "")
b, _ := hex.DecodeString(raw[:16]) // first 8 bytes of the UUID
return int64(binary.BigEndian.Uint64(b))
}
Behavior
- Lock acquired → rebuild proceeds normally
- Lock not acquired (another instance rebuilding) →
return (0, nil)— silent skip, not an error - Lock is always released via
deferafter rebuild completes
Files
api/internal/wiki/wiki.go—RebuildGraph(),rebuildGraphLockKey()api/internal/storage/postgres.go—TryAdvisoryLock(),ReleaseAdvisoryLock()