명령·정책·보존
장비에 보내는 명령, 장비별 정책, 오프라인 동안 누적된 데이터의 보존과 동기화
필요 권한: 운영OPERATOR · ADMIN
명령
중앙은 NAT 뒤의 현장 장비에 먼저 접속할 수 없으므로, 장비가 commands_poll_s(기본 25초) 동안 대기하는 롱폴로 명령을 가져옴. 장비는 처리한 결과를 반드시 보고(ack)하므로 화면에서 명령 상태가 대기 중 → 전달됨 → 완료/실패 로 전환. 명령 전송에는 운영OPERATOR · ADMIN 권한 필요.
- 디바이스 상세의 명령 탭 선택. ① 명령 종류 선택 후 ② 명령 보내기 클릭.
명령 탭: ① 명령 종류 ② 명령 보내기 ③ 실패한 명령은 장비가 보고한 오류와 함께 기록된다 - 장비가 다음 폴링에서 명령을 가져와 처리, 결과는 결과 열에 기록. ③ 실패한 명령에는 장비가 보고한 오류가 그대로 표시(이 예에서는 아티팩트가 없는 모델 버전을 내려받는 중 발생한 404).
| 명령 | 화면 이름 | 장비 동작 | 결과 예 |
|---|---|---|---|
ping | 핑 | 상태 변경 없이 응답 | {"pong": true, "device_id": "edge-bench-01"} |
restart | 재시작 | 에이전트를 종료 코드 3 으로 종료. 감시자가 재시작. | {"restarting": true} |
resync | 재동기화 | failed 가 된 큐 항목을 다시 대기 상태로 되돌리고 즉시 전송 | {"requeued": 0} |
pull_model | 모델 내려받기 (모델 탭의 배포가 보냄) | 인자 {name, version, activate, deployment_id} 의 모델을 내려받아 활성화. 활성화 실패는 실패 로 보고 | {"name": …, "activated": true, "deployment_id": …} |
activate_model | 모델 전환 (모델 탭이 보냄) | 캐시에 있는 버전으로 전환. 내려받지 않음 | {"name": …, "version": …} |
remove_model | 모델 캐시 삭제 (모델 탭이 보냄) | 캐시에서 그 버전 삭제. 실행 중이면 실패 | {"removed": true} |
set_policy | (정책 저장 시 자동) | 새 정책을 적용 | {"applied": true} |
명령은 기본 24시간 이내에 장비가 가져가지 않거나, 가져간 뒤 24시간 안에 결과를 보고하지 않으면 만료 처리. 에이전트가 실행 중인 동안 같은 명령이 다시 전달되어도 한 번만 실행. 모델 명령 셋은 모델과 추론에 자세히.
재시작은 종료 코드 3
에이전트는 스스로 재실행하지 않음. 문제가 생긴 프로세스가 스스로 복구하도록 두지 않는 설계. restart 를 수신하면 진행 중인 전송을 중단하고 처리 중이던 큐 항목을 되돌린 뒤 종료 코드 3 으로 종료, systemd(Restart=always)나 컨테이너 런타임(restart: unless-stopped)이 초기 상태의 새 프로세스를 기동. 디바이스 상세 오른쪽 위 재시작 버튼도 같은 명령 전송.
로그와 종료 코드:
WARNING geo_mlops_sdk.edge.runtime: restart requested: command 1a1d2559-…
$ echo $?
3
| 종료 코드 | 뜻 |
|---|---|
0 | 요청에 따른 정상 종료(SIGTERM·Ctrl-C) |
3 | 재시작 요청. 감시자가 재시작해야 함. |
4 | 로컬 API 를 시작하지 못함(포트 사용 중 등). 재시작해도 해결되지 않는 설정 문제. |
Offline 차단
디바이스 상세의 Offline 버튼은 명령이 아니라 서버 측 스위치. 활성화된 동안 그 장비의 토큰 호출은 모두 503(Retry-After: 60)으로 거부. 상태 확인(/api/v1/health)은 차단되지 않으므로 장비의 link.state 는 online 그대로이고, 로그에 503 edge device … is blocked by an operator 기록. 업로더는 503 을 일시적 실패로 판단해 항목마다 간격을 늘리며(10초에서 최대 15분) 재전송, 차단 해제 시 누적된 데이터 업로드. 단 차단이 3시간 넘게 이어지면 20번 실패한 항목부터 failed 로 전환. 차단 해제 후 geo-mlops-edge queue --state failed 로 확인하고 재동기화 명령 전송. 토큰 폐기와 달리 화면에서 즉시 되돌리기 가능.
정책
정책으로 하트비트 주기, 명령 폴링 주기, 보존 한도, 전송 조절(retention·sync)을 중앙에서 장비별로 지정. 변경에는 설정ADMIN 권한 필요.
- 디바이스 상세의 정책 탭 선택. ① 현재 리비전 표시. 값을 수정하고 ② 정책 저장 클릭.
정책 탭: ① 현재 리비전 ② 정책 저장 (저장하면 리비전이 증가하고 장비가 다음 하트비트에서 가져온다) - 저장하면 리비전이 1 증가, 즉시 반영되도록
set_policy명령도 함께 큐에 추가. 장비는 하트비트 응답의policy_revision변경을 감지해도 새 정책을 가져옴.
| 화면 항목 | 설정 키 |
|---|---|
| 하트비트 주기 (초) | heartbeat_interval_s |
| 보존 기간 (일) | retention.max_age_days |
| 보존 용량 (GiB) | retention.max_bytes |
| 전송 속도 상한 (B/s) | sync.max_bytes_per_s |
| CPU 일시정지 임계 (%) | sync.cpu_pause_percent |
| 전송 허용 시간대 | sync.windows |
화면에서 수정 가능한 항목은 위 여섯 가지. 나머지(명령 폴링 주기, 디스크 최소 여유, 배치 크기, 청크 크기, concurrency, 긴급 우선순위 기준)는 탭 아래에 읽기 전용으로 표시, 변경하려면 PUT /api/v1/edge/devices/{id}/policy API 사용.
하트비트 주기는 서버의 오프라인 판정 기준(기본 180초)보다 충분히 짧게 설정. 길면 정상 장비가 비정상 과 정상 상태를 반복.
보존: 연결 중단 시에도 데이터 유지
에이전트는 케이블 분리, 정전, 며칠간의 오프라인을 전제로 동작.
- 수집 중단 없음. 수집기는 링크 상태와 무관하게 로컬 큐(SQLite + 파일 스풀)에 기록.
- 한도 안에서 저장.
retention의 세 한도(max_bytes50 GiB,max_age_days30일,free_disk_min_bytes5 GiB) 적용. 기간을 넘긴 항목은 우선순위와 무관하게 삭제, 용량이나 디스크 여유 공간이 부족하면 우선순위가 낮고 오래된 것부터 삭제. 전송 중인 항목은 삭제하지 않음. 삭제한 건수는 하트비트의evicted_24h로 보고되어 플릿 목록 대기(적체 건수) 열에 빨간−N으로 표시. 전송 속도보다 누적 속도가 빠르다는 신호. - 링크 복구 시 즉시 전송. 연속 두 번 연결 확인(
link.online_after_ok)이 되면 등록 → 즉시 하트비트 → 큐 비우기 순으로 동작. 전송은 우선순위가 높은 것부터 진행. - 중복 저장 없음. 레코드 id 가 멱등 키(같은 요청을 여러 번 전송해도 한 번만 저장되게 하는 키)이므로, 응답을 수신하지 못해 같은 묶음을 재전송해도 중앙은
duplicates로 집계하고 한 번만 저장. 파일은 청크 단위로 이어서 업로드.
장비 CPU 사용률이 cpu_pause_percent(기본 85) 이상이면 전송을 일시 중지하고 큐에 저장. 사용률이 내려가거나 한도를 높이면 누적된 항목 전송. 일시 중지 중의 상태는 다음과 같음.
"sync": { "state": "paused", "last_error": "paused: cpu above threshold" },
"backlog": { "count": 7, "bytes": 1150, "by_kind": { "blob": 1, "http": 3, "robot": 3 } }
전송을 조절하는 값은 설정 레퍼런스의 sync 표 참고. 실패(failed) 상태가 된 항목은 geo-mlops-edge queue --state failed 로 확인하고, 재동기화 명령이나 POST /api/v1/sync:retry-failed 로 재전송.