Skip to content

FSR/TSR hardening: use transaction-scoped advisory lock #75

Description

@lucasdoell

Problem

Both recomputeAllFsr() (src/lib/fsr/compute.ts) and recomputeAllTsrs() (src/lib/tsr/replay.ts) guard against concurrent runs with a session-scoped advisory lock:

  • acquire via prisma.$queryRaw\SELECT pg_try_advisory_lock()``
  • release via prisma.$executeRaw\SELECT pg_advisory_unlock()`in afinally`

With the pooled @prisma/adapter-pg connection (src/lib/prisma.ts, pg.Pool), a bare $queryRaw/$executeRaw runs on whatever idle pool connection is checked out per call — so the lock and the unlock can land on different backend sessions. When that happens the unlock is a no-op and the original session keeps the lock until that connection is physically closed (it isn't — it's recycled into the pool).

Observed symptom: running the FSR bootstrap twice in quick succession, the second run returns outcome: "skipped_locked" even though no recompute is actually in progress.

Severity

Low. The daily crons are single-flight at the platform level, and each recompute is the last meaningful step, so worst case is a skipped recompute → one day of stale ratings. No corruption, no crash. It is, however, latent and confusing, and it's duplicated across two call sites.

Fix

Switch to a transaction-scoped lock so acquire + release are guaranteed same-connection and auto-released on commit/rollback:

SELECT pg_try_advisory_xact_lock(<id>)

acquired as the first statement inside the recompute's own interactive $transaction, with the lock automatically released when that transaction ends. (FSR already does its writes in one interactive transaction, so this composes cleanly; TSR would need its lock + write wrapped together, or a short pinned transaction around the lock lifecycle.)

Apply the same change to both recomputeAllFsr and recomputeAllTsrs in the same PR — keeping two copies of a subtly-broken lock pattern is worse than one.

Context

Identified during the FSR engine build (branch staging). FSR uses lock id 732402, TSR uses 732401.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions