여러 줄 주석이 설명보다 경위(예전·실측·지적)를 적고 있어 읽는 사람이 결론을 찾기 어려웠다. - ts·tsx·js·mjs·css·py 478개: 여러 줄 주석은 첫 문장 한 줄로, 과거형·날짜 문장은 삭제 - 주석 위치는 TypeScript 파서·파이썬 tokenize/ast 로 찾는다 — 문자열 안의 # · /* 는 건드리지 않는다 - eslint·ts·noqa·type: ignore 같은 지시 주석은 그대로 둔다 파이썬 275개 정리 전후 AST 동일, TS 298개 주석 뺀 토큰 동일(빈 JSX 주석 10곳만 차이). site·frontend·admin tsc, site vitest 105 passed Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
82 lines
2.8 KiB
Python
82 lines
2.8 KiB
Python
"""잡 핸들러 레지스트리 — JobType 별로 '무엇을 하는가'."""
|
|
|
|
from common.enums import JobType
|
|
from common.logger import LOG
|
|
|
|
|
|
class UnknownJobType(RuntimeError):
|
|
"""등록되지 않은 JobType — 재시도해도 소용없다(코드 배포 누락 신호)."""
|
|
|
|
|
|
# JobType -> async def handler(job) -> dict
|
|
HANDLERS: dict[int, object] = {}
|
|
|
|
|
|
def register(job_type: JobType):
|
|
"""핸들러 등록 데코레이터."""
|
|
def _deco(fn):
|
|
if job_type.value in HANDLERS:
|
|
raise RuntimeError(f"JobType.{job_type.name} 핸들러가 이미 등록돼 있다")
|
|
HANDLERS[job_type.value] = fn
|
|
return fn
|
|
|
|
return _deco
|
|
|
|
|
|
def build_handler():
|
|
"""등록된 핸들러로 디스패처를 만든다."""
|
|
|
|
async def dispatch(job: dict) -> dict:
|
|
fn = HANDLERS.get(job["job_type"])
|
|
if fn is None:
|
|
name = JobType(job["job_type"]).name if job["job_type"] in {t.value for t in JobType} else job["job_type"]
|
|
raise UnknownJobType(f"JobType.{name} 핸들러 미등록 — 이 워커 이미지에 해당 모듈이 없다")
|
|
return await fn(job)
|
|
|
|
return dispatch
|
|
|
|
|
|
def registered_types() -> list[str]:
|
|
"""기동 로그용 — 이 워커가 처리할 수 있는 잡 종류."""
|
|
return [JobType(v).name for v in sorted(HANDLERS)]
|
|
|
|
|
|
def log_registry():
|
|
names = registered_types()
|
|
if names:
|
|
LOG.i(f"[worker] 처리 가능 잡: {', '.join(names)}")
|
|
else:
|
|
LOG.w("[worker] 등록된 핸들러가 없습니다 — 적재되는 잡은 모두 UnknownJobType 으로 DEAD 됩니다")
|
|
|
|
|
|
# 등록
|
|
def _register_builtin():
|
|
from services.collect_service import run_collect
|
|
from services.build_service import run_build
|
|
from services.copy_service import run_copy
|
|
from services.story_service import run_local_sync
|
|
from services.song_service import run_song
|
|
from services.social_service import run_draft, run_post
|
|
HANDLERS[JobType.SOCIAL_DRAFT.value] = run_draft
|
|
HANDLERS[JobType.SOCIAL_POST.value] = run_post
|
|
from services.rollback_service import run_rollback
|
|
from services.vision_service import run_vision
|
|
|
|
if JobType.COLLECT.value not in HANDLERS:
|
|
HANDLERS[JobType.COLLECT.value] = run_collect
|
|
if JobType.VISION.value not in HANDLERS:
|
|
HANDLERS[JobType.VISION.value] = run_vision
|
|
if JobType.COPY.value not in HANDLERS:
|
|
HANDLERS[JobType.COPY.value] = run_copy
|
|
if JobType.BUILD.value not in HANDLERS:
|
|
HANDLERS[JobType.BUILD.value] = run_build
|
|
if JobType.LOCAL_SYNC.value not in HANDLERS:
|
|
HANDLERS[JobType.LOCAL_SYNC.value] = run_local_sync
|
|
if JobType.SONG.value not in HANDLERS:
|
|
HANDLERS[JobType.SONG.value] = run_song
|
|
if JobType.ROLLBACK.value not in HANDLERS:
|
|
HANDLERS[JobType.ROLLBACK.value] = run_rollback
|
|
|
|
|
|
_register_builtin()
|