本文へ移動
cccskills
無料GitHub で公開

postgres-concurrent-schema-init-deadlock

Fix PostgreSQL deadlock errors caused by concurrent schema initialization in worker processes. Use when: (1) psycopg2.errors.DeadlockDetected during CREATE INDEX/TABLE IF NOT EXISTS, (2) Multiple Cloud Run jobs, Kubernetes pods, or worker processes start simultaneously, (3) Error shows "Process X waits for RowExclusiveLock... blocked by process Y", (4) init_schema() or migration code runs at worker startup. The key insight: "IF NOT EXISTS" is NOT truly concurrent-safe - PostgreSQL still acquires locks that can deadlock.

インストール方法を見る

含まれるファイル(1)

  • SKILL.md4.2 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

PostgreSQL Concurrent Schema Init Deadlock

Problem

Multiple worker processes (Cloud Run jobs, K8s pods, serverless functions) starting simultaneously all try to run schema initialization code, causing PostgreSQL deadlocks even when using "IF NOT EXISTS" clauses.

Context / Trigger Conditions

  • Error: psycopg2.errors.DeadlockDetected: deadlock detected
  • Log shows: Process X waits for RowExclusiveLock on relation... blocked by process Y
  • Multiple workers/jobs starting at roughly the same time
  • Each worker calls init_schema() or runs migrations at startup
  • Using CREATE TABLE IF NOT EXISTS or CREATE INDEX IF NOT EXISTS

Why This Happens

PostgreSQL's IF NOT EXISTS is not concurrent-safe:

  1. CREATE INDEX IF NOT EXISTS still acquires locks before checking existence
  2. Multiple processes acquiring locks on different objects can deadlock
  3. Even "safe" DDL can conflict when executed concurrently

Solution

Option 1: Skip Init in Production (Recommended)

Schema already exists - don't run init_schema() in workers:

with Database() as db:
    # Schema already exists in production - skip to avoid deadlocks
    # db.init_schema()

    # ... worker code

Option 2: Use Advisory Locks

Serialize schema init with PostgreSQL advisory locks:

def init_schema_safe(self):
    cursor = self._cursor()
    # Acquire advisory lock (blocks other processes)
    cursor.execute("SELECT pg_advisory_lock(12345)")
    try:
        self.init_schema()
    finally:
        cursor.execute("SELECT pg_advisory_unlock(12345)")
        self.conn.commit()

Option 3: Separate Migration Step

Run migrations as a separate job before starting workers:

# In deployment pipeline
python -m src.migrate  # Single process, runs first
# Then start workers
gcloud run jobs execute worker-job

Option 4: Lock Timeout + Retry

Set lock timeout and retry on deadlock:

def init_schema_with_retry(self, max_retries=3):
    for attempt in range(max_retries):
        try:
            cursor = self._cursor()
            cursor.execute("SET lock_timeout = '5s'")
            self.init_schema()
            return
        except psycopg2.errors.DeadlockDetected:
            self.conn.rollback()
            if attempt == max_retries - 1:
                raise
            time.sleep(random.uniform(1, 3))

Verification

After applying fix:

  1. Start multiple workers simultaneously
  2. Check logs for absence of deadlock errors
  3. Verify all workers start successfully

Example

Before (deadlocks with 6 concurrent Cloud Run jobs):

# src/download.py
with VineDatabase() as db:
    db.init_schema()  # DEADLOCK when multiple jobs start!
    # ... download logic

After (no deadlocks):

# src/download.py
with VineDatabase() as db:
    # Schema already exists in production - skip to avoid deadlocks
    # db.init_schema()
    # ... download logic

Notes

  • This applies to any concurrent worker pattern: Cloud Run, Celery, Kubernetes, Lambda
  • The deadlock can be intermittent - depends on exact timing of worker starts
  • CREATE TABLE IF NOT EXISTS is generally safer than CREATE INDEX IF NOT EXISTS
  • Cloud Run jobs often start simultaneously when triggered, making this common
  • Consider using database migration tools (Alembic, Flyway) with proper locking

References

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Fix ArgoCD ExternalSecret deployment failing with "namespace X is not permitted in project Y". Use when: (1) ExternalSecret shows OutOfSync in ArgoCD but won't sync, (2) ArgoCD application status shows "namespace X is not permitted in project 'infrastructure'", (3) ExternalSecret targets a namespace managed by a different ArgoCD project, (4) Using apps-of-apps pattern with separate infrastructure and application projects.

日本語の概要は準備中です。原文の説明を表示しています。

divinevideo/divine-mobile2662026年10月10日 更新

Art direction for any content — reads text, PDF, Word, HTML, PPT, then proposes 2-3 creative directions with photography style, mood, and visual language. After selection, generates AI image prompts and visual briefs section-by-section. Use when the user shares content and needs visual direction, image sourcing, or creative direction for any material.

日本語の概要は準備中です。原文の説明を表示しています。

divinevideo/divine-mobile2662026年10月10日 更新

Fix "Null check operator used on a null value" errors when an object is set to null during an async await. Use when: (1) Object reference is nullified while awaiting, (2) Code accesses object with ! after await returns, (3) Cancel/dispose operations run concurrently with async operations on same object. Solution: capture local reference before await.

日本語の概要は準備中です。原文の説明を表示しています。

divinevideo/divine-mobile2662026年10月10日 更新

Add custom metadata headers (x-amz-meta-*) to AWS v4 signed requests for GCS S3-compatible API. Use when: (1) Adding custom metadata to GCS uploads via S3 API, (2) Getting signature mismatch errors after adding new headers, (3) x-amz-meta-* headers being ignored or causing 403 errors. Custom headers MUST be included in canonical headers and signed headers list.

日本語の概要は準備中です。原文の説明を表示しています。

divinevideo/divine-mobile2662026年10月10日 更新

Fix password/secret authentication failures caused by trailing newlines when creating Google Cloud secrets (or similar) with bash here-strings. Use when: (1) Password authentication fails with correct password, (2) Secret created with `<<< "value"` syntax, (3) Error like "password authentication failed" or "invalid token" despite correct value. Bash here-strings (`<<<`) add a trailing newline that corrupts secrets.

日本語の概要は準備中です。原文の説明を表示しています。

divinevideo/divine-mobile2662026年10月10日 更新

Fix silent video/media processing failures caused by URL extraction code that filters on file extensions (.mp4, .webm, .webp). Use when: (1) Media moderation, transcoding, or analysis silently skips files from Blossom or content-addressed storage servers, (2) URL extraction from Nostr event tags (imeta, r tags) drops URLs without recognized extensions, (3) CDN fallback URLs append .mp4 but the actual server uses extensionless content-addressed paths like /{sha256}. Common in Nostr video events (kind 34236) where different clients use different URL formats.

日本語の概要は準備中です。原文の説明を表示しています。

divinevideo/divine-mobile2662026年10月10日 更新

divinevideo のスキルをすべて見る

このスキルの問題を報告する