Commit Graph

15 Commits

Author SHA1 Message Date
ThearchyHelios eb9af51abb 复核 R-b14(PostgreSQL 单进程墙钟一跳就隔离自己):取得到计入休眠的钟(SLEEP_AWARE)时 stale() 只看它,墙钟只在取不到时当后备(两只里走得多的那只);两只钟对不上(jumped)不再直接隔离,先续一次租——续租那一句按库的时钟核对「自己的租约还没过期」,以它为准:续上了只记一条日志照常,续不上才隔离。README「多进程」补一句:库服务器自己的时钟往前跳超过一个租约时所有进程一起隔离、怎么恢复,往回跳时真没了的进程要多等,本机墙钟跳了不隔离。补测试:墙钟往前往后跳一小时不算续晚了、只算对不上,计入休眠的钟走过两个租约照样算,取不到时墙钟当后备;PostgreSQL 单进程墙钟 ±1 小时续租照常续上、不隔离,真过期仍隔离;执行到一半墙钟 ±1 小时,运行照常跑完、世代不变(改前的写法往前跳那条不过) 2026-10-19 15:07:17 +08:00
ThearchyHelios 68c1f4143e 复核 R-b13(版本拦截与零碎):preflight 报错列出全部活着的、版本不同的进程,各标明心跳在走还是停着、等租约过期(以前只点名先看到心跳的那个,人停掉它再起还会被另一个拦下);源码指纹把依赖锁文件 requirements.lock 的内容也算进去,只升了依赖也算版本不同,锁文件取不到时换成几个关键包的版本,Docker 镜像里留一份锁文件;存量库 run_events 撞了号时把结果记一次(settings 表 cluster:run_events_seq_duplicates,记下撞号的那几处,最多 200 处),之后启动不再整表 GROUP BY、只按索引核对那几处还撞不撞,都处理掉了才再数一遍、建唯一索引、删掉记录。隔离后换身份那几条日志写出新旧完整身份已在 R-b9 那一笔里改了。README「升级」一段跟着补一句。补测试:一个心跳在走、一个心跳停着,报错两个都列出、各标状态;锁文件变了指纹跟着变、取不到时用包版本;撞号第一次整表数、第二次只核对不扫、处理掉之后建上索引并删掉记录 2026-10-19 14:45:54 +08:00
ThearchyHelios ed3bb943df 复核 R-b11(跨零点退回额度退到第二天那一行):quota.take 交回占在了哪一天(本地日期),占不到交回 None;出具、按需视图发起失败时按这个日期退回——23:59:59 占、00:00:01 失败,退的是前一天那一份,第二天的不动。补测试:跨零点占了两份、退回前一天那一份,前一天归零、第二天那份不动 2026-10-19 14:40:11 +08:00
ThearchyHelios 19ffa1fa17 测试:隔离之后重新登记、收拾旧身份的两条用虚构的旧身份(不拿本进程真的身份当旧身份收拾,免得删到同一个测试进程里前面留下的、属主是它的行) 2026-10-19 14:40:10 +08:00
ThearchyHelios 1e6f0554fe 复核 R-b10(隔离换身份后旧身份的名额、请求没人收拾):要名额时把当时的身份记在 holder 上,放的时候按它删,换了身份也删得到;新身份登记上之后收拾旧身份(tidy_retired)——它的执行都已停下、写不了了,不必等它的租约过期:删掉它的登记(发 gone,别的进程马上按属主不在了接手它认领的运行、任务)、它占着的运行名额和同源队的位置,交出它拿着的当班租约,发给它的请求转到新身份名下照办,照实记一条日志;停止请求对不在本进程执行的运行也照停止的规矩办(cancel 自己看属主:转给正在执行它的进程、属主不在了就接手放弃、停在断点上的收成 cancelled)。补测试:拿着名额时换了身份照样放得掉(改前的写法这条不过);新身份登记上之后旧身份的登记、名额、队里的位置、当班租约都收拾掉,转过来的停止请求把停在断点上的那次运行收成 cancelled 2026-10-19 14:36:19 +08:00
ThearchyHelios 7fcce90f95 复核 R-b7(休眠、时钟偏差下隔离失灵):租约改用库的时钟——续租、登记写 lease_until = 库的 clock_timestamp() + 租约,判活、清理过期登记、版本守卫看谁活着都比库的时钟,调度当班的租约同样按库的时钟接班、续租,本地判还当不当班改看计入休眠的单调钟,机器之间墙钟差多少都不起作用;隔离改用计入休眠的钟(Linux CLOCK_BOOTTIME,macOS clock_gettime(CLOCK_MONOTONIC),取不到退回 monotonic),并且一律同时比墙钟,两只钟里走得多的那只说过了一个租约就算续晚了;续租时两只钟差出一个租约(墙钟跳了、休眠没计)也隔离;续租那一句带上「库里自己的租约还没过期」的条件,过期了或者登记不见了就不再续这个身份、隔离换身份(以前登记不见了是用旧身份重新登记)。补测试:单调钟不走而墙钟过了两个租约、墙钟往回拨,都算续晚了;本机墙钟快一小时,别的进程照样活着、当班租约抢不走;库的时钟过了自己的租约时续租不续、隔离一次 2026-10-19 14:27:55 +08:00
ThearchyHelios bf9e4d4811 测试:额度并发那条同时占的个数降到 10(不超过连接池直接能给的连接数)——全量 -n auto 时 SQLite 的池子各测试共用,排队等连接会把池子的队列绑到前一个测试的事件循环上,这条偶发报 bound to a different event loop 2026-10-19 13:35:17 +08:00
ThearchyHelios 62089f2849 复核「另外两处」:评测每题的时限、算期望的时限都不算排队等运行名额的那一段(within 代替 asyncio.wait_for,作答那次运行在 slots 里还排着队时不走表;算期望的运行排着队时把截止时刻往后挪),满载时不再被记成超时、触发止损;同源队(SourceLanes)跟发名额一样,拿这个源的咨询锁之前备好「哪些别的属主确实不在了」,持锁期间只用持锁的那条连接,拿锁之后才出现的属主这一次当活着。slots 加 waiting(run_id, here=):本进程里的直接看、不查库。补测试:排队 0.8 秒、时限 0.3 秒照样答完不记超时(改前的写法这条不过);within 暂停的那几段不算、不暂停照样超时;同源队持锁期间不查「谁还活着」、没了的进程照样让位、拿锁之后才出现的属主不删 2026-10-19 13:31:46 +08:00
ThearchyHelios f3ff5b9c18 复核 R-b5、R-b6:转发运行事件、读缓存失效通知都从游标往回留一小段重读(运行 64 条、缓存 200 条),按发布过的 seq / 处理过的 id 去重——号先取后提交、号大的先提交时,号小的那一条后到也照样转、照样失效,不越过回放已经发过的那一段;合成之后超长的正文增量按字切成几条(二分找每段最长的前缀,不切坏 UTF-8),不再截掉。补测试:号小的后提交照样转出来、不重复;缓存失效 id 大的先到、小的后到都处理;超长增量切开拼回来一字不少 2026-10-19 13:24:44 +08:00
ThearchyHelios 5578cf137d 复核 R-b4(prod.sh、Docker 入口读不到 .env 里的配置):新增 python -m app.cluster workers——照后端自己的配置(环境变量和 .env 一起读)说起几个工作进程,SQLite 而大于 1 时照实报错、退出码 2;prod.sh 只在命令行给了 --workers 时写进环境变量,进程数一律问后端,Docker 的入口同样问它。补测试:SQLite 而大于 1 拒绝、PostgreSQL 照给的数 2026-10-19 13:23:02 +08:00
ThearchyHelios 5f7100906f 复核 R-b3(SQLite 单进程多出来的写库):SQLite 时守卫已经确认只有本进程——登记只写一次、不续租约、本进程直接当班(不写库)、接手只在启动时做,心跳只做本进程自己攒着的活;运行的名额在 SQLite 下放在进程里(规矩同一套:优先级、类别上限、交互留底,只是不落库),一段运行不再为要名额多写三次库。顺带(复核「另外两处」之二):PostgreSQL 发名额持着全站的锁时不再另取连接查「谁还活着」,拿锁之前备好,不认识的属主这一次当活着。补测试:SQLite 空闲十来拍心跳、要一次名额放一次,PRAGMA data_version 不变(名额落库的写法这条不过);库里的名额行那两条只在 PostgreSQL 上跑 2026-10-19 13:22:05 +08:00
ThearchyHelios 75ab3678cb 代码里拦住新旧版本混跑(用户拍板):新增 cluster/version——代码版本(包版本 + 构建号 AGENTLAB_BUILD 或 git 提交 + app/ 下源码指纹,比较按源码指纹)、库结构版本(各表各列加迁移清单的哈希),进程登记时一并记下(cluster_workers 两列,add-only 迁移)。PostgreSQL 时补列之前先看一眼(preflight):库里还有活着的、版本不同的进程,心跳在走就拒绝启动、照实写明是哪几个进程什么版本、要先停掉再升级,心跳停着的(强杀留下的)等租约过期再起;登记那一下在事务级咨询锁里再查一遍,两个不同版本同时启动只有先登记上的起得来。Docker 镜像带上构建号;README 写明升级步骤。补测试:版本不同的活进程被点名拒绝、同版本照常加入、过期的不算、只比源码指纹;PostgreSQL 上心跳在走的拒绝、心跳停着的等过期、登记时再拦一次 2026-10-19 13:04:07 +08:00
ThearchyHelios 01af07b193 出具、按需视图的每日上限改成先占额度再发起(用户拍板):新增 cluster/quota——额度记在库里(rate_counters 按名字 + 本地日期一行),占一份是一句带条件的 UPDATE(没到上限才加一),两种库上都是原子的,这一天第一次占按库里已有的记录起算,发起被拒或出错就退回。出具去掉全站一把锁,只留同一(运行、工作流、版本)的去重锁,几份不同的出具可以同时发起;按需视图的锁缩回按缓存键(视图 + 参数)去重,每日上限改用这个应用的额度。补测试:20 个协程同时占正好到上限、按已有记录起算、退回再占;两个进程同时占正好到上限;三份不同的答案同时出具正好到上限、多出来的回 429 2026-10-19 12:57:38 +08:00
ThearchyHelios 6ed782a84b 运行名额改成给交互留底、其余可借(用户拍板):交互留底缺省全站上限的 1/4、至少 1、至多全站上限减 1,应用、定时、系统三类合起来永远用不到留底;三类各自的上限缺省 = 全站上限 − 留底(设置里可调小),没人问数据时评测能开满;交互上限缺省 = 全站上限;等名额照旧按优先级、同级先来先得。存着的设置原样存、缺省按全站上限和留底现算;留底不小于全站上限时 422。设置页「运行并发」加「给交互留底」一项,写明留底和借用是什么,README 同步。补测试:缺省值、空闲时系统类借满到 全站 − 留底、留底不借给应用类、问数据一来马上拿到留底;多进程端到端加 5b(评测借满时问数据拿留底、不等评测跑完) 2026-10-19 12:53:28 +08:00
ThearchyHelios 89cd135174 补多进程协调的单测(两种库):别的进程用库里的行装出来(登记着的同伴、从没登记过的已经没了的进程)——谁还活着、名额按优先级先给交互类、一类到了上限不挡别的类、没了的进程占着的名额收回而活着的同伴的不碰、同源队几个进程共用且跳过没了的进程的位置、接手运行只碰属主不在了的(升级前没记属主的照不在了处理)、停止和记事件交给活着的属主、属主不在了的停止直接接手放弃、当班到期交接、同一本每日账并发记不越过上限、SQLite 第二个进程(以及 AGENTLAB_WORKERS 大于 1)拒绝启动;评测说明里的并发一段照现在的名额说 2026-10-19 12:14:39 +08:00