Update data calibration and recover stale TCP queue

This commit is contained in:
seo
2026-06-15 19:06:12 +09:00
parent 897dfe97b3
commit 7c2deb9ec1
3 changed files with 79 additions and 2 deletions
+3 -1
View File
@@ -80,6 +80,8 @@ systemctl status car-tcp-worker.service
큐 테이블은 코드에서 자동 생성합니다. Worker가 중지되면 API 요청은 큐에 쌓이지만 4.95초 안에 처리되지 않아 실패로 반환될 수 있습니다. 안전을 위해 worker가 뒤늦게 오래된 queued 요청을 발견하면 실제 TCP 송신 없이 `queue_expired_before_send`로 만료 처리합니다. 큐 테이블은 코드에서 자동 생성합니다. Worker가 중지되면 API 요청은 큐에 쌓이지만 4.95초 안에 처리되지 않아 실패로 반환될 수 있습니다. 안전을 위해 worker가 뒤늦게 오래된 queued 요청을 발견하면 실제 TCP 송신 없이 `queue_expired_before_send`로 만료 처리합니다.
Worker 교체나 예외 종료로 `processing`, `ui_timeout_pending` 상태가 남으면 다음 claim 전에 stale queue를 복구합니다. 전송 전이면 `expired_before_send`, 이미 TCP payload를 보낸 상태면 `settled_sent_only`로 정산해 사용량 누락을 막습니다.
## 주요 함수/모듈 ## 주요 함수/모듈
- `common.php`: secret 로드와 공통 DB/API 함수 - `common.php`: secret 로드와 공통 DB/API 함수
@@ -99,6 +101,6 @@ systemctl status car-tcp-worker.service
- 차량 TCP 실패 reason과 마지막 수신 지연을 확인합니다. - 차량 TCP 실패 reason과 마지막 수신 지연을 확인합니다.
- 명령별 rate limit과 감사 로그를 유지합니다. - 명령별 rate limit과 감사 로그를 유지합니다.
- 통신사 기준 데이터 사용량 보정값을 주기적으로 확인합니다. - 통신사 기준 데이터 사용량 보정값을 주기적으로 확인합니다. 2026-06-15 18:47 T world 실측 66.44MB(68030KB) 기준 2026-06 보정값은 통신사 누적 69,662,720 bytes, 로컬 보정 전 누적 35,100,790 bytes, 배율 1.984648입니다.
- 4.95초 timeout 직후에는 사용량 기록이 즉시 생기지 않을 수 있으며, 최대 60초 뒤 늦은 정산 행이 추가될 수 있습니다. - 4.95초 timeout 직후에는 사용량 기록이 즉시 생기지 않을 수 있으며, 최대 60초 뒤 늦은 정산 행이 추가될 수 있습니다.
- `systemctl status car-tcp-worker.service``journalctl -u car-tcp-worker.service`로 worker 상태를 확인합니다. - `systemctl status car-tcp-worker.service``journalctl -u car-tcp-worker.service`로 worker 상태를 확인합니다.
+75
View File
@@ -284,6 +284,7 @@ function tcp_queue_get(string $requestId): ?array
function tcp_queue_claim_next(PDO $pdo): ?array function tcp_queue_claim_next(PDO $pdo): ?array
{ {
db_ensure_tcp_queue_schema($pdo); db_ensure_tcp_queue_schema($pdo);
tcp_queue_recover_stale($pdo);
$pdo->beginTransaction(); $pdo->beginTransaction();
try { try {
@@ -313,6 +314,80 @@ function tcp_queue_claim_next(PDO $pdo): ?array
} }
} }
function tcp_queue_has_usage(PDO $pdo, string $requestId): bool
{
$stmt = $pdo->prepare("SELECT 1 FROM car_data_usage WHERE request_id = :request_id LIMIT 1");
$stmt->execute([':request_id' => $requestId]);
return (bool)$stmt->fetchColumn();
}
function tcp_queue_recover_stale(PDO $pdo): void
{
$now = microtime(true);
$stmt = $pdo->prepare("
SELECT *
FROM car_tcp_request_queue
WHERE status IN ('processing', 'ui_timeout_pending')
AND usage_deadline_ts > 0
AND usage_deadline_ts < :now
ORDER BY id ASC
LIMIT 20
");
$stmt->execute([':now' => $now]);
$rows = $stmt->fetchAll();
foreach ($rows as $row) {
$requestId = (string)($row['request_id'] ?? '');
if ($requestId === '') {
continue;
}
$sentBytes = max(0, (int)($row['sent_bytes'] ?? 0));
$receivedBytes = max(0, (int)($row['received_bytes'] ?? 0));
$connectMs = max(0, (int)($row['connect_ms'] ?? 0));
$readMs = max(0, (int)($row['read_ms'] ?? 0));
$hasUsage = tcp_queue_has_usage($pdo, $requestId);
if ($hasUsage) {
tcp_queue_update($pdo, $requestId, [
'status' => 'worker_lost_usage_recorded',
'tcp_ok' => 0,
'tcp_error' => 'worker_lost_after_usage_recorded',
]);
continue;
}
if ($sentBytes <= 0) {
tcp_queue_record_usage_and_status(
$pdo,
$row,
'expired_before_send',
0,
0,
false,
'worker_lost_before_send',
'',
$connectMs,
$readMs
);
continue;
}
tcp_queue_record_usage_and_status(
$pdo,
$row,
'settled_sent_only',
$sentBytes,
$receivedBytes,
false,
'worker_lost_late_settlement_sent_only',
'',
$connectMs,
$readMs
);
}
}
function tcp_queue_record_usage_and_status( function tcp_queue_record_usage_and_status(
PDO $pdo, PDO $pdo,
array $job, array $job,
+1 -1
View File
@@ -27,7 +27,7 @@ const RECEIVE_GAP_LIMIT_SEC = 60;
// SKT T world "잔여기본통화 정보" 기준 현재월 누적값. // SKT T world "잔여기본통화 정보" 기준 현재월 누적값.
// carrier_total_bytes / meter_adjusted_bytes 로 보정 배율을 역산해 로컬 송수신 계측값에 적용한다. // carrier_total_bytes / meter_adjusted_bytes 로 보정 배율을 역산해 로컬 송수신 계측값에 적용한다.
const DATA_CURRENT_BILLING_USAGE_BYTES = [ const DATA_CURRENT_BILLING_USAGE_BYTES = [
'2026-06' => ['total_bytes' => 69159936, 'meter_adjusted_bytes' => 34801709, 'included_bytes' => 104857600, 'coupon_registered_at' => null], '2026-06' => ['total_bytes' => 69662720, 'meter_adjusted_bytes' => 35100790, 'included_bytes' => 104857600, 'coupon_registered_at' => null],
]; ];
function car_db(): PDO function car_db(): PDO