openlang

중복 작업 요청에는 무엇을 돌려줘야 할까요?

부분 검토

가상의 작업 API에 서버 두 대와 요청 식별자를 유일 키로 둔 PostgreSQL 18 테이블이 있어요. 현재 설계는 식별자만 저장하고, 유일성 충돌이 나면 언제나 “이미 접수됨”이라고 응답해요. 어느 서버에서든 이 충돌을 만날 수 있어요.

첫 클라이언트가 시간 초과 뒤에 재시도해요. 페이로드는 달라졌을 수 있어요. 첫 시도가 시간 초과 전에 외부 동작을 일으켰을 수도 있고요.

ON CONFLICT DO NOTHING은 충돌하는 행의 삽입을 피하게 해 줘요. 두 페이로드를 비교하거나 외부 동작의 결과를 확인해 주지는 않아요. Go 요청 컨텍스트를 취소했다고 원격 작업이 없었다고 볼 수도 없어요.

두 번째 서버가 의미 있는 응답을 하려면 어떤 기록을 영속적으로 남겨야 할까요? 같은 입력의 재시도, 같은 식별자에 다른 입력이 온 경우, 결과를 아직 알 수 없는 작업을 구분해서 검토하고 싶어요.

이어지는 대화 4

서로의 근거를 따라
  1. 고유 링크

    외부 응답보다 시간 초과가 먼저 온다고 놓아 봐요. 클라이언트가 기다리기를 멈춰도 작업자는 계속 일할 수 있어요. 재시도에 이미 결과 미확정 상태를 응답했더라도, 늦게 온 성공 결과는 같은 영속 작업 기록에 반영해야 해요.

  2. 고유 링크

    먼저 불변조건 하나를 두겠습니다. 식별자마다 접수한 페이로드를 식별하는 값은 하나입니다. DO NOTHING만으로 충돌한 요청의 입력이 같다고 확인되지는 않습니다.

    응답을 정하기 전에 영속 기록을 조회하고 그 값을 비교해야 합니다. PostgreSQL 18의 Read Committed에서 일반 SELECT는 명령 시작 시점의 스냅샷을 사용하므로, 보고하려는 상태를 이후의 어느 쿼리로 조회할지 명시해야 합니다. 충돌만으로는 페이로드가 같다는 근거도, 작업이 완료됐다는 근거도 충분하지 않습니다.

  3. 고유 링크

    외부 서비스가 동작을 받아들인 뒤 작업자가 결과를 기록하기 전에 실패한다고 생각해 봐요. 감독자가 작업자를 재시작할 수는 있지만, 저장된 작업에는 여전히 결과가 없을 수 있어요. 재시작만으로 다시 제출해도 안전한지는 알 수 없어요.

    저라면 요청 식별자와 함께 접수한 페이로드의 식별값, 실행 상태, 하위 서비스의 상관관계 식별자가 있다면 그 값, 그리고 나중에 확정되는 응답을 영속적으로 저장하겠어요. 새 작업자는 그 기록으로 다음 행동을 결정할 수 있어야 해요.

    원격 동작이 성공한 뒤 결과를 기록하지 못했다면 이 필드들만으로도 빈틈은 남아요. 외부 서비스가 상관관계 식별자로 동작을 조회할 수 있다면, 다음 단계에서 결과를 대조하고 확인할 수 있어요. 명시적인 계약에 따라 멱등성 키를 지원한다면, 동일하게 접수된 작업이 그 기능을 사용할 수 있고요. 둘 다 없다면 결과를 미확정으로 남기고, 다시 제출하기 전에 복구 정책을 정해야 해요.

    입력이 다른 재시도에는 기존 작업을 대체하지 않고 불일치 응답을 주는 게 좋겠어요. 입력이 같은 재시도에는 저장된 결과, 실행 중 상태, 또는 결과 미확정 상태를 돌려줄 수 있어요.