블로그

휴대폰이 잠들어도 채팅이 살아 있도록 하기

Mythex의 에이전트는 한 번의 요청에 몇 분 동안 작업할 수 있고, 휴대폰으로 지켜보고 있을 수도 있습니다. 휴대폰은 잠금이 걸리고, 앱을 바꾸고, 네트워크를 바꾸면서 작업합니다. 두 가지 버그가 이 상황을 망가뜨렸습니다. 하나는 "페이지가 다시 보입니다"라는 신호를 받을 때마다 채팅이 연결이 끊겼다고 판단하고 "연결 중…"에 멈출 때까지 반복하는 것이었습니다. 다른 하나는 새 채팅의 첫 답변 동안 휴대폰이 잠들었다가 돌아왔을 때 답변의 처음 몇 조각만 보이고, 수동으로 새로고침하기 전까지 그대로 있는 것이었습니다. 둘 다 고쳤습니다.

채팅이 실행 중인 턴을 따라가는 방식

에이전트가 작업하는 동안 채팅은 우리 서버에서 오는 스트림을 열어 둡니다. 각 단계(생각, 도구 호출, 답변의 한 조각)가 이벤트로 도착합니다. 스트림이 끊기면 채팅이 다시 연결하고, 서버는 최근 120초를 담은 버퍼에서 최근 이벤트를 다시 재생합니다. 턴이 끝나면 채팅은 서버에 저장된 기록도 요청하여, 화면에 보이던 것과 저장된 것을 맞춥니다. 이 마지막 단계는 스트림이 놓친 것을 잡아냅니다.

아무 일도 일어나지 않을 때 연결이 살아 있는지 죽었는지 알기 위해, 서버는 15초마다 작은 "핑"을 보냅니다.

버그 1: 깨어나는 것이 멀쩡한 스트림을 죽였다

브라우저는 페이지가 다시 보이게 되면 알려 줍니다. 탭을 바꾼 뒤나 화면 잠금이 풀린 뒤입니다. 우리는 그 신호를 연결을 확인하라는 신호로 썼습니다. 실제로는 스트림을 중단하고 다시 연결하는 신호였습니다. 숨겨진 동안 연결이 죽었을 것이라고 가정했기 때문입니다.

휴대폰과 내장 브라우저에서는 이 이벤트가 스트림이 죽는 것보다 훨씬 자주 발생합니다. 탭을 바꿀 때마다, 잠금을 풀 때마다, 그리고 일부 내장 브라우저에서는 몇 초마다 한 번씩 발생합니다. 그때마다 멀쩡한 스트림이 중단되었습니다. 채팅은 다시 연결하고, 재생하고, 또 중단되고, 결국 "연결 중…"에 머물렀습니다. 그러다가 에이전트가 아직 작업 중인데도 턴이 끝났다고 표시했습니다.

해결: 스트림이 말을 하고 있는지로 판단하기

이제 채팅은 프로젝트별 스트림이 마지막으로 무엇이든 받은 시각을 기록합니다. 이벤트와 15초마다 오는 핑 모두 포함합니다. "다시 보임" 신호는 25초 동안 조용했던 스트림만 중단합니다. 25초는 핑 간격에 느린 네트워크 구간을 더한 시간보다 길기 때문에, 살아 있는 스트림은 절대 해당되지 않습니다. 테스트는 핑이 살아 있다는 증거로 계산되는지, 그리고 방금 핑을 받은 스트림은 죽은 것으로 취급되지 않는지 확인합니다.

이 과정에서 얻은 교훈입니다. 페이지의 가시성은 페이지에 대한 정보이지 네트워크 연결에 대한 정보가 아닙니다. 연결에 직접 물어보세요.

버그 2: 휴대폰이 깨어난 뒤 답변이 절반만 보였다

이 버그는 iOS 시뮬레이터에서 매번 재현할 수 있었습니다.

  1. 새 채팅을 시작하고, 시간이 걸리는 요청을 보냅니다.
  2. 빌드 동안 휴대폰을 잠들게 둡니다.
  3. 턴이 끝나고 2분짜리 재생 버퍼가 만료된 뒤 돌아옵니다.

채팅에는 답변의 처음 몇 블록이 완료된 것으로 표시되었고, 페이지를 새로고침할 때까지 그대로였습니다.

원인

