recovery_probe.py 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. import argparse
  2. import asyncio
  3. import json
  4. import sys
  5. from uuid import UUID
  6. from sqlalchemy.ext.asyncio import async_sessionmaker
  7. from zhifu.app import create_app
  8. from zhifu.core.config import Settings
  9. from zhifu.core.database import create_engine
  10. from zhifu.modules.agent_runtime.models import AgentRun
  11. from zhifu.modules.agent_runtime.runtime import build_tool_graph
  12. from zhifu.modules.agent_runtime.worker import claim
  13. from zhifu.modules.integrations.fulfillment import execute_due
  14. async def main(identifier, stage):
  15. # 仅供独立验收进程使用;生产租约和工具事务保持完整,不修改租约时间。
  16. settings = Settings()
  17. if settings.environment == "production":
  18. raise RuntimeError("恢复探针仅允许开发和测试环境")
  19. create_app()
  20. engine = create_engine(settings)
  21. sessions = async_sessionmaker(engine, expire_on_commit=False)
  22. try:
  23. if stage == "external":
  24. if not await execute_due(sessions, 30, identifier.bytes):
  25. raise RuntimeError("指定外部操作未被领取")
  26. return
  27. selected = await claim(sessions, 2)
  28. if selected is None or selected[0] != identifier.bytes:
  29. raise RuntimeError("领取结果与指定验收任务不一致")
  30. run_id, token = selected
  31. if stage == "committed":
  32. await build_tool_graph(sessions).ainvoke({"run_id": run_id, "token": token})
  33. async with sessions() as session:
  34. row = await session.get(AgentRun, run_id)
  35. marker = {
  36. "run_id": str(identifier),
  37. "token": token,
  38. "lease_until": row.lease_until.isoformat(),
  39. "stage": stage,
  40. }
  41. print(json.dumps(marker), flush=True)
  42. # 父进程收到真实事务完成标记后终止本进程;不执行生成模型。
  43. await asyncio.to_thread(sys.stdin.read)
  44. finally:
  45. await engine.dispose()
  46. if __name__ == "__main__":
  47. parser = argparse.ArgumentParser(description="验证工作进程终止后的租约恢复")
  48. parser.add_argument("run_id", type=UUID)
  49. parser.add_argument("stage", choices=("claimed", "committed", "external"))
  50. arguments = parser.parse_args()
  51. asyncio.run(main(arguments.run_id, arguments.stage))