Ctrl K
ComunidadGuías…

server/storage/LockHelper.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import type { Sequelize, Transaction } from "sequelize";
import { QueryTypes } from "sequelize";

/**
 * Helper for taking advisory locks in the database.
 *
 * These locks are scoped to a transaction. When the routine to serialize is not
 * a transaction, or it calls an external service, use `MutexLock` instead.
 */
export class LockHelper {
  /**
   * Take an advisory lock that is held for the remainder of the given
   * transaction, blocking every other transaction that asks for the same name
   * until this one commits or rolls back.
   *
   * Use this to make a read-then-write sequence atomic when there is no row to
   * lock, such as counting rows before inserting one more.
   *
   * @param sequelize the database connection to take the lock on.
   * @param name the name of the lock, shared by everything that must serialize.
   * @param transaction the transaction to hold the lock for. When none is given
   * the lock cannot be held and is skipped.
   * @returns a promise that resolves when the lock is held.
   */
  public static async acquire(
    sequelize: Sequelize,
    name: string,
    transaction?: Transaction | null
  ): Promise<void> {
    if (!transaction) {
      return;
    }

    await sequelize.query("SELECT pg_advisory_xact_lock(hashtext(:name))", {
      replacements: { name },
      type: QueryTypes.SELECT,
      transaction,
    });
  }

  /**
   * Attempts to acquire a transaction advisory lock without waiting.
   *
   * @param sequelize the database connection.
   * @param name the lock name.
   * @param transaction the lock transaction.
   * @returns true if the lock was acquired.
   */
  public static async tryAcquire(
    sequelize: Sequelize,
    name: string,
    transaction?: Transaction | null
  ): Promise<boolean> {
    if (!transaction) {
      return true;
    }

    const rows = await sequelize.query<{ locked: boolean }>(
      "SELECT pg_try_advisory_xact_lock(hashtext(:name)) AS locked",
      {
        replacements: { name },
        type: QueryTypes.SELECT,
        transaction,
      }
    );

    return rows[0]?.locked ?? false;
  }
}