프로젝트

일반

사용자정보

Actions

이슈 #432

진행중
JL JL

Engine + ConnectNode 포팅 — Synth / Dispatcher / Scheduler / VNodeCreditor + bidi 스트림 완성

이슈 #432: Engine + ConnectNode 포팅 — Synth / Dispatcher / Scheduler / VNodeCreditor + bidi 스트림 완성

James Lee이(가) 약 7시간 전에 추가함.

상태:
해결
우선순위:
보통
담당자:
목표버전:
시작일:
2026/04/17
완료일:
2026/04/17 (약 7달 지연)
진척도:

0%

추정시간:

설명

배경

alphea-ai-edge (Rust) 의 NodeService.ConnectNode 는 protobuf 시그니처만 있고 현재 핸들러는 Status::unimplemented 를 반환한다 (src/handler/node.rs:288-299). 이 RPC 가 작동하려면 legacy Go 프로젝트의 internal/engine/ 트리 전체(2,462 LoC) 를 Rust 로 포팅해야 한다 — 노드 운영 자체가 가능해지는 임팩트 큰 작업이다.

레거시 구성요소:

컴포넌트 파일 LoC 역할
Engine engine.go 170 Synth/Dispatcher/Scheduler/Creditor 통합 + provider adapter
Dispatcher dispatcher.go 381 실 노드(StreamManager) 로 job 라우팅, fallback 시 Scheduler, 타임아웃 sweep, 완료/실패 처리
Synth synth.go 381 합성 job 생성기 (시나리오/burst/rate 제어, scheduler 백프레셔 반영)
Scheduler scheduler.go 489 built-in edge node 시뮬레이터 (실제 노드가 없을 때 fallback 처리)
EdgeNode edge_node.go 68 부트스트랩 시 edge 노드 row 생성/캐시
Job job.go 269 QueuedJob 모델 + 큐 자료구조
RPCBridge rpcbridge.go 62 핸들러 ↔ 엔진 양방향 호출 어댑터
VirtualNodeCreditor virtual_node_creditor.go 151 가상 노드 보유자에게 1분마다 AGX 적립
VirtualNodeStats virtual_node_stats.go 250 가상 노드 메트릭

레거시 노드 도메인 (internal/domain/node/) 의 StreamManager (실 노드 bidi 세션 인덱싱) + RedisBridge (분산 환경에서 stream session 공유) 도 함께 필요.

목표

  • NodeService.ConnectNode bidi 핸들러 작동 — handshake, heartbeat ack, job assign, job complete/fail, balance update push 흐름 full round-trip.
  • 합성 job 이 dispatcher → 실 노드 (또는 Scheduler fallback) → 결과 수신 → DB 적립 + AGX 정산까지 자동 흐름.
  • 가상 노드 보유자에게 1분 cron 으로 AGX 자동 적립.
  • legacy 와 기능 동등하지만 코드 구조는 Rust idiomatic (tokio task, mpsc/broadcast, Arc<Mutex<...>> 최소화).

제외 범위 (별도 이슈)

  • MonitorService server-streaming StreamStats — Engine snapshot 을 소비하는 dashboard. 본 이슈는 snapshot API 까지만, StreamStats 핸들러는 Monitor 이슈에서.
  • AisService edge console exec/shell — 별도 서비스.
  • PoolService, AgxService, FriendsService, VfsService — 본 이슈와 무관.

Phase 분해 (각 Phase 독립 커밋 + 회귀 테스트)

Phase 1 — StreamManager + ConnectNode handshake

범위: 실제 job dispatch 없이 bidi 세션 자체만.

  • src/domain/node/stream.rs — StreamManager (node_id → tx 매핑), 등록/해제, ConnectedCount.
  • src/handler/node.rs::connect_node — 첫 메시지(없음, JWT 의 typ=node 강제) 검증 → ConnectedMsg 송신 → ack/heartbeat loop 처리.
  • node token (typ=node) 강제 — auth_middleware::caller(req)?.token_type == "node" 체크.
  • E2E 시나리오: tools/client.py 의 메뉴 6 (ConnectNode 시뮬) 이 ConnectedMsg 를 받고 heartbeat ack 가 돌아오는지.

Phase 2 — QueuedJob 모델 + Dispatcher 코어

  • src/engine/job.rs — QueuedJob, JobQueue (BinaryHeap-based priority queue).
  • src/engine/dispatcher.rs — Dispatcher::run 루프 (jobCh 수신 → 적합 노드 선택 → JobAssignMsg 송신), handle_job_complete/handle_job_failed 콜백.
  • node → server 메시지가 dispatcher 까지 routing 되도록 wiring.
  • Phase 1 과 결합되어 외부에서 admin REST 로 임의 job 을 enqueue 하면 연결된 노드에 dispatch 되는 흐름까지.

Phase 3 — Synth (합성 job 생성기)

  • src/engine/synth.rs — tick 루프, calculate_job_count, scenario/rate/burst 제어.
  • admin REST /api/engine/synth/{pause,resume,burst,scenario} — Phase 8 의 일부지만 synth 단위에서 미리 노출.
  • backpressure: scheduler queue 크기/active node 수를 callback 으로 읽어 합성률 조절.

Phase 4 — Scheduler (built-in edge fallback)

  • src/engine/scheduler.rs — built-in edge 노드 시뮬레이터. dispatcher 가 실 노드 매칭 실패 시 여기로 fallback.
  • src/engine/edge_node.rs — startup 시 edge 노드 row 보장.
  • 시뮬 결과를 dispatcher 로 push (job_complete) → DB 적립.

