Skip to content

Instantly share code, notes, and snippets.

@diegolirio
Created June 3, 2026 15:53
Show Gist options
  • Select an option

  • Save diegolirio/d798476cf32d510999ff973401bd1502 to your computer and use it in GitHub Desktop.

Select an option

Save diegolirio/d798476cf32d510999ff973401bd1502 to your computer and use it in GitHub Desktop.
Lock-para-Jobs.md

Estratégias de Lock para Jobs Distribuídos

Abaixo estão as 3 estratégias mais comuns para coordenação de processamento concorrente em filas baseadas em banco de dados: SKIP LOCKED, WAIT e NOWAIT / erro imediato.


1. SKIP LOCKED

Cada instância pega apenas registros livres e ignora os que já estão travados por outra transação.

SELECT id, payload, status
FROM payment_request
WHERE status = 'PENDING'
ORDER BY id
FETCH FIRST 100 ROWS ONLY
FOR UPDATE SKIP LOCKED;

Exemplo com atualização de status no fluxo

-- dentro de transação
SELECT id
FROM payment_request
WHERE status = 'PENDING'
ORDER BY id
FETCH FIRST 100 ROWS ONLY
FOR UPDATE SKIP LOCKED;

-- depois processa e marca
UPDATE payment_request
SET status = 'PROCESSING',
    updated_at = CURRENT_TIMESTAMP
WHERE id IN (...);

Exemplo Oracle com subquery

Em Oracle, muitas vezes fica mais seguro escrever assim:

SELECT *
FROM (
    SELECT id, payload, status
    FROM payment_request
    WHERE status = 'PENDING'
    ORDER BY id
)
WHERE ROWNUM <= 100
FOR UPDATE SKIP LOCKED;

Comportamento

  • Instância A pega linhas 1–100
  • Instância B pega linhas 101–200
  • Instância C pega linhas 201–300

As linhas já bloqueadas por outras transações são simplesmente ignoradas.

Quando usar

  • Filas de processamento
  • Jobs distribuídos com múltiplas instâncias
  • Cenários onde throughput e paralelismo importam

2. WAIT

Aqui a instância tenta pegar as mesmas linhas, mas espera o lock ser liberado por alguns segundos.

Oracle

SELECT id, payload, status
FROM payment_request
WHERE status = 'PENDING'
ORDER BY id
FOR UPDATE WAIT 5;

Isso significa: espere até 5 segundos se a linha já estiver bloqueada.

PostgreSQL

No PostgreSQL, o comportamento padrão de FOR UPDATE já é esperar indefinidamente:

BEGIN;

SELECT id, payload, status
FROM payment_request
WHERE status = 'PENDING'
ORDER BY id
FOR UPDATE;

COMMIT;

Se quiser limitar o tempo de espera:

SET LOCAL lock_timeout = '5s';

SELECT id, payload, status
FROM payment_request
WHERE status = 'PENDING'
ORDER BY id
FOR UPDATE;

Comportamento

  • Instância A bloqueia linhas
  • Instância B tenta pegar as mesmas linhas
  • Instância B fica aguardando
  • Quando A libera o lock, B continua

Quando usar

  • Processamento serializado
  • Quando você quer garantir espera ao invés de pular ou falhar
  • Cenários em que conflito é aceitável e deve aguardar resolução

3. NOWAIT / erro imediato

Aqui a instância tenta pegar o lock e, se ele já existir, recebe erro imediatamente.

Oracle

SELECT id, payload, status
FROM payment_request
WHERE status = 'PENDING'
ORDER BY id
FOR UPDATE NOWAIT;

PostgreSQL

SELECT id, payload, status
FROM payment_request
WHERE status = 'PENDING'
ORDER BY id
FOR UPDATE NOWAIT;

Comportamento

  • Instância A bloqueia linhas
  • Instância B tenta pegar as mesmas linhas
  • O banco retorna erro imediatamente

Exemplos típicos de erro

  • Oracle: ORA-00054
  • PostgreSQL: erro de lock não disponível

Quando usar

  • Quando conflito deve falhar rápido
  • Fluxos onde retry é tratado pela aplicação
  • Cenários em que esperar não faz sentido

Resumo das estratégias

Estratégia Se a linha já está lockada
FOR UPDATE SKIP LOCKED pula a linha e segue
FOR UPDATE / WAIT espera o lock liberar
FOR UPDATE NOWAIT lança erro imediatamente

Exemplo mental com 3 instâncias

Suponha uma fila com linhas 1..10.

SKIP LOCKED

  • Instância A pega 1,2,3
  • Instância B pega 4,5,6
  • Instância C pega 7,8,9

WAIT

  • Instância A pega 1,2,3
  • Instância B tenta 1,2,3 e espera
  • Instância C tenta 1,2,3 e espera

NOWAIT

  • Instância A pega 1,2,3
  • Instância B tenta 1,2,3 e recebe erro
  • Instância C tenta 1,2,3 e recebe erro

Recomendação para filas de jobs

Na prática, o uso mais comum é:

  • SKIP LOCKED → melhor para throughput e paralelismo
  • WAIT → melhor quando você quer serialização
  • NOWAIT → melhor quando conflito deve falhar rápido

Conclusão

Se o seu caso é uma fila de processamento distribuída, normalmente a melhor estratégia é SKIP LOCKED, pois permite que múltiplas instâncias consumam lotes distintos sem sobreposição.

Se a intenção é esperar a liberação do lock, use WAIT.

Se a intenção é falhar imediatamente quando houver contenção, use NOWAIT.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment