别再自己写重试循环了!Temporal让Java代码执行像数据库一样持久化


百万行Java代码里90%的崩溃恢复逻辑,最终都败给了一个没考虑到的Kafka超时,这难道不荒唐吗?

关系数据库用预写日志保证了数据不丢,现在Temporal.io用同样的套路保证你的代码跑完。这东西叫持久化执行,就是把程序运行状态像存钱一样存下来,服务器炸了都不怕。Java开发者们,你们的重试循环和状态机代码可能要失业了。

数据库出现之前的黑暗年代还在你代码里重演

你写支付流程的时候,是不是先扣钱,再锁库存,然后发邮件,最后叫物流?每一步都可能挂掉。你怎么办?加个状态字段,搞个定时任务扫表,再写个重试计数器,最后拉个群专门盯订单状态。这套组合拳打出来,每个项目都差不多,但每个都烂得独一无二。

那个叫Temporal.io的东西看不下去了。它说,你们这帮人写的代码,像极了数据库出现之前,每个程序都自己管文件、自己搞锁、自己折腾崩溃恢复的样子。那时候每个程序都觉得自己能搞定,结果数据丢得乱七八糟。现在你们对程序执行流程干的事,跟当年一模一样。

你写的那堆status列、retry_count字段、还有那个每五分钟跑一次的清理Job,本质上就是在给运行中的程序做崩溃恢复。这活数据库在数据层面干得漂漂亮亮,到了代码执行层面,大家又退回了原始社会。

预写日志这招不只能对付数据库崩溃

数据库为啥重启之后数据还在?因为它有个预写日志,干啥事都先记一笔,再真正动手。万一崩了,重启就把日志重放一遍,状态全回来。

Temporal对Java代码干的事一模一样。你的Workflow里每一步——调了个活动、等了个定时器、收到了个返回值——全都变成事件写进历史记录里。跑你代码的JVM突然挂了?没关系,换个Worker节点,把历史记录重放一遍,你的局部变量retriesRemaining值还在,循环走到第几步还记得。

你的代码得是确定性的,就是同样的输入必须走同样的路径。这跟事件溯源要求的一样,只不过这次被保护的对象是你整个业务流程。你那些在内存里飘来飘去的变量,现在有了持久化保险。

跨月跨年的交易事务不再是笑话

数据库的事务再牛,也就撑个几秒。你见过哪个ACID事务能等三十天的?Temporal的Workflow能直接写sleep(30天),然后这三十天里不占任何线程、任何Pod、任何JVM内存。

三十天后定时器一响,哪怕这期间你部署了四十次新版本,服务器全换了一遍,这个Workflow照常醒来,接着发续费提醒邮件。就像一个被遗忘在角落里但永远会响的闹钟,只不过这个闹钟跨了无数次服务器重启。

对于那种跑好几年、事件数破万的长流程,它还有个叫"继续为新"的招数,能把历史记录重置,避免文件太大。这叫啥?这叫把你的业务流程变成了一个打不死的小强,停在哪就从哪爬起来,不用从头再来。

你早就享受过这种待遇,只是没意识到

虚拟内存让你假装电脑内存无限大,操作系统在背后偷偷换页。Temporal让你假装你的进程永生不死,在不同机器间随意切换。

垃圾回收把你从手动free()内存的苦海里救了出来。Temporal把你从手动写重试循环的苦海里救了出来。你现在写card.charge()不用管连接超时怎么办,就像你写new Object()不用管最后谁把它清掉一样自然。

Kubernetes说"保持三个副本运行"是个目标,系统自己会往那个状态靠。Temporal说"这段代码跑完"是个目标,平台自己会往那个状态靠,中间挂掉多少个Worker都没关系。这模式你早就用上了,只不过现在轮到了代码执行这个层面。

你的Java代码能删掉多少行

用了Temporal,你第一件事就是去删代码。删掉那些状态标记列和扫它们的定时任务,删掉每个外部调用外面的重试循环,删掉那些问"这步是不是已经跑过了"的幂等记账代码,删掉那些为了扛失败而搞出来的队列加定时任务的管道。

剩下来的代码长什么样?就长成业务本身的样子:扣钱,锁库存,发邮件,等发货,三十天后提醒续费。一行接一行的直白Java,所有可靠性工程全被一个专门干这活的平台接走了。

你四十年前就不再自己写文件系统日志了。再过几年,回头看现在这帮人用队列、定时任务、状态标志硬凑执行恢复的样子,就跟看古人钻木取火一样。

就像数据库让你的数据持久化了一样,Temporal.io正在让你的代码执行也持久化。那个半夜被叫起来修订单状态的兄弟,终于能睡个安稳觉了。