{"id":"IL-0546","org":"Buildkite","date":"2023-07-22","docs":[],"title":{"en":"Buildkite jobs could not go to newly connected agents once agent IDs passed a 32-bit integer foreign key's limit","ko":"Buildkite 에 새로 연결한 에이전트가 잡을 받지 못했다"},"domain":["database"],"impact":{"scope":"Agents connected between 10:06:20 and 11:40:09 UTC could not pick up new jobs; the status page lists Agent API and Job Queue","users":"unknown","region":"unknown"},"review":{"written_by":"session","reviewed_at":null,"reviewed_by":null},"lessons":{"en":"Buildkite said that, while existing numeric primary keys stay in use, the incident showed a blind spot in its monitoring.","ko":"Buildkite 는 데이터베이스 샤딩 작업과 함께 새 테이블에 시간 순서 UUID 기본 키를 쓰고 있지만, 기존 숫자 기본 키는 한동안 남겨 둔다. 이 장애로 모니터링에 사각지대가 있다는 것이 드러났다."},"related":[],"sources":[{"url":"https://www.buildkitestatus.com/incidents/63zxhjsysszc","kind":"official-status","archived":"https://web.archive.org/web/20240518004408/https://www.buildkitestatus.com/incidents/63zxhjsysszc"}],"summary":{"en":"Buildkite stores connected agents in PostgreSQL with a `bigint` primary key, but a foreign key that maps build jobs to agents was stored as `integer`. At 10:06:20 UTC on 22 July 2023 the agent ID passed 2,147,483,647, the largest value a signed 32-bit integer can hold, and from then on jobs could not be assigned to any agent that connected. Monitoring alerted within 4 minutes. The team started migrating the foreign key to `bigint` and looked for a faster fix at the same time. Neither the SQL standards nor PostgreSQL offer unsigned integer types, but PostgreSQL sequences accept a negative start and a negative increment and Rails/ActiveRecord handles that, so the negative half of the 32-bit range could serve as a temporary workaround. The IDs are internal only, since Buildkite uses separate UUIDs for public references, so no outside system would reject negative IDs.\n\nAfter testing the workaround in non-production environments and reconfiguring the table partitioning, the team changed the agent ID sequence at 11:40 UTC to start at -1 and step by -1, and agents that connected from then on worked. By 12:08 UTC the team had disconnected the agents that had connected between 10:06 and 11:40, so they came back with new IDs. Buildkite already used time-ordered UUID primary keys for new tables as part of its database sharding project, but is keeping existing numeric primary keys for some time, and the incident showed a blind spot in its monitoring.","ko":"2023년 7월 22일 10:06:20 UTC 에 Buildkite 의 연결된 에이전트를 가리키는 내부 기본 키가 PostgreSQL `integer` 타입의 최댓값을 넘었다. `integer` 는 부호 있는 32비트 정수이고 최댓값은 2,147,483,647 이다. 기본 키 자체는 부호 있는 64비트 정수인 `bigint` 로 저장돼 여유가 충분했다. 하지만 빌드 잡과 에이전트를 잇는 외래 키는 더 작은 `integer` 로 저장돼 있었고, 그 시각 이후에 연결한 에이전트에는 잡을 배정할 수 없었다.\n\n자동 모니터링이 4분 안에 알렸다. 팀은 외래 키를 bigint 로 바꾸는 마이그레이션을 시작하면서 더 빠른 해결책도 찾았다. SQL 표준과 PostgreSQL 은 부호 없는 정수 타입을 지원하지 않는다. 하지만 PostgreSQL 시퀀스는 음수 시작값과 음수 증가값을 지원하고 Rails/ActiveRecord 도 이를 받아들여서, 부호 있는 32비트 정수의 음수 쪽 절반을 임시로 쓸 수 있었다. 이 ID 는 내부에서만 쓰고 외부 참조에는 별도의 UUID 를 쓰므로, 외부 시스템이 음수 ID 를 거부할 위험은 없었다.\n\n비운영 환경에서 해결책을 확인하고 테이블 파티셔닝을 다시 설정한 뒤, 11:40 UTC 에 ID 시퀀스를 -1 에서 시작해 -1 씩 증가하도록 바꿨다. 그 뒤에 연결한 에이전트는 제대로 동작했다. 12:08 UTC 까지 10:06 부터 11:40 사이에 연결한 에이전트를 모두 끊어 새 ID 로 다시 연결하게 했다."},"trigger":{"en":"At 10:06:20 UTC on 22 July 2023, the primary key for connected agents went past the maximum value of the PostgreSQL integer type.","ko":"2023년 7월 22일 10:06:20 UTC 에 연결된 에이전트의 내부 기본 키가 PostgreSQL `integer` 타입의 최댓값을 넘었다."},"severity":"unknown","symptoms":["integer-id-overflow"],"timeline":{"detected_after":"4m","resolved_after":"2h 2m"},"date_kind":"incident","detection":{"en":"Automated monitoring alerted the team within 4 minutes of the ID passing the integer maximum.","ko":"자동 모니터링이 4분 안에 알림을 보냈다."},"components":["database"],"root_cause":"capacity","remediation":[{"text":{"en":"Changed the agent ID sequence at 11:40 UTC to start at -1 and increment by -1, after verifying it in non-production environments and reconfiguring table partitioning","ko":"비운영 환경에서 확인하고 테이블 파티셔닝을 다시 설정한 뒤, 11:40 UTC 에 에이전트 ID 시퀀스가 -1 에서 시작해 -1 씩 증가하도록 바꿨다. 그 뒤에 연결한 에이전트는 제대로 동작했다."}},{"text":{"en":"Disconnected the agents that had connected between 10:06 and 11:40 UTC by 12:08 UTC so they reconnected with new IDs","ko":"12:08 UTC 까지 10:06 부터 11:40 사이에 연결한 에이전트를 모두 끊어 새 ID 로 다시 연결하게 했다."}}],"action_items":[{"text":{"en":"Monitor identifiers and alert when one exceeds 50% of its maximum value","ko":"식별자가 최댓값의 50% 를 넘으면 알리는 모니터링과 알림을 만들었다."}},{"text":{"en":"Audit all existing primary and foreign keys for correctness and remaining runway","ko":"기존의 모든 기본 키와 외래 키가 올바른지, 최댓값까지 여유가 얼마나 남았는지 점검했다."}},{"text":{"en":"Add ratchet tests that stop new 32-bit integer identifiers from being introduced","ko":"새 32비트 `integer` 식별자가 들어오지 못하게 막는 ratchet 테스트를 더했다."}}],"contributing":["monitoring-blind-spot"],"recurrence_of":null,"symptoms_text":{"en":"From 10:06:20 UTC on Saturday 22 July 2023, Buildkite agents that connected could not pick up jobs, while agents that had connected before that moment kept working. Automated monitoring alerted the team within 4 minutes.\n\nThe cause was in PostgreSQL: the internal primary key for connected agents had just passed 2,147,483,647, the maximum of the PostgreSQL `integer` type (signed 32-bit). The primary key itself was a `bigint` and had room to spare, but some tables referenced agent IDs through foreign key columns of type `integer`, and the IDs of agents created after 10:06:20 could not be stored in those columns. The status page reported the problem first as newly connected agents being unable to run jobs, and later as tables trying to reference 64-bit agent IDs with 32-bit foreign key columns.","ko":"2023년 7월 22일 10:06:20 UTC 이후에 연결한 Buildkite 에이전트가 새 잡을 받지 못했다. 그 전에 연결한 에이전트는 계속 동작했다.\n\n연결된 에이전트의 내부 기본 키가 PostgreSQL `integer` 타입의 최댓값인 2³¹-1, 곧 2,147,483,647 을 넘었다. 기본 키는 `bigint` 였지만 빌드 잡과 에이전트를 잇는 외래 키는 `integer` 였고, 10:06:20 UTC 이후에 만들어진 에이전트 ID 는 32비트로 참조할 수 없었다.\n\n자동 모니터링이 4분 안에 알림을 보냈다. 상태 페이지에는 10:42 UTC 에 새로 연결한 에이전트가 잡을 실행하지 못한다는 글이 올라왔고, 10:47 UTC 에 일부 테이블이 32비트 외래 키 열로 64비트 에이전트 ID 를 참조하려 해서 생긴 문제라는 설명이 올라왔다. 영향을 받은 구성 요소는 Agent API 와 Job Queue 였다.\n\nBuildkite 가 11:40 UTC 에 문제를 고친 뒤에도 10:06:20 UTC 부터 11:44 UTC 사이에 연결한 에이전트는 계속 잡을 받지 못했다. 이 에이전트들은 연결을 끊어 새 ID 로 다시 연결하게 해야 했다."},"updated_at":"2026-11-14T12:34:19.052674Z","url":"https://benchlet.com/incidentlib/app/cases/IL-0546","org_slug":"buildkite"}