현장

계산대가 없는 동안 — 열어 둔 구멍 하나를 메운다

창간호부터 열려 있던 줄이 오프라인 동작이었다. 이번엔 계산대 프로세스를 중간에 죽이고 주문 세 건을 더 받았다. 잃지 않는 것과 두 번 받지 않는 것은 반대 방향의 실패라서, 둘 다 검사한다.

작성: makemind · 2026년 8월 14일

이 매거진은 여섯 달 동안 같은 문장을 반복해 적었다.

오프라인·캐시 동작 — 아직 열려 있는 줄

(2026년 1월을 돌아보며에서 그대로 옮긴 것이다.) 이번 편이 그 줄을 지운다.

왜 이게 남아 있었나

만들기 귀찮아서가 아니다. 오프라인은 시험하기가 까다롭다. 연결이 있는 상태를 시험하는 건 쉽다 — 돌려서 되면 된다. 없는 상태를 시험하려면 없게 만들어야 하고, "없다"는 상태가 여러 종류다.

이 샘플은 그중 가장 나쁜 두 가지만 다룬다.

  1. 보낼 데가 없다. 그런데 손님은 앞에 서 있다.
  2. 보냈는데 대답이 안 왔다. 도착했는지 아닌지 패드는 알 방법이 없다.

둘은 반대 방향의 실패로 이어진다. 첫 번째를 안 다루면 주문이 사라지고, 두 번째를 안 다루면 두 번 계산된다. 큐를 넣어서 첫 번째만 해결하면 두 번째가 새로 생긴다 — 그게 이 편이 하고 싶은 말이다.

계산대가 있을 때

TILL ONLINE — 패드가 받은 주문이 till 에 바로 닿는다. 아래 큐는 비어 있고 오늘 1건 3.5k won
TILL ONLINE — 패드가 받은 주문이 till 에 바로 닿는다. 아래 큐는 비어 있고 오늘 1건 3.5k won
till: connected
online: took 1, delivered 1, till has 1 (3.5k won)

평범하다. 커피 한 잔 눌렀고, 계산대가 받았다.

계산대가 사라진다

till: process gone — the pad is now on its own

프로세스를 죽였다. 푸드트럭이라면 핫스팟이 끊긴 것이고, 패드 입장에서는 구별되지 않는다 — 보낸 게 답을 안 받는다는 사실만 같다.

그리고 주문 세 건을 더 받는다.

TILL UNREACHABLE — 패드는 계속 받는다. WAITING TO REACH THE TILL 에 pad1-002 · pad1-003 · pad1-004 세 id 가 줄 서 있다
TILL UNREACHABLE — 패드는 계속 받는다. WAITING TO REACH THE TILL 에 pad1-002 · pad1-003 · pad1-004 세 id 가 줄 서 있다
offline: took pad1-002 (sandwich) — nothing was sent
offline: took pad1-003 (coffee) — nothing was sent
offline: took pad1-004 (juice) — nothing was sent
offline: pad still took 3 orders, 3 waiting, ids pad1-002 pad1-003 pad1-004

화면이 빨간 건 정직하기 위해서다. 안 보내지고 있다는 걸 숨기면 그건 오프라인 지원이 아니라 오프라인 은폐다. 주문을 계속 받되, 몇 건이 아직 안 갔는지 사람이 볼 수 있어야 한다.

아웃박스가 전부다

이 샘플의 답은 클래스 하나다. 주문 패드는 계산대를 직접 부르지 않는다.

/// The order pad never calls the till directly. It writes into here, and here
/// tries to deliver. That one indirection is what lets the person behind the
/// counter keep working while the till is unreachable, and it is also what
/// makes the failure honest: the pad can show how many orders are still
/// undelivered, because the outbox knows.

그 한 겹이 두 가지를 동시에 준다. 계속 일할 수 있는 것과, 몇 건이 밀렸는지 말할 수 있는 것.

규칙은 두 개뿐이다.

① id는 여기서, 첫 시도 전에 만든다.

final p = Pending('$device-${(++_minted).toString().padLeft(3, '0')}', item);

계산대가 id를 붙이면 재전송이 새 주문이 된다. 그러면 손님이 두 번 계산된다. 재시도가 안전하려면 무엇을 재시도하는지가 재시도 전에 정해져 있어야 한다.

② 순서대로 보내고, 첫 실패에서 멈춘다.

} catch (_) {
  // Still ours. Leave it at the front and stop — the ones behind it are
  // newer and must not overtake.
  break;
}

건너뛰고 뒤엣것을 보내면 장부가 아침을 잘못 적는다. 12시 주문이 11시 주문보다 먼저 찍힌 장부는 그냥 틀린 장부다.

그리고 큐는 파일에 있다.

/// Where the queue lives between app launches. A queue that only exists in
/// memory is not a queue — closing the lid is the same as losing the orders.
final File spoolFile;

이 콘텐츠는 개발자 이상이 필요합니다

로그인 후 플랜을 업그레이드하면 계속 읽을 수 있습니다.

플랜 보기
Twitter