Kotlin 39:一条任务从请求到重启能证明什么
此前的实验分开验证了 JSON 领域校验、Ktor 回环、协程任务树与真实 PostgreSQL:34的 HTTP registry 仍在内存里,35的 JDBC Store 没有接到这个路由。把两篇测试的 PASS 拼在一起,不能推出“一条 HTTP 请求提交后重启仍能查询”。39 改为同一组隔离 PostgreSQL 数据目录和两个先后启动的真实 Netty JVM,逐项询问:202 出现前是否已提交、Job 失败留下什么、数据库断线怎样返回、重启后 GET 读到的是状态还是正在运行的任务。 本轮保持 Kotlin 2.2.21、Gradle 8.14、JDK 21、coroutines 1.10.2、Ktor 3.3.1、JDBC 42.7.7 与专用 PostgreSQL 16.15。2026-10-10 核对 Ktor 服务测试、PostgreSQL 16 INSERT/UPDATE 与 JDK 21 Connection;精确运行版本和原始响应见 writing-plans/kotlin/verification/39/。只使用本地合成请求,测试初始化自己的数据库进程...
Go E01:Java 经验迁移时容易误读的三个 Go 契约
主线 39已经核验服务的接纳、查询和退出;系列导航仍把 E01–E08 单独计数。迁移 Java 经验时,几个用词看起来熟悉:null、对象引用、线程中断。但 Go 的接口值、struct 值与 context 取消有自己的规则。本篇只在原累计工程上加三项反例测试,不复制 Java 服务。素材另附SHA-256及复跑步骤。 不能用 Java 的 null 猜接口是否为空 Go 1.27.1 的语言规范在 Variables 一节直接给出 var v *T 为 nil、x = v 后接口 x 动态类型为 *T 的例子。TestElectiveJavaTypedNilIsNotMissingTask 把 nil 的 *electiveLookupError 赋给 error:原指针仍为 nil,接口比较 err != nil 却为 true。这是typed nil,不是「有一个非空错误对象」。测试给错误方法加了 nil 接收者保护,以便观察接口内容,而不是靠 panic 判断。 同一任务服务的真实 TaskStore.Lookup("missing") 返回 (T...
Kotlin 38:进程退出时,哪些任务和连接还活着
34 的 HTTP 实验在测试应用与回环端口证明了 202 先于后台任务完成,但那时服务由测试管理;测试结束时由调用方手动停引擎、停内存任务。把类装进发行包后,真实 JVM 收到终止请求的顺序由谁保证?单看“进程没了”无法判断:请求可能仍被受理,挂起任务可能没等清理完成,打印的终态也可能与实际资源退出不一致。 本篇沿用 Kotlin 2.2.21、Ktor 3.3.1、Gradle 8.14、JDK 21。依据是 Gradle application 插件的 installDist/distZip、Ktor embeddedServer 的服务配置、JDK 21 Runtime.addShutdownHook(2026-10-10 核对)。下述只运行本机 127.0.0.1 的合成任务,不构成公网部署。 发行包里有两个不同的入口 累计工程从 00 起的 main(args) 仍是校验 submit alpha 的教学 CLI:它接受输入,不执行后台任务。修改 application.mainClass 去指向 HTTP 服务,会让已经回归了几十篇的 CLI 正反例失去原来的语义。...
Kotlin 37:装箱与协程成本怎样测才不误判
36 的字节码观察确认了挂起函数的 JVM 签名与状态字段,但单凭 `javap` 里多了几个字段,算不出应用的分配量,更算不出 HTTP 请求耗时。08 的集合实验展示 `take(1)` 在首项匹配时 Sequence 可以少做很多转换;那种输入若直接放进性能对比,两条路径其实完成了不同的工作。这里先把工作量对齐,再问几个更窄的问题:同一组任务标签通过 List 与 Sequence 转换、同一组 ID 包装成 value class、同一条合成状态路径通过 `runBlocking`,在当前 JVM 上分别记录什么。 工具是 Kotlin 编译器/插件 2.2.21、JDK 21、Gradle 8.14 以及 OpenJDK JMH 1.37(tag 2effa2c8310e1d3ad03c8ee02024edca9252b46a)。JMH 官方同一 tag 的 JMHSample_02_BenchmarkModes、JMHSample_08_DeadCode 和 JMHSample_27_Params 分别解释模式/单位、死代码消除与固定输入;源码身份及本机解析依赖见 w...
Kotlin 36:suspend 函数怎样变成可恢复的字节码
35 的事务实验把同步 JDBC 留在固定的工作线程,但外层函数仍写作 `suspend fun insert(...)`。这个修饰符并不表示 SQL 有了一条额外的线程,也不表示持有连接时能安全地随处挂起。理解它要从已经写过的 `executeSyntheticTask` 出发:执行任务步骤时函数可以暂停,步骤返回后又要带着 `TaskId` 和先前状态继续。暂停时这些局部变量去了哪里? 本篇保持编译器/Gradle 插件 2.2.21、language/API 2.2、JDK 21 和 jvmTarget 21。通过 Git tag v2.2.21 定位编译器提交 2146684dcba708e5a304758b41a9e4ec9c7eff71,并在这个提交下阅读 AddContinuationLowering.kt 与 CoroutineCodegen.kt。Gradle --version 所说的 内嵌 Kotlin 2.0.21 是 Gradle 自己的脚本环境,不是编译本工程源码的编译器。以下的类名、局部字段和指令只适用于这份固定生成物;可跨版本引用的是 Kotlin...
Kotlin 35:事务中途挂起,连接归谁
34 的 HTTP 服务把“请求已受理”和“后台任务已完成”分开了;任务状态还停在内存中,服务重启就没了。要保存状态,最容易写错的地方并不只是 `INSERT` 语句,而是:一个协程执行 JDBC 时如果换了线程、取消了 Job、甚至连接抛异常,**谁负责整个事务的提交、回滚和关闭**? 本篇继续使用 Kotlin 2.2.21、coroutines 1.10.2、Gradle 8.14、JDK 21、Ktor 3.3.1,在本机隔离临时目录启动 PostgreSQL 16.15 (Ubuntu 16.15-0ubuntu0.24.04.1);JDBC 驱动冻结为 org.postgresql:postgresql:42.7.7。驱动上游 tag REL42.7.7 指向注解对象 7d5a13de18cc77bdbc76a88de36fc61c00799022,剥离后源码 commit 为 9217ed16cb2918ab1b6b9258ae97e6ede244d8a0。版本组合在本机实际编译和运行,不能由这些版本号推断其他数据库驱动有同样的取消行为。依据是 JDK 21 Con...
Kotlin 34:HTTP 受理以后任务谁负责
33 的 JSON DTO能拒绝缺字段和错误类型,`TaskId` 与 `makeTaskDraft` 还能拒绝空白业务值。把这些校验搬进 HTTP 路由以后,`POST /tasks` 返回 202 是否意味着任务已经成功?如果浏览器离开,谁有权取消已经受理的任务?关键不在返回体措辞,而在**请求、后台 Job 和查询记录是否由同一所有者明确管理**。 本篇仍用 Kotlin 2.2.21、coroutines 1.10.2、serialization 1.9.0、Gradle 8.14、JDK 21,新增 Ktor core、Netty、content-negotiation、serialization-kotlinx-json、test-host 的 JVM 制品 3.3.1。源码 tag 3.3.1 SHA 为 49fb2bfb657cc74af6abadae9e11c765234dafa4。官方 Ktor 服务测试和创建服务文档于 2026-10-10 查阅;这些滚动页面当时已是更新版本,具体路径只能以本机 3.3.1 测试和解析树为证。Ktor 新增传递依赖使 JUn...
Kotlin 33:解码成功为何任务仍不合法
32 的热流只提供内存中的任务观察入口。接收外部任务之前还有一道不应省略的边界:JSON 能反序列化为 Kotlin 对象,是否说明这个对象可以成为业务任务?答案取决于**结构契约**与**领域不变量**是否都通过,二者不由同一个机制检查。 本篇冻结 Kotlin JVM/serialization 编译插件 2.2.21、kotlinx-serialization-json:1.9.0、Gradle 8.14、JDK 21、coroutines 1.10.2。序列化库 v1.9.0 tag SHA 16306f4c97e21e4d134bf1bb95fc20a61927f6b0,官方 CHANGELOG 注明该版要求 Kotlin 2.2。当前组合能构建和运行的依据是本机 Gradle 解析及测试日志,不是从版本号推断所有组合都兼容。文档依据为 Kotlin 官方序列化入口及 Json、ignoreUnknownKeys、explicitNulls API(2026-10-10 查阅);这些入口会滚动更新,实验只对应本篇锁定的依赖。 DTO 描述字段,不代表已接受的任务 累计工...
Kotlin 32:最新状态和事件通知会漏掉什么
31 的 flow 构造器只有收集时才执行。同一个进度流被两次收集,合成任务也做了两遍。如果任务服务需要让多个界面观察**同一条任务**,直接把这条冷流交给每个界面并不合适。把发布和观察拆开之后,另一个问题随之出现:订阅得太晚,或读得太慢,会失去哪些更新? 版本沿用 Kotlin 2.2.21、Gradle 8.14、JDK 21、coroutines core/test 1.10.2。契约依据是官方 StateFlow、SharedFlow 与 shareIn API;读取日期为 2026-10-10。以下观察来自本篇四组实际测试;库源码 tag SHA 5f8900478a8e20c073145b1608fbc71fe3d7378b 只标识依赖版本,不代表已追踪热流内部实现。 一条任务,两个不同的问题 TaskLiveUpdates 提供两个只读入口:state: StateFlow<TaskState> 和 events: SharedFlow<String>。内部的 MutableStateFlow 从 Queued 开始;通知使用默认的 Muta...
Go 39:空环境如何验收任务完整生命周期
38 章把累计任务服务做成可构建的进程。这还不是验收:提交响应、数据库记录和进程退出各自只能回答一个问题。本章从空目录和隔离 PostgreSQL 16.15 启动,把故障注入到同一个服务的入口、领取和终态提交点。完整工程与原始实验包、SHA-256、独立复跑步骤随文交付。 先定位要验证的承诺 源码冻结在 Go 1.27.1、lib/pq v1.12.3。serve.go:runTaskServer 只负责配置、监听和关闭;任务创建与查询仍在 http_tasks.go:create/lookup,SQL 条件领取与终态提交仍在 sql_tasks.go:Claim/Finish。包内 evidence/39/ 保存初版实验的源码哈希、符号位置和二进制版本;补齐后的当前源码由 CURRENT-SHA256SUMS 校验,不能用旧日志的哈希代替。capture39.sh 初始化全新 PostgreSQL 实例,go test/race 回归、构建程序,然后在专属 go39live 库运行 verification/39.sh。包外新目录还要重做一遍,不能将上一次 go test 输...