새 채팅에는 저장된 대화인 스레드가 없습니다. 첫 메시지가 스레드를 만들기 전까지는 없습니다. 그 생성은 전송 함수 안에서 일어나는데, 전송 함수는 이미 reconcile 단계를 캡처한 뒤였습니다. 그 reconcile은 여전히 스레드가 없다고 생각했습니다. 그래서 새 채팅의 첫 턴이 끝날 때 reconcile은 스레드가 없는 것을 보고 아무것도 요청하지 않고 조용히 반환했습니다.

보통은 아무도 알아채지 못했습니다. 스트림이 턴 전체를 이미 전달했기 때문입니다. 하지만 턴 동안 잠들었다가 120초 재생 버퍼가 만료된 뒤에 돌아온 휴대폰은 스트림에서 빠진 이벤트를 받을 수 없었습니다. 그 빈틈을 채워야 할 reconcile은 한 번도 실행되지 않았습니다.

해결

  • 전송이 reconcile에 턴이 속한 스레드를 알려 줍니다. 그래서 새 채팅의 첫 턴도 다른 턴과 똑같이 reconcile됩니다. 답변이 돌아올 때 다른 채팅을 열고 있다면, 결과는 엉뚱한 곳에 보이는 대신 버려집니다.
  • 실패한 reconcile은 다시 시도합니다. 나쁜 연결 상태에서 깨어난 휴대폰은 턴이 이미 끝났는데도 기록을 가져오지 못할 수 있습니다. 이제 그것을 기억해 두고, 탭이 다시 보이거나 네트워크가 돌아오면 다시 요청합니다.
  • "작업 시간"을 정직하게 보여 줍니다. 각 답변에는 에이전트가 작업한 시간이 표시됩니다. 탭이 서버의 턴 종료 메시지를 보지 못했다면, 예전에는 자신의 시계로 그 값을 채웠습니다. 전송 버튼을 누른 시점부터 휴대폰이 깨어난 시점까지, 떠나 있던 시간까지 포함한 값이었습니다. 이제 그 수치는 추정치로 표시되고, 기록이 도착하면 저장된 실제 시간으로 바뀝니다.

얻은 교훈

  • 사람들이 실제로 쓰는 기기에서, 실제로 쓰는 방식대로 테스트하세요. 두 버그 모두 "잘 작동하는 스트림"과 "주머니 속 휴대폰" 사이의 틈에 있었습니다.
  • 한 번도 실행되지 않는 대비책은 대비책이 아닙니다. reconcile 단계는 바로 이 경우를 잡기 위해 있었지만, 조용히 건너뛰고 있었습니다.
  • 복구도 다시 시도하세요. 휴대폰이 깨어나는 순간은 연결 상태가 가장 나쁠 때인 경우가 많습니다.
  • 추측을 사실처럼 보여 주지 마세요. 잘못된 시계에서 나온 시간은 아무것도 없는 것보다 나쁩니다. 표시하거나 교체하세요.

이 작업에서 턴이 실행되는 동안 보이는 몇 가지도 함께 정리되었습니다. 셸 단계는 cd 대신 실제 작업을 하는 명령으로 표시되고, 채팅의 스크린샷은 페이지의 왼쪽 위를 유지하며 칼럼에 맞고, 새 프로젝트는 새로고침 없이 생성된 이름을 받습니다.

휴대폰에서 쓰는 앱을 직접 만들고 있다면, 모바일 친화적인 웹 앱 만들기와 네이티브 앱과 프로그레시브 웹 앱 비교에 기본 내용이 있습니다. 채팅 자체에 대해서는 채팅 문서를 참고하세요.

Mythex · Pricing · AI로 무엇이든 만들기 · 웹사이트 및 앱 템플릿 · Mythex 비교 · AI 앱 개발 용어집 · 무료 AI 앱 개발 도구 · English

English አማርኛ العربية Български বাংলা Bosanski Català Čeština Dansk Deutsch Ελληνικά Español Español (España) Eesti فارسی Suomi Français Français (Canada) ગુજરાતી हिन्दी Hrvatski Magyar Հայերեն Bahasa Indonesia Íslenska Italiano 日本語 ქართული Қазақ тілі ಕನ್ನಡ Lietuvių Latviešu Македонски മലയാളം Монгол मराठी Bahasa Melayu မြန်မာ Norsk bokmål Nederlands ਪੰਜਾਬੀ Polski Português (Brasil) Português (Portugal) Română Русский Slovenčina Slovenščina Soomaali Shqip Srpski Svenska Kiswahili தமிழ் తెలుగు ไทย Tagalog Türkçe Українська اردو Tiếng Việt 简体中文 繁體中文(香港) 繁體中文(台灣)