diff --git a/cloud/automations.py b/cloud/automations.py index 1c0d00f..c9de7c3 100644 --- a/cloud/automations.py +++ b/cloud/automations.py @@ -610,14 +610,37 @@ def _is_integrity_error(exc): 只有这类错误值得在事务边界重试整段;其它错误重试无用, 必须立即回滚抛错,不能被重试掩盖成“锁/冲突问题”。 - 旧 _audit_row 已删除:本模块不再有任何 audit_log 直写, - 审计只走 _audit_on_conn(见模块文档)。 + 本模块不直写 audit_log:审计只走 _audit_on_conn(见模块文档); + 下面的 _audit_row 仅为兼容包装(供 main #275 resident.py), + 本身仍走 _audit_on_conn,不含 audit_log INSERT。 """ if isinstance(exc, sqlite3.IntegrityError): return True return type(exc).__name__ == "PostgresIntegrityError" +def _audit_row(conn, project_id, action, detail, now): + """兼容包装:供 main #275 resident.py 的审计调用。 + + 本函数不直写 audit_log(#250 断言只允许 auth.py 出现 + audit_log INSERT):经 cloud.auth.audit_on_conn 写 + audit_log 行 + audit_ledger 链条目同一对,user_id 仍为 + "system"、created_at 用调用方给的 now。保留 main 旧版的 + best-effort 自提交语义:写对失败时回滚后吞掉,不影响 + resident 轮询本身;调用方已 commit 的业务行不受影响 + (审计对写是独立的后续写)。 + """ + try: + _audit_on_conn(conn, "system", project_id, action, detail, + created_at=now) + conn.commit() + except Exception: + try: + conn.rollback() + except Exception: + pass + + def run_due_automation(conn, automation_id, now=None): """云端自动化执行器的唯一入口:抢单 -> 配额门 -> 建任务 -> 记产出。 diff --git a/cloud/tests/test_handler_split_conformance.py b/cloud/tests/test_handler_split_conformance.py index 446207f..e8546b5 100644 --- a/cloud/tests/test_handler_split_conformance.py +++ b/cloud/tests/test_handler_split_conformance.py @@ -9,8 +9,10 @@ Pins the split contract so a future violation fails CI: as #238 arch_conformance.scan_imports); - server.py re-exports the moved shared helpers as identical objects, so `from cloud.server import _task_to_dict` keeps working; -- handler method accounting: 238 total, 144 left in server.py itself, - 94 in mixins, no name defined twice. +- handler method accounting: 243 total, 149 left in server.py itself, + 94 in mixins, no name defined twice. (v5 rebase: main #275 added + 5 resident methods that legitimately stay in server.py, so the + stack's 238/144 becomes 243/149; moved count stays 94.) Only the standard library; no real model, no network, no secrets. """ @@ -138,7 +140,7 @@ class TestReexports(unittest.TestCase): class TestMethodAccounting(unittest.TestCase): - def test_total_238_no_duplicates(self): + def test_total_243_no_duplicates(self): seen = {} dups = [] classes = [CloudControlPlaneHandler] @@ -153,9 +155,9 @@ class TestMethodAccounting(unittest.TestCase): dups.append((seen[name], cls.__name__, name)) seen[name] = cls.__name__ self.assertEqual(dups, []) - self.assertEqual(total, 238) + self.assertEqual(total, 243) self.assertEqual(len(_own_methods(CloudControlPlaneHandler)), - 238 - 94) + 243 - 94) if __name__ == "__main__":