AI Agent Relay Protocol
이 문서는 외부 ai-node-agent가 AWS public relay와 통신하는 표준 계약을 정의합니다.
목표는 다음 세 가지입니다.
- 외부 노드가
backend주소나 AWS private Redis 주소를 직접 알지 않도록 한다. local backend,dev backend가 기존처럼 동일한 shared Redis를 보면서도, 외부 노드는 relay 하나만 바라보게 만든다.- 고빈도 실시간 이벤트와 저빈도 확정 상태를 분리하여, 네트워크 비용과 구현 복잡도를 동시에 낮춘다.
1. 전제
- 외부
ai-node-agent는 shared Redis에 직접 연결하지 않는다. - 외부
ai-node-agent는 단일 public relay 주소만 알고 있다. - relay는 외부 노드로부터 받은 메시지를 shared Redis의 기존 키/채널 모델에 맞게 정규화한다.
local backend,dev backend는 기존처럼 shared Redis를 읽는다.
핵심 구조는 아래와 같습니다.
ai-node-agent
-> public relay (WebSocket + HTTP)
-> shared Redis
-> local/dev backend
2. 역할 분리
relay와의 통신은 성격에 따라 세 가지 plane으로 나눕니다.
2.1 Realtime Plane
- 대상:
heartbeat,progress,executing,node.monitor - 특성: 고빈도, 최신값 위주, 일부 중복 허용
- 권장 transport: WebSocket
2.2 Durable Status Plane
- 대상:
- 1차:
post_processing,failed,processing_failed - 2차:
completed,artifact_registered
- 1차:
- 특성: 저빈도, 유실되면 안 됨, 멱등성 중요, DB authoritative
- 권장 transport: HTTP
중요한 점은 durable status plane이 단순히 Redis에 상태를 쓰는 통로가 아니라, backend 도메인 서비스가 DB 상태 전이를 확정하는 plane이라는 점입니다.
여기서 artifact_registered는 개념적 이름이고, 현재 코드베이스의 wire-level 이벤트명은
creation_result_added입니다. 즉 문서에서 말하는 artifact_registered는
결과물 1개가 DB/스토리지 기준으로 등록된 순간을 뜻하며, 현재 구현에서는
creation_result_added로 fan-out 됩니다.
2.3 Control Plane
- 대상:
CANCEL_JOB,WARMUP_UPDATE, 향후DRAIN_NODE,PAUSE_NODE - 특성: relay가 agent에게 push 해야 함
- 권장 transport: WebSocket
3. 단일 허브 원칙
현재 단계에서는 Redis나 relay를 물리적으로 여러 개로 나누지 않습니다.
- Redis: 단일 shared Redis 유지
- Relay: 단일 public relay 유지
대신 논리적으로만 분리합니다.
- node presence
- job events
- control commands
이유는 다음과 같습니다.
- 외부 노드 설정을 단순하게 유지할 수 있다.
local/devbackend가 동일한 중앙 상태를 그대로 볼 수 있다.- heartbeat/progress/control을 서로 다른 처리 우선순위로 다룰 수 있다.
4. Transport 선택 기준
4.1 WebSocket으로 보내는 것
heartbeatprogressexecutingnode.monitor- relay -> agent 방향의
command - agent -> relay 방향의
command_ack
4.2 HTTP로 보내는 것
post_processingfailedprocessing_failedcompletedartifact_registered(creation_result_added와 동일 개념)- 재시도와 멱등성이 필요한 저빈도 이벤트
5. WebSocket 계약
5.1 연결
agent는 부팅 시 relay에 agent 전용 WebSocket 1개를 엽니다.
연결 시 최소한 아래 정보를 식별 가능하게 전달해야 합니다.
nodeIdagentVersioncapabilitiesenvironments- 인증 토큰
예시 개념:
{
"type": "hello",
"nodeId": "api-node-agent-01",
"agentVersion": "2026.04.08",
"capabilities": ["image", "video", "monitoring"],
"environments": ["local", "dev"]
}
relay는 연결 성공 시 ack를 반환합니다.
{
"type": "hello_ack",
"nodeId": "api-node-agent-01",
"sessionId": "relay-session-uuid"
}
5.2 WebSocket 메시지 타입
heartbeat
노드 생존 여부 및 현재 기본 상태를 나타냅니다.
{
"type": "heartbeat",
"nodeId": "api-node-agent-01",
"status": "waiting",
"occurredAt": "2026-04-08T10:15:30.000Z"
}
job_event
고빈도 실시간 작업 이벤트입니다.
{
"type": "job_event",
"eventType": "progress",
"env": "dev",
"creationId": "uuid",
"userId": "uuid",
"nodeId": "api-node-agent-01",
"sequence": 12,
"occurredAt": "2026-04-08T10:15:31.200Z",
"payload": {
"progress": 42,
"max": 100,
"comfyPromptId": "uuid",
"node": "ksampler"
}
}
eventType 후보:
progressexecutingexecution_successpreview
node_monitor
노드 자원 상태를 전달합니다.
{
"type": "node_monitor",
"nodeId": "api-node-agent-01",
"occurredAt": "2026-04-08T10:15:32.000Z",
"payload": {
"cpuPercent": 21.5,
"ramPercent": 43.1,
"gpuUtilPercent": 88,
"gpuMemoryPercent": 61.2,
"diskPercent": 57.0
}
}
command_ack
relay가 내려준 명령을 agent가 수신/처리했음을 알립니다.
{
"type": "command_ack",
"commandId": "uuid",
"nodeId": "api-node-agent-01",
"result": "accepted",
"occurredAt": "2026-04-08T10:15:35.000Z"
}
command
relay가 agent에게 보내는 제어 메시지입니다.
{
"type": "command",
"commandId": "uuid",
"commandType": "CANCEL_JOB",
"env": "dev",
"creationId": "uuid",
"payload": {}
}
6. HTTP 계약
HTTP는 저빈도 확정 상태를 위해 사용합니다.
현재 권장 구현은 다음 두 단계로 나뉩니다.
- 1차:
ai-node-agent가 직접 생성하는 durable 상태를 relay HTTP로 전송post_processingfailedprocessing_failed
- 2차: post-processing/backend가 확정하는 상태를 동일한 durable plane으로 통합
completedartifact_registered(creation_result_added)
권장 엔드포인트는 다음과 같습니다.
POST /v1/agent-relay/job-status
작업의 durable 상태 전이를 relay에 전달합니다.
{
"env": "dev",
"creationId": "uuid",
"userId": "uuid",
"nodeId": "api-node-agent-01",
"status": "post_processing",
"eventType": "post_processing",
"occurredAt": "2026-04-08T10:16:02.000Z",
"idempotencyKey": "creationId:status:sequence"
}
status 후보:
post_processingfailedprocessing_failedcompleted
eventType는 status보다 더 세부적인 실패/후처리 단계를 표현할 때 사용합니다.
예:
processing_failedpost_processing_uploadpost_processing_sync
POST /v1/agent-relay/artifacts
S3 원본 경로나 결과 metadata를 relay에 전달할 때 사용합니다.
{
"env": "dev",
"creationId": "uuid",
"nodeId": "api-node-agent-01",
"artifactType": "raw_output",
"s3Path": "s3://bucket/key",
"occurredAt": "2026-04-08T10:16:03.000Z",
"idempotencyKey": "creationId:artifactType:s3Path"
}
7. Durable Status 처리 원칙
durable status plane은 Redis 업데이트용 HTTP endpoint가 아닙니다. 최종 목표는 relay -> backend domain service -> DB -> Redis projection 흐름을 고정하는 것입니다.
7.1 1차 구현 원칙
ai-node-agent는post_processing,failed,processing_failed를 HTTP로 relay에 전송합니다.- relay는 backend durable service로 전달합니다.
- backend durable service는 기존 도메인 서비스와 연결하여 DB 상태 전이를 수행합니다.
- DB 반영 후에만 Redis
prompt_progress:*와ai-comfyui-events를 projection으로 갱신합니다.
7.2 2차 구현 원칙
completed는 결과 개수/후처리 완료 조건을 기준으로 backend가 확정합니다.artifact_registered는 post-processing worker 또는 backend 내부 서비스가 durable plane으로 전달합니다.- 현재 구현에서는
artifact_registered라는 새 wire 이벤트를 추가하지 않고, 기존creation_result_added를 canonical event로 유지합니다. - 결과 일부가 등록되는 동안
Creation.status는POST_PROCESSING을 유지하고, 필요한 결과가 모두 등록되었을 때만COMPLETED로 전이합니다. - 즉
completed는 1차부터ai-node-agent가 직접 전송하는 상태로 가정하지 않습니다.
7.3 DB authoritative 원칙
Creation.status가 최종 상태의 authoritative source입니다.- Redis의
prompt_progress:*는 프론트 실시간 표시용 projection입니다. - Redis Pub/Sub는 fan-out 수단이지 durable source가 아닙니다.
7.4 DB 과부하 회피 원칙
- 모든
progresstick을 DB에 쓰지 않습니다. - heartbeat를 DB에 주기적으로 쓰지 않습니다.
- 같은 상태에 대한 중복 HTTP 요청은 멱등하게 처리합니다.
updatedAttouch는 상태 전이가 필요한 시점에만 최소화합니다.- 결과물 저장은 이미 필요한
creation_resultsinsert/update로 한정합니다.
7.5 현재 구현 상태
- 1차 durable plane:
post_processing,failed,processing_failed는ai-node-agent -> relay HTTP -> backend domain service -> DB -> Redis projection으로 구현되었습니다.
- 2차 durable plane:
completed는 backendCreationResultsService가 결과 개수 기준으로 확정합니다.- 결과 일부 등록 시 상태는
PROCESSING으로 되돌아가지 않고POST_PROCESSING을 유지합니다. - 결과 등록 fan-out 이벤트는 현재
creation_result_added이름으로 유지합니다.
- 남은 작업:
- post-processing worker를 포함한 end-to-end 검증
8. 공통 이벤트 envelope
WebSocket/HTTP 모두 아래 공통 필드를 유지하는 것이 좋습니다.
envnodeIdcreationId(job scoped인 경우)userId(가능하면 포함)occurredAtsequenceidempotencyKeypayload
이 필드를 유지해야 relay가 다음 처리를 안정적으로 수행할 수 있습니다.
- 중복 제거
- 순서 역전 방지
- 늦게 도착한 progress discard
- env 라우팅
- 장애 분석
9. Redis Adapter 규칙
relay는 shared Redis의 기존 모델을 최대한 유지합니다.
9.1 Node Presence
agent_heartbeat:{nodeId}nodes:knownnodes:active:last_seen
9.2 Job State / Lookup
prompt_progress:{creationId}comfy_id_map:{comfyPromptId}필요 시 유지prompt_outputs:{creationId}필요 시 유지
9.3 Pub/Sub
ai-comfyui-events
relay는 외부 agent가 보낸 이벤트를 정규화한 뒤 ai-comfyui-events로 발행합니다.
backend는 기존처럼 이 채널을 구독하여 프론트엔드에 fan-out 합니다.
durable status plane의 경우에도 Redis는 projection 역할을 유지합니다. 즉, DB 상태가 먼저 갱신된 뒤 Redis projection이 뒤따르는 것을 원칙으로 합니다.
10. Multi-backend 동작 원칙
이 시스템은 local backend와 dev backend가 동시에 존재하는 것을 전제로 합니다.
공통으로 보여야 하는 것
- node presence
- heartbeat
- node.monitor
- 현재 노드가
waiting인지processing인지
작업별로 분리되어야 하는 것
- 특정
creationId의 progress completed,failed,post_processing- artifact metadata
즉, relay/Redis 모델은 아래 원칙을 지켜야 합니다.
- node plane: 양쪽 backend가 같이 본다.
- job plane:
env,creationId,userId기준으로 각 backend가 필터링한다.
11. 신뢰성 규칙
relay는 단순 프록시가 아니라 정규화 계층입니다. 최소한 아래 규칙이 필요합니다.
11.1 Heartbeat
- latest timestamp 기준 갱신
- TTL 관리
- heartbeat path는 가장 가볍고 빠르게 처리
11.2 Progress
sequence또는occurredAt기준 최신값만 반영- 늦게 도착한 progress는 버린다
- 동일 progress 값은 dedup 가능
11.3 Durable Status
idempotencyKey기반 재시도 허용completed이후 늦게 온 progress는 무시failed와completed의 충돌 규칙을 명시- 같은
Creation.status에 대한 반복 업데이트는 no-op 처리 - DB 상태 변경과 Redis projection 발행의 순서를 고정
11.4 Reconnect
- agent는 relay 연결이 끊기면 자동 재연결
- 재연결 후
hello와 현재 상태를 재전송 - 필요 시 마지막 미반영 durable event를 재시도
12. 보안 원칙
- relay는 HTTPS/WSS만 허용
- 최소한 agent 전용 토큰 인증 필요
- 가능하면 노드별 자격 증명 분리
- rate limit 적용
- 필요 시 IP allowlist 또는 mTLS 검토
중요한 점은, relay는 public endpoint이지만 Redis는 여전히 private이어야 한다는 것입니다.
13. 구현 우선순위
Phase 1
- WebSocket:
heartbeat,progress,node.monitor - HTTP:
post_processing,failed,processing_failed - relay -> Redis adapter
- backend는 기존 Redis 소비 로직 유지
- realtime plane은 이 단계에서 완료로 본다
Phase 2
- durable status를 DB authoritative 모델로 고정
completed,artifact_registered(creation_result_added)를 backend/post-processing 흐름에 통합- Redis는 projection/cache 역할로 정리
Phase 3
- relay -> agent control command push
CANCEL_JOB,WARMUP_UPDATEcommand_ack
Phase 4
- dedup / backpressure / batching 고도화
- preview 이미지 처리 최적화
- extreme scale 시 relay 내부 worker 분리 검토
14. 결론
이 프로토콜의 핵심은 다음 다섯 가지입니다.
- 외부 노드는 backend 주소와 Redis 주소를 알 필요가 없다.
- shared Redis는 유지하되, 외부 노드는 Redis에 직접 붙지 않는다.
heartbeat/progress/control과durable status는 transport를 분리한다.- durable status의 최종 진실은 DB이고, Redis는 projection으로 유지한다.
- 물리적 분리보다 단일 relay + 단일 shared Redis + 논리적 역할 분리를 우선한다.