Fix workers time columns to DOUBLE PRECISION on Postgres

SQLite REAL is 8-byte double, but Postgres REAL is 4-byte
float4 (~7 significant digits). Epoch seconds (10 digits) were
rounded to 128-second steps, so worker liveness ages were off
by up to +-64s and could even go negative (observed live on
the host: last_seen ahead of NOW() by 20s). New tables use
DOUBLE PRECISION; existing Postgres tables are upgraded only
when information_schema actually reports REAL, so the ALTER
does not run on every heartbeat (it would take an ACCESS
EXCLUSIVE lock each time). SQLite path is unchanged (its
REAL is already double precision).
Regression test asserts new tables use DOUBLE PRECISION.
This commit is contained in:
host committed 2026-10-26 05:04:59 +08:00
1 parent 3bc9d49d0c
commit e2d6a454bf
2 files changed
+64 -3

No files matched your search

+21
View File
@@ -458,5 +458,26 @@ class ProjectTaskFieldTestCase(_ServerCase):
self.assertEqual(body["executor"], "docker")
class WorkerTablePrecisionTestCase(unittest.TestCase):
def test_workers_time_columns_are_double_precision(self):
# 回归:2026-10-26 主机实测,workers.last_seen 用 REAL 时,
# Postgres 的 float4 把 epoch 秒舍入到 128 秒一档,存活判断
# 误差可达 ±64 秒、甚至出现负 age。新表必须是 DOUBLE PRECISION。
import sqlite3 as _sqlite3
tmp = tempfile.TemporaryDirectory()
db_path = os.path.join(tmp.name, "w.db")
from cloud.workers import ensure_workers_table
ensure_workers_table(db_path)
conn = _sqlite3.connect(db_path)
try:
rows = conn.execute("PRAGMA table_info(workers)").fetchall()
finally:
conn.close()
tmp.cleanup()
by_name = {r[1]: r[2] for r in rows}
self.assertIn("DOUBLE", by_name["last_seen"])
self.assertIn("DOUBLE", by_name["created_at"])
if __name__ == "__main__":
unittest.main()