갱신 버튼을 눌러 응답을 받았어도 자료 자체가 새로워졌는지는 따로 확인해야 한다. 원본 값에 붙은 시각과 서버가 그 값을 받은 시각, 화면이 다시 요청한 시각은 서로 다를 수 있다. 한 시세 프로그램의 서버와 화면 연결을 읽으면서 이 세 가지를 구분했다.

출발점은 늦게 받는 시장 자료도 실시간이라고 볼 수 있느냐는 질문이었다. 연결 성공과 고정 데모는 초기 단계의 기록이고, 집필 때 본 안내문과 소스는 들어온 자료로 가상 계산을 이어 가는 구조였다. 여기서는 계산 성과 대신 자료의 시각이 전달되고 표시되는 과정을 다룬다.

원본 시각과 수신 시각을 먼저 나란히 놓는다

정상 서버 경로에서 asOf는 선택한 시세 자료의 시각이고, fetchedAt은 서버가 공급자 응답을 받은 뒤 기록한 시각이다. 응답을 늦게 받았다고 원본 자료의 시각이 그때로 바뀌지는 않는다. 수신 시각만 보여 주면 오래된 원본도 방금 생긴 자료처럼 읽힐 수 있다.

확인한 화면 코드는 수신 상태와 별도로 시세 기준 시각과 지연 설명을 표시한다. 요청이 실패해 같은 시장의 이전 자료를 남길 때에는 최근 수신값·재연결 중이라는 상태를 사용한다. 숫자가 남아 있다는 사실과 새 요청이 성공했다는 사실을 함께 읽게 한 구조다.

필드 이름만으로 출처가 보장되지는 않는다. 화면 어댑터는 응답에 fetchedAt이 없으면 현재 시각을 대신 넣는다. 따라서 그 필드가 항상 서버가 남긴 원본 수신 기록이라고 설명할 수는 없다. 값을 전달한 정상 경로와 빠진 값을 채우는 경로도 확인해야 한다.

코드와 구현 살펴보기

시각 관계의 합성 예시 · 실제 시세 기록 아님

Synthetic timing example, not a captured market response
source asOf    = 12:00
server fetchedAt = 12:03
screen refresh = 12:04
A refreshed response alone does not move source asOf to 12:04.

캐시 표시에도 서로 다른 재사용 경로가 있다

서버의 캐시 설정은 30초이고 화면의 정기 요청 설정은 60초다. 캐시가 유효하면 저장해 둔 값을 반환한다. 그때 fetchedAt도 그 값과 함께 남아 있으므로 새로운 HTTP 응답마다 방금 시각으로 바꾸지 않는다. 원본 자료를 언제 받았는지 추적할 수 있는 단서가 유지된다.

cached가 참인 경우가 모두 오래 보관한 응답을 뜻하지는 않는다. 같은 키의 조회가 이미 진행 중이면 그 요청의 결과를 기다려 함께 돌려주는 분기도 cached를 참으로 둔다. 이 값은 현재 코드에서 재사용 경로를 알려 주지만 실제 원본의 나이나 조회 지연을 혼자 설명하지는 못한다.

이 두 주기는 코드의 설정값이다. 실제 화면의 요청 간격을 재어 얻은 수치나 자료가 반드시 정해진 시간 안에 도착한다는 약속은 아니다. 30초와 60초를 더해 전체 지연의 상한을 만들지도 않았다. 원본의 시각과 실제 요청 결과를 함께 확인해야 한다.

목록의 대표 시각 하나로 모든 항목을 최신이라고 부르지 않는다

서버는 선택한 항목들의 유효한 원본 시각에서 가장 늦은 값을 asOf로, 가장 이른 값을 oldestAsOf로 만든다. 종목별 원본 시각이 같다는 가정을 두지 않은 것이다. 대표 시각이 최근이어도 다른 항목은 더 오래된 자료일 수 있다.

화면 어댑터는 oldestAsOf가 있으면 그것을 우선해 기준 시각으로 쓰고, 없으면 응답의 asOf나 항목의 가장 늦은 시각을 사용한다. 오래된 쪽을 표시하려는 선택과 대체 경로를 함께 읽어야 했다. 모든 항목의 시각이 확인되었다는 보증은 아니다.

서버 집계에서는 비어 있거나 유효하지 않은 시각을 뺀다. 따라서 대표 시각이 있어도 시각 없는 항목까지 확인된 것은 아니다. 비슷한 목록을 만든다면 집계 방식과 시각이 빠진 항목을 함께 표시하는 편이 낫다.

다시 받은 같은 자료가 새 계산으로 이어지지 않게 한다

가상 계산 엔진의 스냅샷 키는 종목과 원본 시각으로 만들어지고, 서버 수신 시각은 키에서 제외된다. 처리 기록에 같은 키가 남아 있으면 같은 스냅샷을 다시 계산하지 않고 기존 장부를 반환한다. 응답을 다시 받았다는 이유만으로 같은 입력의 가상 체결을 늘리지 않으려는 구분이다.

이 경로는 입력으로 받은 관측 시각과 원본 시각의 차이를 비교하고, 이전에 받은 자료보다 시각이 뒤로 가지 않는지도 검사한다. 매 요청의 현재 벽시계를 기준으로 최신성을 확인하는 방식은 아니다. 화면이 전달한 시각과 엔진이 비교하는 값을 따라가야 이 차이를 알 수 있다.

기존 시험에는 같은 스냅샷을 다시 넣었을 때 같은 장부를 돌려주는 조건과, 오래된 자료가 평가값을 뒤로 돌리지 않는 조건이 있다. 이번에는 시험 정의를 읽었고 원제품 검사나 시세 수신을 실행하지 않았다. 처리 기록의 범위를 벗어난 모든 재실행까지 영구히 한 번만 처리한다고 주장하지도 않는다.

표시 지연 0분과 실시간 보장을 같은 문구로 쓰지 않는다

현재 지연 문구 함수는 유한한 지연 값이 없으면 지연 여부를 확인할 수 없다고 표시한다. 0 이하인 값에는 표시 지연 0분과 실시간 보장이 아니라는 설명을 함께 붙인다. 공급자 메타데이터의 숫자 하나가 전체 연결 방식과 전송 품질을 대신하지 않게 하는 문구다.

서버 응답도 비공식·지연 가능이라는 표기와 함께 틱·호가 자료를 제공하지 않는 기능 범위를 남긴다. 이는 현재 코드가 내보내는 계약이다. 이번 글을 쓰며 공급자의 실제 지연, 현재 장 상태, 서비스 보장이나 실제 거래 연결을 시험한 결과는 아니다.

새로 연결할 업무에서도 값·원본 시각·수신 시각·현재 상태를 한 묶음으로 읽어 볼 수 있다. 갱신이 실패해 남아 있는 값인지, 새 원본을 받은 값인지, 시각이 빠져 대체한 값인지부터 구분하면 화면의 방금이라는 말을 더 정확하게 쓸 수 있다. 자료가 부족할 때 계산을 보류하는 문제는 아래 글에서 이어 다룬다.