xxl_endpoints.py 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. """XXL-JOB Admin → Executor 通信端点 —— 对标 Java XxlJobController.java
  2. 提供给 XXL-JOB Admin 调用的 HTTP API:
  3. POST /beat — 心跳检测
  4. POST /idleBeat — 空闲检测
  5. POST /run — 触发任务执行
  6. POST /kill — 强制终止任务
  7. POST /log — 读取执行日志
  8. """
  9. import logging
  10. from quart import Blueprint, request, jsonify
  11. logger = logging.getLogger(__name__)
  12. # 全局引用,由 create_xxl_bp 注入
  13. _executor_ref = None
  14. def set_xxl_executor(executor):
  15. """注入 XxlJobExecutor 实例(在 app 启动时调用)"""
  16. global _executor_ref
  17. _executor_ref = executor
  18. def create_xxl_bp() -> Blueprint:
  19. """创建 XXL-JOB API Blueprint
  20. XXL-JOB Admin 通过此 Blueprint 与执行器通信。
  21. 端点路径与 XXL-JOB 标准一致:/beat, /idleBeat, /run, /kill, /log
  22. """
  23. bp = Blueprint("xxl_job", __name__)
  24. @bp.route("/beat", methods=["POST"])
  25. async def beat():
  26. """心跳检测"""
  27. result = _executor_ref.beat()
  28. return jsonify(result)
  29. @bp.route("/idleBeat", methods=["POST"])
  30. async def idle_beat():
  31. """空闲检测:检查指定 jobId 是否正在运行"""
  32. form = await request.form
  33. job_id = int(form.get("jobId", 0))
  34. result = _executor_ref.idle_beat(job_id)
  35. return jsonify(result)
  36. @bp.route("/run", methods=["POST"])
  37. async def run():
  38. """触发任务执行"""
  39. form = await request.form
  40. trigger_params = {
  41. "jobId": int(form.get("jobId", 0)),
  42. "executorHandler": form.get("executorHandler", ""),
  43. "executorParams": form.get("executorParams", ""),
  44. "executorBlockStrategy": form.get("executorBlockStrategy", ""),
  45. "executorTimeout": int(form.get("executorTimeout", 0)),
  46. "logId": int(form.get("logId", 0)),
  47. "logDateTime": int(form.get("logDateTime", 0)),
  48. "glueType": form.get("glueType", ""),
  49. "glueSource": form.get("glueSource", ""),
  50. "glueUpdatetime": int(form.get("glueUpdatetime", 0)),
  51. "broadcastIndex": int(form.get("broadcastIndex", 0)),
  52. "broadcastTotal": int(form.get("broadcastTotal", 1)),
  53. }
  54. logger.info(
  55. "XXL-JOB run: handler=%s, jobId=%s, params=%s",
  56. trigger_params["executorHandler"],
  57. trigger_params["jobId"],
  58. trigger_params["executorParams"],
  59. )
  60. result = await _executor_ref.run(trigger_params)
  61. return jsonify(result)
  62. @bp.route("/kill", methods=["POST"])
  63. async def kill():
  64. """强制终止任务"""
  65. form = await request.form
  66. job_id = int(form.get("jobId", 0))
  67. logger.info("XXL-JOB kill: jobId=%s", job_id)
  68. result = await _executor_ref.kill(job_id)
  69. return jsonify(result)
  70. @bp.route("/log", methods=["POST"])
  71. async def log():
  72. """读取执行日志"""
  73. form = await request.form
  74. log_date_time = int(form.get("logDateTim", 0))
  75. log_id = int(form.get("logId", 0))
  76. from_line_num = int(form.get("fromLineNum", 1))
  77. result = _executor_ref.log(log_date_time, log_id, from_line_num)
  78. return jsonify(result)
  79. return bp