fix(automation): 去掉 MySQL 不认的 NULLS FIRST,排序改用可移植写法

生产 MySQL 上手动跑第一轮就报 1064:

  You have an error in your SQL syntax ... near 'NULLS FIRST, login_tasks.id ASC'

NULLS FIRST 是 PostgreSQL/SQLite 语法,MySQL 不支持。本地测试全绿是因为跑在
SQLite 上(它认识这个语法),属于方言差异漏网 —— 生产是 MySQL、测试是 SQLite,
行为测试覆盖不到这类问题。

改成 `ck_checked_at IS NULL DESC, ck_checked_at ASC, id ASC`:三个方言下语义
一致(没检测过的优先)且都是合法 SQL。顺带把选行查询抽成 build_select_query,
便于按方言编译做回归。

新增回归测试:用 MySQL 方言 compile() 选行 SQL,断言不含 NULLS FIRST/LAST,
且「没检测过优先」用可移植写法表达。

规划附录 C.2 记下这条:写 SQL 前先确认方言;P0 连的是 order_site 的 PostgreSQL,
项目里已经出现 MySQL / SQLite / PG 三套方言。
This commit is contained in:
yml2213
2026-10-02 20:14:49 +08:00
parent f8a4a0baff
commit 3d5d0f551f
3 changed files with 36 additions and 4 deletions
+5
View File
@@ -1176,6 +1176,11 @@ OSS_PREFIX=collect
P1a 踩过一次:`.env` 加了 `AUTOMATION_ENABLED=true`,容器里查不到,调度器照旧不启动;
早先 §15.1 写入的 `ORDER_SITE_*` 与 `OSS_*` 同样没生效。新增变量时三处都要动:
`.env`(服务器实值)+ `docker-compose.yml`(透传)+ `.env.example`(留档);
- **注意方言差异:生产是 MySQL 8,测试是 SQLite**。SQLite 能吃下的写法 MySQL 未必认,行为测试也发现不了。
P1a 踩过一次:`ORDER BY ck_checked_at ASC NULLS FIRST` 在 SQLite 正常,MySQL 直接报
`1064 ... near 'NULLS FIRST'`。跨方言的排序用可移植写法(如 `col IS NULL DESC, col ASC`),
并在测试里按 MySQL 方言 `compile()` 一次做回归。**P0 更要注意:它连的是 order_site 的 PostgreSQL**,
三套方言(MySQL / SQLite / PG)都出现过,写 SQL 前先想清楚方言;
- **DB 读出来的时间是 naive UTC**:`datetime` 列取回后不带时区,直接和 `datetime.now(UTC)` 比较会
`TypeError: can't compare offset-naive and offset-aware`(P1a 踩过一次)。比较前一律用
`_as_utc()`(`services/yyb_service.py` 与 `services/automation/scheduler.py` 各有一份)补时区。