bbd92a840a
PR-Worker-Pool-Registry-1A (scaffold only, no runtime activation). 신규: - migrations/270~274 (1 statement/1 file 강제): worker_capabilities + 2 idx + worker_heartbeats + 1 idx - app/models/worker_pool.py: WorkerCapability + WorkerHeartbeat ORM (queue.py 패턴) - app/api/internal_worker.py: 5 endpoint 모두 _stub_503() — register/heartbeat/claim/result/drain - tests/test_internal_worker_stub.py: 503 응답 smoke (inline ASGI client, DB 의존 0) 수정: - app/main.py: import + include_router 각 1줄 (prefix=/internal/worker, internal_study 일관) scaffold-first + phase-gate-material-first 강제 (worker-pool-policy §1, §12): - 인증 dependency 0 (1B 에서 JWT + require_worker_user) - ProcessingQueue 변경 0 (방향 b: worker_jobs 별 table = 1B) - LLM 호출 0 / canonical DB 변경 0 / 운영 자동 분기 0 회귀 0 (1주 안전망 = app/main.py.pre-registry-1a.20260518). plan: ~/.claude/plans/floofy-exploring-mitten.md Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
53 lines
2.1 KiB
Python
53 lines
2.1 KiB
Python
"""worker_capabilities + worker_heartbeats 테이블 ORM (PR-Worker-Pool-Registry-1A).
|
|
|
|
1A 단계: schema only. 라우트 5개 (register/heartbeat/claim/result/drain) 모두 503 stub.
|
|
실 활성화 + WorkerJob 모델은 1B 영역. 본 모듈 import 자체는 init_db 가 mig 270~274 적용
|
|
후 안전 (테이블 존재 보장).
|
|
"""
|
|
|
|
from datetime import datetime
|
|
|
|
from sqlalchemy import BigInteger, DateTime, ForeignKey, Text
|
|
from sqlalchemy.dialects.postgresql import JSONB
|
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
|
|
from core.database import Base
|
|
|
|
|
|
class WorkerCapability(Base):
|
|
__tablename__ = "worker_capabilities"
|
|
|
|
worker_id: Mapped[str] = mapped_column(Text, primary_key=True)
|
|
user_id: Mapped[int] = mapped_column(
|
|
BigInteger, ForeignKey("users.id"), nullable=False
|
|
)
|
|
device_label: Mapped[str] = mapped_column(Text, nullable=False)
|
|
worker_class: Mapped[str] = mapped_column(Text, nullable=False)
|
|
tier: Mapped[str] = mapped_column(Text, nullable=False)
|
|
capabilities: Mapped[list] = mapped_column(JSONB, default=list, nullable=False)
|
|
models_loaded: Mapped[list] = mapped_column(JSONB, default=list, nullable=False)
|
|
endpoint: Mapped[str | None] = mapped_column(Text)
|
|
created_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True), default=datetime.now, nullable=False
|
|
)
|
|
last_registered_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True), default=datetime.now, nullable=False
|
|
)
|
|
|
|
|
|
class WorkerHeartbeat(Base):
|
|
__tablename__ = "worker_heartbeats"
|
|
|
|
id: Mapped[int] = mapped_column(BigInteger, primary_key=True)
|
|
worker_id: Mapped[str] = mapped_column(
|
|
Text, ForeignKey("worker_capabilities.worker_id"), nullable=False
|
|
)
|
|
heartbeat_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True), default=datetime.now, nullable=False
|
|
)
|
|
status: Mapped[str] = mapped_column(Text, nullable=False)
|
|
current_job_id: Mapped[int | None] = mapped_column(BigInteger)
|
|
battery: Mapped[str | None] = mapped_column(Text)
|
|
thermal: Mapped[str | None] = mapped_column(Text)
|
|
raw_payload: Mapped[dict] = mapped_column(JSONB, default=dict, nullable=False)
|