- Archive provider-resource-admission-ownership milestone/SDD - Align contract: CP-edge wire, runtime refresh, node runtime, OpenAI surface - Update roadmap: phase state, priority queue - Update specs: control-plane ops, OpenAI surface, edge execution, provider pool refresh - Add node runtime supervisor bootstrapping and unit tests - Fix control-plane edge registry handler and http_views - Fix edge model queue admission and long context queue tests
16 KiB
16 KiB
| spec_doc_type | spec_id | status | source_evidence | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| spec | runtime/edge-node-execution | 부분 |
|
스펙: Edge-Node 실행 경로
목적
Edge와 Node 사이에 현재 구현된 실행 기능을 기능 단위로 정리한다. 코드 배치 규칙이나 도메인별 작업 지침은 domain rule을 따른다.
기능 목록
| 기능 | 설명 |
|---|---|
| Node token 등록과 dispatch-ready | Node가 RegisterRequest.token으로 ownership/config를 받고, config 적용·adapter start·handler 설치 뒤 NodeReadyRequest/ack로 dispatch-ready가 된다. |
| Node config payload 전달 | Edge가 token에 매칭되는 node record를 찾아 NodeConfigPayload를 RegisterResponse에 담아 내려준다. |
| 등록 실패 처리 | unknown token, duplicate connection, config payload build failure를 register response와 node lifecycle event로 표현한다. |
| 실행 요청 전달 | Edge service가 SubmitRun 요청을 RunRequest로 만들어 선택된 Node에 보낸다. 명시 node가 없고 연결 node가 1개면 single-node fallback을 사용한다. |
| adapter 실행 | Node가 RunRequest.adapter로 adapter instance를 찾고 adapter Execute를 호출한다. admission은 adapter Capabilities().MaxConcurrency 기준이다. |
| 실행 이벤트 스트림 | Node adapter가 낸 start, delta, reasoning_delta, complete, error, cancelled 이벤트를 RunEvent로 Edge에 relay한다. |
| provider raw tunnel | Edge가 ProviderTunnelRequest를 보내면 Node가 provider HTTP/SSE response를 열고 ordered ProviderTunnelFrame으로 status/header/body/end/error/usage 후보를 relay한다. |
| mixed provider dispatch wire | provider-pool model group은 Edge service에서 provider를 먼저 선택한 뒤 OpenAI-compatible provider에는 ProviderTunnelRequest, Ollama/CLI/native provider에는 normalized RunRequest를 보낸다. |
| provider resource lease | 여러 model key가 같은 provider를 참조해도 Edge가 node_id + provider_id lease에서 일반·long capacity를 합산하고 terminal/send 실패/disconnect가 lease를 정확히 한 번 반환한다. |
| Node connectivity supervision | 단일 supervisor가 retryable initial connect 실패와 established-session disconnect를 같은 reconnect policy로 처리하고 local shutdown, fatal 오류, 유한 exhaustion만 terminal로 구분한다. |
| disconnect/reconnect fencing | current dispatch-ready owner의 generation만 provider를 offline/excluded로 만들고 queue를 재평가하며, reconnect ready는 새 generation candidate와 기존 waiter를 즉시 복구한다. |
| adapter-local capacity guard | Node의 normalized 실행과 provider tunnel 실행은 같은 stable adapter instance capacity gate를 공유해 Edge admission 우회 실행도 backend 한도를 넘지 않는다. |
| usage breakdown relay | RunEvent.usage와 ProviderTunnelFrame.usage는 provider가 보고한 input/output/reasoning/cached input token count를 Edge 관측 계층으로 전달한다. |
| terminal event 합성 | adapter가 terminal event 없이 종료하면 Node가 terminal event를 합성한다. |
| run cancel | Edge가 CancelRequest를 보내면 Node run manager가 active run context를 cancel한다. |
| logical session 종료 | adapter가 SessionTerminator를 구현한 경우 TERMINATE_SESSION으로 session을 종료한다. 모든 adapter 공통 기능은 아니다. |
| Node command | capabilities, transport status, usage status, session list, ollama API 계열 조회/제어성 command를 실행 요청과 분리해 처리한다. |
| Node local run store | Node가 run id, adapter, target, session id, background, status, timestamps, error를 SQLite에 기록한다. |
| Edge event fanout | Edge event bus가 run event와 node lifecycle event를 in-process subscriber에게 fanout한다. |
범위
- 포함: Edge-Node TCP/protobuf transport, register handshake, run/cancel/command, provider raw tunnel, Node adapter execution, Edge event bus fanout, Node local run store.
- 제외: OpenAI-compatible/A2A HTTP request shape, Control Plane 운영 wire, provider-pool config refresh 상세, durable global history/audit.
주요 흐름
Node 등록
sequenceDiagram
participant Node
participant EdgeTransport as Edge transport
participant NodeStore as Edge NodeStore
Node->>EdgeTransport: TCP connect
Node->>EdgeTransport: RegisterRequest(token)
EdgeTransport->>NodeStore: token으로 NodeRecord 조회
alt token valid
EdgeTransport->>EdgeTransport: NodeConfigPayload 생성, pending ownership claim
EdgeTransport-->>Node: RegisterResponse(accepted=true, config)
Node->>Node: config 적용, adapter start, session handler 설치
Node->>EdgeTransport: NodeReadyRequest(node_id)
EdgeTransport->>EdgeTransport: current owner를 dispatch-ready로 전환
EdgeTransport->>EdgeTransport: provider availability 활성화, queued waiter pump, connected event
EdgeTransport-->>Node: NodeReadyResponse(ready=true)
else token invalid or duplicate
EdgeTransport-->>Node: RegisterResponse(accepted=false, reason)
end
Node process는 이 handshake 바깥에서 단일 connectivity supervisor를 실행한다. retryable initial dial/register 실패와 session disconnect는 같은 bounded cadence로 재시도하고, 명시적 reconnect.max_attempts=0은 local shutdown까지 unlimited로 동작한다.
실행 요청과 이벤트
sequenceDiagram
participant Caller
participant EdgeService as Edge service
participant EdgeTransport as Edge transport
participant Node
participant Adapter
Caller->>EdgeService: SubmitRun(adapter, target, input)
EdgeService->>EdgeService: Node 선택
EdgeService->>EdgeTransport: RunRequest
EdgeTransport->>Node: RunRequest
Node->>Node: adapter instance resolve
Node->>Adapter: Execute(spec)
Adapter-->>Node: RuntimeEvent(delta/start/complete)
Node-->>EdgeTransport: RunEvent
EdgeTransport-->>Caller: run stream
Provider raw tunnel
sequenceDiagram
participant OpenAI as Edge OpenAI surface
participant EdgeService as Edge service
participant Node
participant Provider
OpenAI->>EdgeService: SubmitProviderTunnel
EdgeService->>Node: ProviderTunnelRequest
Node->>Provider: HTTP/SSE request
Provider-->>Node: status/header/body
Node-->>EdgeService: ProviderTunnelFrame sequence
EdgeService-->>OpenAI: request-bound frame stream
취소와 session 종료
sequenceDiagram
participant EdgeService as Edge service
participant Node
participant Adapter
alt cancel run
EdgeService->>Node: CancelRequest(CANCEL_RUN, run_id)
Node->>Node: active run context cancel
else terminate session
EdgeService->>Node: CancelRequest(TERMINATE_SESSION, adapter, target, session_id)
Node->>Adapter: TerminateSession(target, session_id)
end
계약
iop.edge-node-runtime-wire:agent-contract/inner/edge-node-runtime-wire.md- proto 원문:
proto/iop/runtime.proto
설정/데이터/이벤트
- Edge의 node source of truth는
configs/edge.yaml과packages/go/config의nodes[]구조다. - accepted registration은 duplicate ownership claim과 config 전달만 담당한다. ready ack 전 Node는 direct/provider-pool dispatch, provider tunnel/command, config refresh push, connected snapshot/event에서 제외된다.
- Edge registry의 connection generation은 internal fence이며 wire/config로 노출하지 않는다. current client의 첫 ready만 provider resource activation과 queue pump를 수행하고, duplicate ready는 idempotent ack, stale/rejected ready는 reject로 처리한다.
- current owner disconnect는 event bus와 분리된 authoritative service 경로에서 해당 generation의 provider lease를 exactly-once 반환하고 resource를 offline으로 fence한 뒤 모든 model group waiter를 live candidate로 재평가한다. 후보가 없어진 waiter는 queue timeout을 기다리지 않고 unavailable로 끝난다.
- configured Node/provider는 연결이 끊겨도 snapshot catalog에서 사라지지 않는다. Node는
connected=false, enabled provider는status=unavailable,health=offline, effective capacity/counter 0으로 보이며 ready reconnect 뒤 새 generation의 configured capacity가 복구된다. reconnect.max_attempts생략은10, 명시적0은 unlimited, 양수는 유한 limit이다. unlimited mode는 양수interval_sec가 필요하고 생략값은10이다. fatal config/credential 오류와 유한 exhaustion은 non-zero terminal, local shutdown은 정상 종료다.RunEvent는 adapter execution stream이고,EdgeNodeEvent는 node lifecycle/control event다.ProviderTunnelFrame.body는 OpenAI-compatible provider passthrough의 source of truth이며RunEvent.delta나 Edge event bus payload로 보내지 않는다.ProviderTunnelFrame.usage와metadata는 관측 후보이며 pure passthrough body에 합쳐지지 않는다.- provider-pool mixed dispatch에서
ProviderTunnelRequest와RunRequest중 어느 wire를 사용할지는 selected provider capability에서 파생되며, client request metadata selector로 결정하지 않는다. Usage.reasoning_tokens와Usage.cached_input_tokens는 provider가 별도 보고한 경우에만 채워지는 optional breakdown이다.- Node local DB는 기본
file:iop.db?cache=shared&mode=rwc로 열린다. - heartbeat는 Edge와 Node transport 양쪽에서 2초 interval, 5초 wait 기준을 사용한다. 정상적인 프로세스·OS 종료는 transport close로 즉시 감지하고, heartbeat timeout은 종료 신호가 오지 않는 전원 차단·네트워크 단절의 fallback으로 사용한다.
검증
go test ./apps/edge/internal/transport ./apps/edge/internal/service ./apps/edge/internal/nodego test ./apps/node/internal/transport ./apps/node/internal/node ./apps/node/internal/router ./apps/node/internal/adapters ./apps/node/internal/storego test ./apps/node/internal/adapters/openai_compat ./apps/node/internal/adapters/vllmgo test ./apps/edge/internal/bootstrap -run '^TestActualNodeReconnectReadyPumpsQueuedWaiterExactlyOnce$'- 실제iop-node재연결 뒤 기존 provider-pool waiter의 dispatch 1회, terminal 1회, counter 0 수렴을 확인한다../scripts/e2e-provider-capacity-smoke.sh- loopback provider에서 두 model alias가 capacity 1 resource를 공유하고 final normal/long counter가 0으로 회복하는지 확인한다.make test-e2e- Edge-Node와 OpenAI 보조 smoke를 함께 실행한다. runtime path 변경 시 사용자 흐름 검증을 대체하지 않는다.
한계와 주의사항
- mTLS helper는 존재하지만 현재 Edge-Node transport 설정에는 연결되어 있지 않다.
TERMINATE_SESSION은 모든 adapter에 공통으로 보장되는 기능이 아니다.- Node store는 전역 query/audit API가 아니다. 상위 운영 이력은 별도 설계가 필요하다.
- provider raw tunnel은 기존 socket 위 request-bound stream이다. 별도 Node stream server나 Edge의 provider direct access 경로가 아니다.
- usage breakdown은 provider-reported 값만 전달한다. provider가 보고하지 않은 reasoning token을 Node나 Edge가 추정하지 않는다.
변경 기록
- 2026-07-07: 현재 코드, 계약, README 기준으로 bootstrap spec 작성.
- 2026-07-07: 기능 목록 중심으로 축소하고 주요 흐름을 Mermaid sequence diagram으로 정리.
- 2026-07-08: Provider raw tunnel 실행 흐름과 passthrough event/data 경계를 현재 계약 기준으로 반영.
- 2026-07-10:
RunEvent.usage/ProviderTunnelFrame.usage의 input/output/reasoning/cached input breakdown 전달 기준을 반영. - 2026-07-12: Model Group Mixed Provider Dispatch 종료 검토 기준으로 selected provider capability에서 파생되는
ProviderTunnelRequest/RunRequest분기 경계를 반영. - 2026-07-18: 저장소 구조 분해 뒤 Edge run/tunnel, Node handler, adapter split test의
source_evidence를 현재 경로로 동기화. - 2026-07-22: accepted registration을 pending ownership/config 단계로 제한하고, handler 설치 뒤
NodeReadyRequest/ack로 dispatch eligibility와 reconnect waiter pump를 여는 순서를 반영. - 2026-07-22: provider resource lease, connection generation fencing, initial/장기 reconnect supervision, offline snapshot과 adapter-local capacity guard를 현재 구현·계약·회귀 테스트 기준으로 동기화.