Commands, policy and retention
Commands sent to a device, per-device policy, and retention and sync of data buffered while offline
Required permission: OperateOPERATOR · ADMIN
Commands
Central cannot open a connection to a device behind a factory NAT, so the device fetches commands by long polling, waiting up to commands_poll_s (default 25 seconds). The device always reports (acks) the result, so on screen a command moves through Queued (대기 중) → Delivered (전달됨) → Done (완료) / Failed (실패). Sending commands needs the OperateOPERATOR · ADMIN permission.
- Open the Commands (명령) tab on the device detail page. ① Pick a command type and ② press Send command (명령 보내기).
Commands tab — ① command type ② Send command ③ a failed command keeps the error the device reported - The device picks it up on its next poll and handles it, and the outcome stays in the Result (결과) column. ③ A failed command shows the error exactly as the device reported it (here, a 404 from trying to pull a model version with no artifacts).
| Command | Screen name | What the device does | Example result |
|---|---|---|---|
ping | Ping (핑) | Answers without changing anything | {"pong": true, "device_id": "edge-bench-01"} |
restart | Restart (재시작) | Ends the agent with exit code 3 — the supervisor starts it again | {"restarting": true} |
resync | Resync (재동기화) | Puts queue items folded into failed back into the queue and sends right away | {"requeued": 0} |
pull_model | Pull model (모델 내려받기); a deployment from the Models tab sends it | Pulls and activates the model given by {name, version, activate, deployment_id}. A failed activation is reported as failed | {"name": …, "activated": true, "deployment_id": …} |
activate_model | Switch model (모델 전환); sent by the Models tab | Switches to a cached version without downloading | {"name": …, "version": …} |
remove_model | Remove cached model (모델 캐시 삭제); sent by the Models tab | Removes that version from the cache; fails while it is running | {"removed": true} |
set_policy | (automatic on policy save) | Applies the new policy | {"applied": true} |
A command that is not picked up within 24 hours (the default), or picked up and not answered within 24 hours, becomes Expired (만료). While the agent is running, a command delivered again is still executed only once. The three model commands are described in Models and inference.
Restart means exit code 3
The agent does not re-execute itself. A misbehaving process is not trusted to repair itself. On restart it stops the transfer in progress, returns the claimed queue items and ends with exit code 3, and systemd (Restart=always) or the container runtime (restart: unless-stopped) starts a clean new process. The Restart (재시작) button at the top right of the device detail page sends the same command.
Log and exit code:
WARNING geo_mlops_sdk.edge.runtime: restart requested: command 1a1d2559-…
$ echo $?
3
| Exit code | Meaning |
|---|---|
0 | Stopped on request (SIGTERM, Ctrl-C) |
3 | Restart requested — the supervisor must start it again |
4 | Could not open the local API (port in use and so on) — a config problem that restarting will not fix |
Offline block
The Offline (Offline) button on the device detail page is a server-side switch, not a command. While it is on, every call made with that device's token is rejected with 503 (Retry-After: 60). The health check (/api/v1/health) is not blocked, so the device's link.state stays online and the log shows 503 edge device … is blocked by an operator. The uploader treats a 503 as a temporary failure and retries each item at growing intervals (from 10 seconds up to 15 minutes); when the block is lifted it uploads the backlog. If the block lasts more than 3 hours, however, items that have failed 20 times turn failed. After lifting the block, check with geo-mlops-edge queue --state failed and send the Resync (재동기화) command. Unlike revoking the token, you can undo it right from the screen.
Policy
A policy sets, per device and from Central, the heartbeat interval, the command poll interval, retention limits and upload throttling (retention, sync). Changing it needs the SettingsADMIN permission.
- Open the Policy (정책) tab on the device detail page. ① The current revision is shown. Edit the values and ② press Save policy (정책 저장).
Policy tab — ① current revision ② Save policy (the revision goes up and the device picks it up on its next heartbeat) - Saving raises the revision by 1 and also queues a
set_policycommand so the change applies right away. The device also fetches the new policy when it sees thatpolicy_revisionin the heartbeat response has changed.
| Screen field | Setting key |
|---|---|
| Heartbeat interval (s) (하트비트 주기 (초)) | heartbeat_interval_s |
| Retention period (days) (보존 기간 (일)) | retention.max_age_days |
| Retention size (GiB) (보존 용량 (GiB)) | retention.max_bytes |
| Upload rate limit (B/s) (전송 속도 상한 (B/s)) | sync.max_bytes_per_s |
| CPU pause threshold (%) (CPU 일시정지 임계 (%)) | sync.cpu_pause_percent |
| Allowed upload windows (전송 허용 시간대) | sync.windows |
These six are the fields you edit on the screen. The rest (command poll interval, minimum free disk, batch size, chunk size, concurrency, urgent priority threshold) are shown read-only below them; to change those, use the PUT /api/v1/edge/devices/{id}/policy API.
The heartbeat interval must be well below the server's offline threshold (180 seconds by default). If it is too long, a healthy device flickers to Unhealthy (비정상).
Retention — nothing is thrown away when the link drops
The agent is built to expect pulled cables, power cuts and days offline.
- Collection never stops. Collectors write to the local queue (SQLite + file spool) regardless of link state.
- It buffers within limits. It keeps to the three
retentionlimits (max_bytes50 GiB,max_age_days30 days,free_disk_min_bytes5 GiB). Items past the age limit are dropped regardless of priority; when size or free disk runs short it drops the lowest-priority, oldest items first. Items being sent are never dropped. The number dropped goes up in the heartbeat'sevicted_24hand shows as a red−Nin the Backlog (대기) column of the fleet list — a sign that data is piling up faster than it is sent. - When the link comes back, it sends right away. After two connection checks in a row (
link.online_after_ok) it registers → sends a heartbeat immediately → drains the queue. It sends the highest priority first. - Nothing is stored twice. The record id is an idempotency key, so if a response is lost and the same batch is sent again, Central counts them as
duplicatesand stores them once. Files resume upload chunk by chunk.
When the device's CPU usage reaches cpu_pause_percent (default 85), uploads pause and items stay in the queue. When usage drops or the limit is raised, the queued items are sent. While paused, the state looks like this.
"sync": { "state": "paused", "last_error": "paused: cpu above threshold" },
"backlog": { "count": 7, "bytes": 1150, "by_kind": { "blob": 1, "http": 3, "robot": 3 } }
The values that throttle uploads are in the sync table of the Configuration reference. Check items folded into failure with geo-mlops-edge queue --state failed, and send them again with the Resync (재동기화) command or POST /api/v1/sync:retry-failed.