실제 WebSocket 클라이언트는 항상 연결이 끊깁니다. 휴대폰이 잠기고, Wi-Fi가 셀룰러로 전환되고, 터널에 문제가 생기고, 캡티브 포털이 방해합니다. 연결이 다시 돌아오면 클라이언트가 자리를 비운 사이에 게시된 메시지는 사라져 있습니다. "휴대폰이 잠긴 동안 메시지를 놓쳤다"는 것은 사용자가 가장 먼저 알아채는 장애이며, 흔한 우회책 — 재연결할 때마다 전체 상태를 다시 가져오는 것 — 은 낭비가 심하고 잘못되기 쉽습니다.
sgcWebSockets는 이제 이 문제를 직접 해결합니다. 서버에서 히스토리를 활성화하면 재연결하는 클라이언트가 놓친 메시지를 정확히 재생합니다. offset 기준으로 말입니다. 옵트인 방식이며 기본값은 비활성화이므로, 직접 켜기 전까지 기존 배포 환경은 이전과 정확히 동일하게 동작합니다. 이 글에서는 작동 방식, 구성 방법, 그리고 Delphi 및 .NET 예제를 다룹니다.
작동 방식
히스토리가 활성화되면 채널에 게시되는 모든 메시지에 단조 증가하는 offset이 찍히고, 서버의 채널별 한정 링 버퍼에 추가됩니다. 클라이언트는 각 채널에서 마지막으로 받은 offset을 기억합니다. 재연결하여 다시 구독할 때 그 offset을 전송하면, 서버는 그보다 새로운 모든 메시지를 해당 연결 하나에 재생합니다. 순서대로, 중복 없이 말입니다.
클라이언트가 offset을 보유하므로 관리해야 할 서버 측 세션이 없습니다. 복구는 그저 평범한 재구독일 뿐입니다.
서버에서 히스토리 활성화하기
히스토리는 sgc 프로토콜 서버의 History 옵션 객체 아래에 있습니다. 이를 켜고 메시지 개수 및/또는 보존 기간으로 한정하십시오:
uses
sgcWebSocket, sgcWebSocket_Protocols;
var
oProtocol: TsgcWSPServer_sgc;
begin
oProtocol := TsgcWSPServer_sgc.Create(nil);
oProtocol.Server := oServer;
oProtocol.History.Enabled := True;
oProtocol.History.Size := 1000; // keep the last 1000 messages per channel
oProtocol.History.TTLSeconds := 3600; // optional: also drop entries older than 1 hour
end;
Size는 채널별 메모리를 제한합니다(이는 과거에 무한정이었던 큐도 한정합니다). TTLSeconds는 선택적인 보존 기간 제한입니다. 히스토리가 비활성화된 경우(기본값) 전송 경로에 offset이 없으며 동작상의 변화도 전혀 없습니다.
클라이언트에서 자동 복구
클라이언트가 offset을 대신 추적합니다. 재연결 후에는 평범한 Subscribe만으로 해당 채널에서 놓친 내용을 재생해 달라고 서버에 자동으로 요청합니다 — 무엇도 추적하거나 전달할 필요가 없습니다:
// On (re)connect, just resubscribe. The client auto-sends the last offset it saw,
// and the server replays the messages published while the client was offline.
sgcWSPClient_sgc1.Subscribe('news');
// Or request the full retained history explicitly (cursor 0 = everything kept):
sgcWSPClient_sgc1.Subscribe('news', 0);
채널별 offset 맵은 연결 끊김 후에도 유지되므로, 재연결하여 다시 구독하기만 하면 됩니다. GetLastOffset('news')는 커서를 표시하거나 영구 저장하고 싶을 때 이를 노출합니다.
.NET
매니지드 에디션은 동일한 API를 그대로 따릅니다. 서버 프로토콜에서 히스토리를 활성화하면 클라이언트는 재구독 시 복구합니다:
var protocol = new TsgcWSPServer_sgc { Server = server };
protocol.History.Enabled = true;
protocol.History.Size = 1000;
protocol.History.TtlSeconds = 3600;
// Client: a plain resubscribe after reconnect recovers the missed messages.
client.Subscribe("news");
long last = client.GetLastOffset("news");
옵트인 방식이며 기본적으로 안전
히스토리는 기본적으로 비활성화입니다. 비활성화 상태에서는 게시되는 프레임에 offset이 실리지 않고, 게시/구독 경로도 이전과 바이트 단위로 동일합니다 — 따라서 업그레이드를 해도 명시적으로 활성화하기 전까지는 아무것도 바뀌지 않습니다. 활성화하면 한정 링이 메모리를 예측 가능하게 유지합니다.
멀티 노드 클러스터에서 이번 릴리스의 히스토리는 노드 로컬입니다. 동일한 노드로 재연결하는 클라이언트는 완전한 재생을 받습니다. 클러스터 전체에 공유되는 히스토리는 로드맵에 있습니다. 바로 실행할 수 있는 데모가 라이브러리와 함께 제공됩니다(Delphi에서는 02.WebSocket_Protocols\15.MessageHistory_Recovery, .NET에서는 samples\HistoryRecoveryDemo). 이 데모는 클라이언트를 오프라인으로 만들고, 자리를 비운 동안 메시지를 게시한 뒤, 클라이언트를 재연결시켜 놓친 메시지를 정확히 복구하는 모습을 보여줍니다.
제공 범위
메시지 히스토리와 재연결 복구는 Delphi 7부터 13까지(Win32/Win64, Linux64, macOS, Android 및 iOS) 그리고 매니지드 .NET 에디션에서 sgc 프로토콜로 제공됩니다. sgcWebSockets 클라이언트가 이미 갖추고 있는 WatchDog 자동 재연결과 자연스럽게 어우러집니다.
활성 구독을 보유한 고객은 고객 영역에서 새 빌드를 다운로드할 수 있습니다. 체험판 사용자는 esegece.com/products/websockets/download에서 업데이트된 설치 프로그램을 받을 수 있습니다.
질문, 피드백이 있거나 앱에 복구 기능을 연결하는 데 도움이 필요하신가요? 문의하기 — 코드를 작성한 사람들로부터 직접 답변을 받으실 수 있습니다.
