postgresql - Prevenirea condițiilor de cursă atunci când se blochează rânduri


Deci am un tabel numit 'Ready' care stochează referințe la obiecte S3 care sunt gata pentru procesare. În aplicația mea care consumă aceste date și le modifică, vreau să pot prelua cel mai recent obiect S3, dacă furnizorul său relevant nu este utilizat sau dacă blocarea acelui furnizor a expirat.

Structura mesei mele arată astfel:

cheie (PK) | furnizor | marcă temporală (createdAt) | blocat | exp

Folosesc TypeORM pentru a crea o TRANZACȚIE, a obține cea mai recentă referință a obiectului (neblocată) și a actualiza toate celelalte coloane cu acel furnizor pentru a fi blocate, astfel încât să nu consumăm din greșeală două seturi de date de la același furnizor.

Codul meu arată astfel:

return getManager().transaction(async (entityManger) => {
    const firstReady = await entityManger
      .createQueryBuilder(Ready, 'ready')
      .setLock('pessimistic_write')
      .select()
      .orderBy('timestamp')
      .where('locked = false or exp < :now', { now: Date.now() })
      .getOne();
    if (!firstReady) return;
    await entityManger
      .createQueryBuilder(Ready, 'ready')
      .update()
      .set({ locked: true, exp: Date.now() + vars.PG.LOCK_EXP })
      .where('provider = :provider', { provider: firstReady.provider })
      .execute();
    logger.debug(`Acquired lock on ${firstReady.provider} and S3 object key ${firstReady.key}`);
    return firstReady.key;
  });

Sunt îngrijorat că, dacă, întâmplător, doi consumatori interoghează două rânduri separate cu același furnizor aproape în același timp, aș putea avea o condiție de concurență. Am luat în considerare blocarea întregului tabel atunci când un consumator efectuează această interogare, dar mă întreb dacă există o metodă mai bună. Mulțumesc!