multica-ai/multica · error

acquire advisory-lock connection: %w

Error message

acquire advisory-lock connection: %w

What it means

pool.Acquire(ctx) failed when the backfill tried to reserve a dedicated session connection to hold advisory lock 4246 for the whole run. Acquire fails when the context is done, the pool is closed, or the max connection lifetime/idle settings cause a acquire-time failure (e.g. pool already at max_conns and acquire deadline exceeded).

Source

Thrown at server/cmd/backfill_task_usage_hourly/main.go:104

	pool, err := pgxpool.New(ctx, dbURL)
	if err != nil {
		return fmt.Errorf("connect to database: %w", err)
	}
	defer pool.Close()

	if err := pool.Ping(ctx); err != nil {
		return fmt.Errorf("ping database: %w", err)
	}

	// Serialise against the cron rollup and any other backfill run via
	// advisory lock 4246 — the same id the cron entry checks with
	// pg_try_advisory_lock. While this backfill holds it, the cron tick
	// no-ops instead of racing on task_usage_hourly row locks; a second
	// concurrent backfill blocks here until this one finishes. The lock
	// is held on a dedicated session connection for the whole run.
	lockConn, err := pool.Acquire(ctx)
	if err != nil {
		return fmt.Errorf("acquire advisory-lock connection: %w", err)
	}
	defer lockConn.Release()
	if _, err := lockConn.Exec(ctx, `SELECT pg_advisory_lock(4246)`); err != nil {
		return fmt.Errorf("acquire advisory lock 4246: %w", err)
	}
	defer func() {
		// Unlock on a fresh context so a cancelled ctx (SIGINT) does not
		// skip the release. Releasing the connection afterwards would end
		// the session anyway, but an explicit unlock frees it immediately.
		_, _ = lockConn.Exec(context.Background(), `SELECT pg_advisory_unlock(4246)`)
	}()

	var minTS, maxTS pgtype.Timestamptz
	if err := pool.QueryRow(ctx, `SELECT MIN(created_at), MAX(created_at) FROM task_usage`).Scan(&minTS, &maxTS); err != nil {
		return fmt.Errorf("scan task_usage time range: %w", err)
	}
	if !minTS.Valid {
		slog.Info("task_usage is empty; nothing to backfill")

View on GitHub (pinned to 2c0912b6ec)

Solutions

  1. If ctx.Err() is context.Canceled, this is expected on interrupt — just re-run later; the idempotent design resumes
  2. Check whether another process exhausted Postgres max_connections so the pool cannot open new sessions
  3. Verify the process is not double-running with a shared pool that was closed
Defensive patterns

Strategy: retry

Try / catch

lockConn, err := pool.Acquire(ctx)
if err != nil {
    return fmt.Errorf("acquire advisory-lock connection: %w", err)
}

Prevention

When it happens

Trigger: ctx cancelled by SIGINT/SIGTERM before acquisition; pool.Close() racing the Acquire; pool_max_conns exhausted by other long-lived acquires so Acquire blocks past its context deadline.

Common situations: Sending Ctrl+C immediately at startup; running the backfill against a pool shared with a busy worker that saturates connections (rare here since the tool owns its pool).

Related errors


AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15). Data as JSON: /api/errors/a276bc4adff8bd25. Report an issue: GitHub.