feat(agent-office): ytpub_retry 텔레그램 콜백 → music-lab retry 프록시
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -43,6 +43,9 @@ async def _handle_callback(callback_query: dict) -> Optional[dict]:
|
|||||||
if callback_id.startswith("issue_"):
|
if callback_id.startswith("issue_"):
|
||||||
return await _handle_insta_issue(callback_query, callback_id)
|
return await _handle_insta_issue(callback_query, callback_id)
|
||||||
|
|
||||||
|
if callback_id.startswith("ytpub_retry_"):
|
||||||
|
return await _handle_ytpub_retry(callback_query, callback_id)
|
||||||
|
|
||||||
cb = get_telegram_callback(callback_id)
|
cb = get_telegram_callback(callback_id)
|
||||||
if not cb:
|
if not cb:
|
||||||
return None
|
return None
|
||||||
@@ -169,6 +172,30 @@ async def _handle_insta_issue(callback_query: dict, callback_id: str) -> dict:
|
|||||||
return {"ok": False, "error": str(e)}
|
return {"ok": False, "error": str(e)}
|
||||||
|
|
||||||
|
|
||||||
|
async def _handle_ytpub_retry(callback_query: dict, callback_id: str) -> dict:
|
||||||
|
"""ytpub_retry_{pipeline_id} 콜백 → music-lab pipeline retry 프록시."""
|
||||||
|
from .. import service_proxy
|
||||||
|
from .messaging import send_raw
|
||||||
|
|
||||||
|
await api_call(
|
||||||
|
"answerCallbackQuery",
|
||||||
|
{"callback_query_id": callback_query["id"], "text": "재시도 요청 중..."},
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
pid = int(callback_id.removeprefix("ytpub_retry_"))
|
||||||
|
except (ValueError, AttributeError):
|
||||||
|
return {"ok": False, "error": "invalid_callback_data"}
|
||||||
|
|
||||||
|
res = await service_proxy.pipeline_retry(pid)
|
||||||
|
sc = res.get("status_code")
|
||||||
|
if sc in (200, 202):
|
||||||
|
await send_raw(text=f"🔄 파이프라인 #{pid} 재개: {res.get('retrying_step', '?')}")
|
||||||
|
else:
|
||||||
|
await send_raw(text=f"⚠️ 재개 불가 (#{pid}): {res.get('detail', sc)}")
|
||||||
|
return {"ok": True}
|
||||||
|
|
||||||
|
|
||||||
async def _handle_message(message: dict, agent_dispatcher) -> Optional[dict]:
|
async def _handle_message(message: dict, agent_dispatcher) -> Optional[dict]:
|
||||||
"""슬래시 명령 메시지 처리."""
|
"""슬래시 명령 메시지 처리."""
|
||||||
from .router import parse_command, resolve_agent_command, HELP_TEXT
|
from .router import parse_command, resolve_agent_command, HELP_TEXT
|
||||||
|
|||||||
@@ -147,6 +147,38 @@ async def test_failed_pipeline_renotify_after_recovery():
|
|||||||
assert sent.await_count == 2 # 재알림
|
assert sent.await_count == 2 # 재알림
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_handle_ytpub_retry_calls_proxy():
|
||||||
|
from app import service_proxy
|
||||||
|
from app.telegram import webhook
|
||||||
|
|
||||||
|
retry = AsyncMock(return_value={"status_code": 202, "ok": True, "retrying_step": "video"})
|
||||||
|
fake_send = AsyncMock(return_value={"ok": True})
|
||||||
|
fake_api_call = AsyncMock(return_value={"ok": True})
|
||||||
|
|
||||||
|
with patch.object(service_proxy, "pipeline_retry", retry), \
|
||||||
|
patch("app.telegram.messaging.send_raw", fake_send), \
|
||||||
|
patch("app.telegram.webhook.api_call", fake_api_call):
|
||||||
|
res = await webhook._handle_ytpub_retry({"id": 1}, "ytpub_retry_7")
|
||||||
|
|
||||||
|
retry.assert_awaited_once_with(7)
|
||||||
|
assert res["ok"] is True
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_handle_ytpub_retry_invalid_data():
|
||||||
|
from app.telegram import webhook
|
||||||
|
|
||||||
|
fake_send = AsyncMock(return_value={"ok": True})
|
||||||
|
fake_api_call = AsyncMock(return_value={"ok": True})
|
||||||
|
|
||||||
|
with patch("app.telegram.messaging.send_raw", fake_send), \
|
||||||
|
patch("app.telegram.webhook.api_call", fake_api_call):
|
||||||
|
res = await webhook._handle_ytpub_retry({"id": 1}, "ytpub_retry_abc")
|
||||||
|
|
||||||
|
assert res["ok"] is False
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_failed_poll_exception_is_silent():
|
async def test_failed_poll_exception_is_silent():
|
||||||
"""list_failed_pipelines 예외 시 poll이 조용히 넘어감 (active 알림에 영향 없음)."""
|
"""list_failed_pipelines 예외 시 poll이 조용히 넘어감 (active 알림에 영향 없음)."""
|
||||||
|
|||||||
Reference in New Issue
Block a user