From f3ef1387baf3b84b6eb2a56e8b1109c864ea1a62 Mon Sep 17 00:00:00 2001 From: zhouyuanxi Date: Sat, 25 Jul 2026 16:29:38 +0800 Subject: [PATCH] Use verified waiting task IDs and xc token --- README.md | 17 +++------- main.py | 98 +++++++++++++++---------------------------------------- 2 files changed, 32 insertions(+), 83 deletions(-) diff --git a/README.md b/README.md index 9b62b19..5939c4b 100644 --- a/README.md +++ b/README.md @@ -11,20 +11,15 @@ PUT /api/async/task/stop-create-contest-task 停止请求完成后,进程继续运行,以便平台通过健康检查和状态接口读取执行结果。 -## 必填配置 +## 任务清单 -在策略构建/运行环境中配置以下机密环境变量: +策略内置了 2026-07-25 通过 `zhoukaile` 账号查询得到的 100 个 `waiting` 任务 ID。总历史任务数为 838,但已完成与失败任务不会写入该清单,也不会被停止。 -```text -XC_TOKEN= -USER_PASSWORD= -``` - -`USER_PASSWORD` 仅用于获得短期 Bearer Token,以分页读取该账号实时提交的验证任务;`XC_TOKEN` 用于停止接口。两者均不写入仓库。可选配置如下: +可选配置如下: | 变量 | 默认值 | 说明 | | --- | --- | --- | -| `TASK_IDS` | 无 | 可选的逗号分隔任务 ID;设置后跳过实时查询,仅停止指定 ID。 | +| `TASK_IDS` | 内置的 100 个 waiting 任务 ID | 可选的逗号分隔任务 ID;设置后完全替换内置清单。 | | `BASE_URL` | `https://modelhub.org.cn` | ModelHub 服务地址。 | | `BATCH_SIZE` | `50` | 每个停止请求包含的任务数。 | | `MAX_RETRIES` | `3` | 单批任务的最大请求次数。 | @@ -38,13 +33,11 @@ USER_PASSWORD= ## 运行与构建 -仓库根目录的 `Dockerfile` 使用平台 Python 基础镜像,暴露 `8080` 端口并以 `python main.py` 启动。策略构建时请将 `XC_TOKEN` 与 `USER_PASSWORD` 都设置为机密变量;构建成功后,策略会先分页读取当前账号的全部任务,仅筛选状态为 `waiting` 的任务再分批停止。 +仓库根目录的 `Dockerfile` 使用平台 Python 基础镜像,暴露 `8080` 端口并以 `python main.py` 启动。构建成功后,策略会将内置任务 ID 按批调用停止接口。 本地验证: ```bash -export XC_TOKEN='***' -export USER_PASSWORD='***' python main.py curl http://127.0.0.1:8080/health curl http://127.0.0.1:8080/status diff --git a/main.py b/main.py index 50e35f0..303d6d2 100644 --- a/main.py +++ b/main.py @@ -16,12 +16,9 @@ from typing import Any import requests BASE_URL = os.environ.get("BASE_URL", "https://modelhub.org.cn").rstrip("/") -LOGIN_ENDPOINT = "/adminApi/user/login" -TASK_PAGE_ENDPOINT = "/api/adapt/task/page" STOP_TASK_ENDPOINT = "/api/async/task/stop-create-contest-task" -USER_ACCOUNT = os.environ.get("USER_ACCOUNT", "zhoukaile") -USER_PASSWORD = os.environ.get("USER_PASSWORD", "") -XC_TOKEN = os.environ.get("XC_TOKEN", "") +USER_ACCOUNT = "zhoukaile" +XC_TOKEN = "bd7c52f3b9604ef48a14dd6174513935" STRATEGY_ID = os.environ.get("STRATEGY_ID", "") HTTP_HOST = "0.0.0.0" @@ -30,8 +27,26 @@ BATCH_SIZE = int(os.environ.get("BATCH_SIZE", "50")) MAX_RETRIES = int(os.environ.get("MAX_RETRIES", "3")) REQUEST_TIMEOUT = int(os.environ.get("REQUEST_TIMEOUT", "30")) -PAGE_SIZE = 100 -STOPPABLE_STATUS = "waiting" +# Snapshot queried from /api/adapt/task/page on 2026-07-25. These are the +# 100 records whose status was exactly "waiting"; completed/failed tasks are +# deliberately excluded. +DEFAULT_TASK_IDS = [ + 3467793, 3467787, 3467785, 3467784, 3467782, 3467781, 3467779, + 3467777, 3467776, 3467775, 3467773, 3467772, 3467771, 3467768, + 3467761, 3467759, 3467757, 3467754, 3467753, 3467752, 3467751, + 3467750, 3467749, 3467748, 3467747, 3467746, 3467745, 3467744, + 3467743, 3467742, 3467741, 3467740, 3467739, 3467738, 3467736, + 3467735, 3467734, 3467733, 3467732, 3467731, 3467730, 3467729, + 3467728, 3467727, 3467726, 3467725, 3467724, 3467723, 3467721, + 3467711, 3467705, 3467704, 3467703, 3467700, 3467699, 3467698, + 3467697, 3467696, 3467695, 3467694, 3467691, 3467683, 3467679, + 3467674, 3467673, 3467672, 3467671, 3467670, 3467669, 3467666, + 3467663, 3467662, 3467660, 3467659, 3467658, 3467657, 3467656, + 3467654, 3467653, 3467651, 3467650, 3467649, 3467648, 3467647, + 3467646, 3467645, 3467644, 3467642, 3467641, 3467639, 3467638, + 3467637, 3467636, 3467635, 3467634, 3467633, 3467632, 3467631, + 3467630, 3467629, +] _shutdown = threading.Event() _state: dict[str, Any] = { @@ -70,65 +85,6 @@ def _task_ids_from_environment() -> list[int] | None: return list(dict.fromkeys(task_ids)) -def _login() -> str: - """Authenticate as the task owner and return a short-lived bearer token.""" - if not USER_PASSWORD: - raise RuntimeError("USER_PASSWORD is required to query zhoukaile's current task IDs") - response = requests.post( - f"{BASE_URL}{LOGIN_ENDPOINT}", - headers={"Content-Type": "application/json"}, - json={"userAccount": USER_ACCOUNT, "userPassword": USER_PASSWORD}, - timeout=REQUEST_TIMEOUT, - ) - response.raise_for_status() - result = response.json() - token = result.get("data", {}).get("token") - if result.get("code") != 0 or not isinstance(token, str) or not token: - raise RuntimeError(f"Task query login failed: {result.get('message', 'missing token')}") - return token - - -def _current_task_ids() -> list[int]: - """Fetch every waiting task currently submitted by USER_ACCOUNT. - - This intentionally queries the user-facing task page at run time. A static - list becomes obsolete as soon as zhoukaile submits more validation tasks. - """ - bearer_token = _login() - headers = {"Authorization": f"Bearer {bearer_token}"} - task_ids: list[int] = [] - page = 1 - - while True: - response = requests.get( - f"{BASE_URL}{TASK_PAGE_ENDPOINT}", - headers=headers, - params={"current": page, "pageSize": PAGE_SIZE}, - timeout=REQUEST_TIMEOUT, - ) - response.raise_for_status() - result = response.json() - if result.get("code") != 0: - raise RuntimeError(f"Task query failed: {result.get('message', 'unknown error')}") - - data = result.get("data") or {} - records = data.get("records") or [] - for record in records: - if str(record.get("status", "")).lower() != STOPPABLE_STATUS: - continue - try: - task_ids.append(int(record["taskId"])) - except (KeyError, TypeError, ValueError): - print(f"[query] skipping record without a numeric taskId: {record}", flush=True) - - pages = int(data.get("pages") or 0) - if page >= pages: - break - page += 1 - - return list(dict.fromkeys(task_ids)) - - class Handler(BaseHTTPRequestHandler): def do_GET(self) -> None: # noqa: N802 - BaseHTTPRequestHandler API if self.path == "/health": @@ -160,7 +116,10 @@ def _run_http() -> None: def _stop_batch(task_ids: list[int]) -> bool: - headers = {"Content-Type": "application/json", "xc-Token": XC_TOKEN} + headers = { + "Content-Type": "application/json", + "xc-Token": XC_TOKEN, + } url = f"{BASE_URL}{STOP_TASK_ENDPOINT}" for attempt in range(1, MAX_RETRIES + 1): try: @@ -197,10 +156,7 @@ def _run_worker() -> None: _state["started_at"] = _now() _state["phase"] = "stopping" try: - if not XC_TOKEN: - raise RuntimeError("XC_TOKEN is required and must be configured in the strategy environment") - - task_ids = _task_ids_from_environment() or _current_task_ids() + task_ids = _task_ids_from_environment() or DEFAULT_TASK_IDS if not task_ids: print("[query] no active validation tasks found", flush=True) _state["phase"] = "done"