初始提交:chongming-task 任务控制库
单任务受控执行(15 态状态机 + 审计轨迹)、DAG 管道、Controller 门面。
执行器三个:线程(默认,含 async def 任务)、内联(同步 / 测试)、进程
(spawn 子进程:硬性停止、绕开 GIL、崩溃隔离)。
调度:并发额度 + 每桶限流 + 具名资源信号量(按标签)+ 优先级排队。
持久层:TaskStore 契约 + 内存 / SQLite / Postgres 实现,契约测试随包发布。
跨进程与多节点:写穿 / 读穿、指令通道与租约、owned_buckets 划界、reconcile。
CLI、12 个可直接运行的示例、docs/ 下 5 份文档。
门禁:ruff / ruff format / mypy(strict) 干净;
pytest 563 passed(44 skipped 是需要真实 Postgres 的那批);
带一台可连的 Postgres 时 607 passed。
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
"""示例 4:用 Controller 管理一批任务(注册 / 提交 / 排队 / 查询 / 控制)。
|
||||
|
||||
这是管理后台的核心:**一个统一入口**持有任务定义、运行中的任务与并发额度。
|
||||
将来的 CLI 或看板都只是这一层的薄适配。
|
||||
|
||||
运行::
|
||||
|
||||
uv run python examples/04_controller.py
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import time
|
||||
|
||||
from chongming_task.controller import Controller, render_table
|
||||
|
||||
|
||||
def transform(ctx, rows: int) -> int:
|
||||
"""转换:逐行推进。"""
|
||||
for _ in range(30):
|
||||
ctx.checkpoint()
|
||||
time.sleep(0.02)
|
||||
return rows * 2
|
||||
|
||||
|
||||
def extract(ctx, source: str) -> str:
|
||||
"""抽取:比转换慢一倍。"""
|
||||
for _ in range(60):
|
||||
ctx.checkpoint()
|
||||
time.sleep(0.02)
|
||||
return f"{source} -> 1200 行"
|
||||
|
||||
|
||||
def main() -> None:
|
||||
controller = Controller(max_parallel=2)
|
||||
controller.register("transform", transform, tags={"cpu"})
|
||||
controller.register("extract", extract, tags={"io"})
|
||||
controller.register("load", transform, description="写回目标库")
|
||||
|
||||
print("已注册任务:", "、".join(controller.registry.names()))
|
||||
print("并发上限:2\n")
|
||||
|
||||
for index in range(4):
|
||||
controller.submit(
|
||||
"transform", 100 * (index + 1), task_id=f"t{index}", label=f"转换-{index + 1}"
|
||||
)
|
||||
print(f"提交了 4 个任务;此刻排队 {controller.queued_count} 个(超出并发上限的部分)")
|
||||
|
||||
time.sleep(0.4)
|
||||
print("\n--- 查询:运行中的视图 ---")
|
||||
print(render_table(controller.list_tasks()))
|
||||
stats = controller.stats()
|
||||
print(
|
||||
f" 未结束 {stats.unfinished}"
|
||||
f"(其中排队 {controller.queued_count},占用执行额度 {controller.active_count})"
|
||||
)
|
||||
|
||||
controller.wait_all(timeout=30)
|
||||
print("\n--- 查询:全部结束 ---")
|
||||
print(render_table(controller.list_tasks()))
|
||||
|
||||
print("\n>>> 提交一个长任务,然后中途停止它")
|
||||
controller.submit("extract", "s3://demo/big", task_id="t-long", label="抽取(大)")
|
||||
time.sleep(0.3)
|
||||
print(f" 当前状态:{controller.get('t-long').status.value}")
|
||||
controller.stop("t-long", reason="手工干预")
|
||||
outcome = controller.wait("t-long", timeout=10)
|
||||
print(
|
||||
f" 终态:{outcome.status.value}"
|
||||
f"(失败归类 {outcome.failure.kind.value},可重试 {outcome.failure.retryable})"
|
||||
)
|
||||
|
||||
print("\n--- 最终统计 ---")
|
||||
final = controller.stats()
|
||||
for status, count in sorted(final.by_status.items(), key=lambda item: item[0].value):
|
||||
print(f" {status.value:<10} {count}")
|
||||
print("\n提示:另一个进程里的 chongming-task ps 看不到这些任务——内存不共享,")
|
||||
print(" 跨进程查询需要共享存储(stdlib sqlite3),那是下一步。")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user