Phase 5 — Job 영속화 + AGX 정산

  • job_history row insert on assign, update on complete/fail.
  • job_receipts row + aggregated_earnings (또는 legacy rewards_log) 갱신.
  • BalanceUpdateMsg push to node.
  • 새 마이그레이션이 필요하면 0013_*.sql. DB 변경이라 #254 도 refs 에 포함 필수.

Phase 6 — 타임아웃 sweep + 취소

  • Dispatcher 가 주기적으로 assigned job 의 deadline 초과 검사 → JobCancelMsg 송신, 다른 노드로 reassign 또는 drop.
  • job_history.status = 'TIMED_OUT'.

Phase 7 — VirtualNodeCreditor

  • src/engine/virtual_node_creditor.rs — 1분 tick 으로 가상 노드 보유자에게 AGX 적립.
  • legacy 의 virtual_node_assignments / virtual_node_credits / virtual_node_packages 테이블 미생성 상태 — 마이그레이션 추가 필요 (#254 refs).

Phase 8 — Engine 통합 + admin 컨트롤

  • src/engine/mod.rs — Engine 구조체로 4 컴포넌트 묶고 start(ctx) 에서 tokio task 들 spawn.
  • AppState 에 engine: Arc<Engine> 추가, main.rs 에서 GoTrue/admin server 와 함께 부팅.
  • admin REST API 확장 — engine snapshot, synth/scheduler 컨트롤 (Pause/Resume/SetTick/SetRate/SetScenario/TriggerBurst).
  • Dev Console UI 에 Engine 탭 (snapshot 표시 + 컨트롤 버튼).

DB 변경 예상

  • Phase 5: job_history/job_receipts 가 이미 0001~0005 에 일부 정의되어 있으므로 컬럼 보강 수준. 새 마이그 1개.
  • Phase 7: virtual_node_assignments, virtual_node_credits, virtual_node_packages — 신규 마이그.

→ 두 phase 모두 commit 시 refs 에 #254 포함.

인증

  • Phase 1 에서 auth_middleware::public_path_set() 에 /alphea.v1.NodeService/ConnectNode 추가하지 말 것 — node token 필수.
  • 핸들러 본문에서 caller(&request)? 로 AuthContext 가져와 token_type == "node" 검증.
  • node_id 는 JWT sub 에서 추출 (== caller_user_id).

완료 기준 (DoD — 이슈 전체)

  • Phase 1~8 모든 phase 가 별도 커밋으로 main 에 머지됨.
  • cargo test / cargo clippy --all-targets -- -D warnings 전부 통과.
  • examples/connect_node_roundtrip.rs (또는 tools/client.py 메뉴 6) 시나리오:
    1. 노드 등록 → 토큰 획득 → ConnectNode 연결 → ConnectedMsg 수신
    2. admin REST 로 demo job enqueue → JobAssignMsg 수신 → JobCompleteMsg 송신
    3. BalanceUpdateMsg 수신, DB 의 aggregated_earnings 가 갱신됨
  • CLAUDE.md 의 "Engine (background tasks)" 섹션이 "still target architecture" 가 아니라 실제 구현으로 갱신됨.

관련 이슈

  • #379 (해결) — Heartbeat 포팅. 본 이슈의 선행 작업이며, ConnectNode 의 NodeHeartbeatMsg 처리에 같은 store 함수 재사용.
  • #375 (해결) — JWT 전역 인터셉터. connect_node 핸들러에서 caller(req) 헬퍼 사용.
  • #421 (해결) — AGX 잔액 account scope 전환. Phase 5/7 정산이 이 위에서 작동.
  • #254 (진행) — DB 스키마. Phase 5/7 마이그레이션 시 함께 refs.

참고 코드

  • 레거시: ~/Works/alphea-rpc-next/alphea-rpc/internal/engine/ (전체)
  • 레거시: ~/Works/alphea-rpc-next/alphea-rpc/internal/domain/node/stream.go, redis_bridge.go
  • 레거시: ~/Works/alphea-rpc-next/alphea-rpc/internal/handler/node.go:218 (ConnectNode 핸들러)

예상 작업량

  • Phase 1: 3~4h (StreamManager + handshake)
  • Phase 2: 5~6h (Dispatcher + JobQueue + bidi message routing)
  • Phase 3: 3~4h (Synth)
  • Phase 4: 4~5h (Scheduler)
  • Phase 5: 3~4h (Persistence + AGX 정산 + balance push)
  • Phase 6: 2~3h (Timeout sweep)
  • Phase 7: 2~3h (VNodeCreditor + 마이그)
  • Phase 8: 3~4h (Engine 통합 + admin 컨트롤 + Dev Console UI)
  • 총: 25~33h

연결된 일감 4 (4 건 진행 중 — 모두 미완료)

다음 일감과 관련됨: 이슈 #375: JWT 전역 인터셉터 구현 (alphea-ai-edge)해결James Lee2026/04/15

Actions
다음 일감과 관련됨: 이슈 #421: AGX 잔액을 Wallet 종속 → Account(GoTrue user_id) 종속으로 전환해결James Lee2026/04/27

Actions
다음 일감과 관련됨: 이슈 #254: 8-2. 데이터베이스 스키마 설계 (사용자. 앱. 일정)진행James Lee2026/04/282026/04/29

Actions
다음 일감을 우선 진행: 이슈 #379: NodeService.Heartbeat 구현 (alphea-ai-edge)해결James Lee2026/04/16

Actions
Actions

내보내기 PDF Atom