feat(worker-pool): Registry-1B Pull 활성화 (auth + worker_jobs + 5 endpoint)
worker-pool-policy §B 1B 영역 완료. 1A scaffold (mig 270~274 + 503 stub) 위에:
- mig 275/276: worker_jobs (status CHECK + user_id=owner) + pending partial index
- create_laptop_worker_bot_token + require_worker_user dependency (voice-memo 동형)
- /internal/worker/{register,heartbeat,claim,result,drain} 5 endpoint 실 구현
- /claim FOR UPDATE SKIP LOCKED + 204 body 0
- /result 소유권 검증 (worker_id 매칭, 404) + failed 재시도 (attempts/max)
- explicit failure 시 request.result 무시 (DB result NULL 유지)
- 테스트 22 항목 7 파일
policy §B.2 5 invariant 보존: voice-memo wrapper 변경 0, drain advisory,
result raw JSONB, ProcessingQueue 무변경, 운영 자동 분기 변경 0.
활용처 (recap context + /jobs/recap + payload 100KB guard) = Registry-1C 영역.
stale recovery / 노트북 client / canonical promote = Notebook-Pilot-1 영역.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -51,6 +51,17 @@ def create_voice_memo_bot_token(username: str) -> str | None:
|
||||
return create_access_token(username, expires_minutes=expire_days * 24 * 60)
|
||||
|
||||
|
||||
def create_laptop_worker_bot_token(username: str) -> str | None:
|
||||
# PR-Worker-Pool-Registry-1B — laptop-worker-bot 계정 한정 long-expiry token (voice-memo 동형).
|
||||
if os.getenv("LAPTOP_WORKER_BOT_TOKEN_ENABLED", "false").lower() != "true":
|
||||
return None
|
||||
bot_username = os.getenv("LAPTOP_WORKER_BOT_USERNAME", "laptop-worker-bot")
|
||||
if username != bot_username:
|
||||
return None
|
||||
expire_days = int(os.getenv("LAPTOP_WORKER_BOT_TOKEN_EXPIRE_DAYS", "365"))
|
||||
return create_access_token(username, expires_minutes=expire_days * 24 * 60)
|
||||
|
||||
|
||||
def create_refresh_token(subject: str) -> str:
|
||||
now = datetime.now(timezone.utc)
|
||||
expire = now + timedelta(days=REFRESH_TOKEN_EXPIRE_DAYS)
|
||||
@@ -129,3 +140,21 @@ async def require_admin(
|
||||
detail="관리자 권한 필요",
|
||||
)
|
||||
return user
|
||||
|
||||
|
||||
async def require_worker_user(
|
||||
credentials: Annotated[HTTPAuthorizationCredentials, Depends(security)],
|
||||
session: Annotated[AsyncSession, Depends(get_session)],
|
||||
):
|
||||
"""PR-Worker-Pool-Registry-1B — /internal/worker/* 인증.
|
||||
|
||||
laptop-worker-bot 만 허용. voice-memo-bot 또는 일반 사용자 토큰 → 403.
|
||||
"""
|
||||
user = await get_current_user(credentials, session)
|
||||
bot_username = os.getenv("LAPTOP_WORKER_BOT_USERNAME", "laptop-worker-bot")
|
||||
if user.username != bot_username:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="worker user only",
|
||||
)
|
||||
return user
|
||||
|
||||
Reference in New Issue
Block a user