发布时间:2026/7/23 21:27:34
从 OptaPlanner 7.x 到 8.x,我们只改了 3 个地方 一次“受控恐慌”后的冷静迁移一、起因一次并不严重的“事故”事情是从测试环境的一句日志开始的。那天上午测试同学反馈APS 排产偶尔点完按钮页面一直转圈。​后台日志里没有明显的Exception但有一个线程长时间处于WAITING状态。重启服务后问题消失。再跑几次又复现但概率很低。我们第一反应是“是不是 JDK 17 OptaPlanner 7.x Drools 的老问题终于爆了”老实说当时心里是有点慌的。毕竟 APS 是生产核心模块谁也不想背一个“排产算不出来”的锅。二、决策不是“大升级”而是“小修补”在翻了一圈 OptaPlanner 的 issue 和社区讨论后我们发现这个问题在 8.x 里被反复提及但没有明确的“已修复”标记7.x 官方早已停止维护但 8.x 的 API 变动看起来“可控”于是我们定了一个原则不动业务逻辑只动“不得不改”的地方。换句话说这不是一次“架构升级”而是一次“打补丁式的迁移”。三、真正改动的只有这 3 个地方事后统计我们一共改了3 个文件加起来不到 50 行代码。1️⃣ApsConstraintProviderpenalize() 变得“更数学了”这是我们最早碰到的编译错误。7.x 的老代码private Constraint capabilityConflict(ConstraintFactory constraintFactory) { return constraintFactory.from(Task.class) .filter(t - { if (t.getResourceBo() null) { return false; } if (CollUtil.isEmpty(t.getResourceBo().getCapabilityIds())) { return true; } else { return !t.getResourceBo().getCapabilityIds() .containsAll(t.getCapabilityIds()); } }) .penalize(Capability conflict, HardSoftScore.ofHard(10)); }8.x 的新写法private Constraint capabilityConflict(ConstraintFactory constraintFactory) { return constraintFactory.from(Task.class) .filter(t - { if (t.getResourceBo() null) { return false; } if (CollUtil.isEmpty(t.getResourceBo().getCapabilityIds())) { return true; } else { return !t.getResourceBo().getCapabilityIds() .containsAll(t.getCapabilityIds()); } }) .penalize(HardSoftScore.ONE_HARD) .multiply(10); }我们在 Code Review 时是怎么解释的我当时跟同事说“以前是‘一次性扣 10 分’现在是‘先扣 1 分再放大 10 倍’。”听起来像文字游戏但其实语义更清晰了ONE_HARD是一个单位惩罚.multiply(10)是权重系数以后如果要把权重放到配置中心这个写法会非常自然.multiply(penaltyConfig.getCapabilityConflictWeight())这不是语法糖这是可维护性的提升。2️⃣StartTimeUpdatingVariableListener从“地下”走到“地上”这个改动是最让我舒服的一个。7.x 的 importimport org.optaplanner.core.impl.domain.variable.listener.VariableListener; import org.optaplanner.core.impl.score.director.ScoreDirector;8.x 的 importimport org.optaplanner.core.api.domain.variable.VariableListener; import org.optaplanner.core.api.score.director.ScoreDirector;为什么这是个好信号因为impl这个包名在 Java 世界里通常意味着一句话“别碰我我随时可能变。”我们之前写VariableListener心里多少有点“偷用内部 API”的不安。现在它被挪到api包说明了一件事OptaPlanner 承认你写的这种监听器是合法扩展。这对我们这种“自己维护影子变量”的 APS 系统来说是个定心丸。3️⃣ScoreDirector字符串 → Lambda最实用这可能是日常开发中感知最强的一个变化。7.x 的写法scoreDirector.beforeVariableChanged(task, planStartTime); task.setPlanStartTime(newTime); scoreDirector.afterVariableChanged(task, planStartTime);8.x 的写法scoreDirector.beforeVariableChanged(task, Task::getPlanStartTime); task.setPlanStartTime(newTime); scoreDirector.afterVariableChanged(task, Task::getPlanStartTime);我们为什么喜欢这个改动举个真实的例子有一次我们重构Task类把字段从planStartTime改成了startTime。在 7.x 时代这类改动非常危险Java 编译器不知道你在字符串里写的是什么只有运行时才会抛异常单元测试稍不注意就漏掉但在 8.xIDE 直接标红重构字段名lambda 自动跟着改编译期就把问题拦住了我当时在群里发了一句“就冲这个 lambda这趟升级就值了。”四、迁移过程中的两个“小插曲”插曲一一开始我们以为要改很多约束打开ApsConstraintProvider看到十几个约束方法心里咯噔一下。结果发现过滤逻辑一个都没变只有penalize()的写法变了而且 IDE 的批量替换 正则就能搞定大半插曲二担心 Shadow Variable 会不会崩我们有多个影子变量CustomShadowVariable担心 8.x 会有行为变化。实际验证下来监听器触发时机一致计算逻辑无误求解结果在多个数据集上完全一致五、我们怎么验证“没改坏”迁移完成后我们没有立刻上线而是做了三轮验证回归测试用生产脱敏数据跑 100 次求解对比 7.x 与 8.x 的求解结果和分数构成性能对比平均求解时间波动在 ±5% 以内GC 行为无明显变化异常注入模拟并发提交、服务重启验证 SolverManager 行为是否一致最终结论是这次升级没有改变 APS 的任何业务语义。六、回头看这次迁移的价值是什么如果只是为了“修那个偶发线程卡死”我们其实可以只加 JVM 参数。但我们还是做了 8.x 的迁移原因有三把“隐患”往前挪了一步7.x 是死胡同8.x 至少还有社区参考为 Timefold 铺路8.x 的 API 更接近 Timefold将来迁移成本更低团队信心大家亲手改过知道“哪里会变、哪里不变”七、一句话总结从 7.x 到 8.x不是一次“冒险”而是一次“低成本、高确定性的技术避险”。如果你也在犹豫要不要升我的建议是JDK 17 下能跑就先别动真要动就只动“必须动”的地方动完之后一定要验证而不是假设

相关新闻

2026/7/23 21:27:33

1Panel 服务器运维管理

1Panel 是一个现代化、开源的 Linux 服务器运维管理面板。它提供直观的 Web 图形界面,帮助用户轻松管理 Linux 服务器中的应用、网站、文件、数据库以及大语言模型(LLMs)等。 第一部分:1Panel 概述 一、什么是 1Panel?…

2026/7/23 21:27:33

一文搞懂出口摩洛哥必备COC认证全部要求

摩洛哥COC认证是清关的硬门槛,2025年起全面数字化。本文从法律要求、宗教禁忌、实操流程三方面拆解,帮出口商少走弯路,顺利通关。一、为什么非办不可?2020年6月起,电器、建材、玩具、纺织品等全品类强制要求COC&#x…

2026/7/23 22:53:04

《课题申报:避开两处大忌,轻松写出高分申请书》

“诸位伏案撰写教育部课题项目之师友,是否呕心沥血打磨文稿,递呈上去却屡遭专家指出疏漏,一番苦心付诸东流?今日小生便与大家拆解两处申报大忌,切莫误入歧途。 其一,切莫虚抬研究价值。不少人在阐述研究意义…

2026/7/23 22:53:04

安全设备越来越多,为什么企业还是会出问题?

过去几年,很多企业持续加大网络安全投入。防火墙、EDR、WAF、堡垒机、日志平台……安全设备越来越多,安全体系看起来也越来越完善。但现实情况却是,安全事件并没有因此消失。不少企业在发生安全事件后复盘发现,问题往往不是没有设…

2026/7/23 22:53:04

数据岗 AI 工作流改造:依托大模型解决业务数据分析痛点

从事企业数据分析工作近五年,从传统离线报表统计到实时业务数据复盘,我始终深陷在数据岗最典型的低效困境里。在大模型全面普及之前,我们数据团队的日常工作高度同质化且机械繁琐:业务方提出临时分析需求后,需要先梳理…

2026/7/23 22:53:04

Kotlin 协程与结构化并发:Scope、Job 与取消

文章目录第 1 章 协程是什么:轻量任务 结构化并发踩坑第 2 章 launch 与 async:事件 vs 结果踩坑第 3 章 Dispatcher:Main / IO / Default踩坑第 4 章 取消与协作第 5 章 SupervisorJob:子失败不拖垮全家第 6 章 异常处理与测试踩…

2026/7/23 22:53:04

一封核查申请信件滞留多日,到底该由哪个科室签收受理?

6月29日,我寄出一封EMS快件,里面是一套案件相关的举证申请材料,希望院领导对21920号案件相关程序情况予以核查。此前在案件审理阶段,我申请以第三人身份参与诉讼,仅得到口头答复,并未出具书面意见。快递收件…

2026/7/23 22:48:03

Doker背景——服务器技术架构演进之路

目录 概述 常见概念 基本概念 应用/系统 模块(Module)/ 组件(Component) 分布式(Distributed) 集群(Cluster) 主(Master)/ 从(Slave&…

2026/7/23 12:54:51

Unity与Python本地通信:基于Flask的跨语言数据交换实战

1. 项目概述:为什么我们需要一个本地通信服务器?在游戏开发、数字孪生、仿真训练等众多领域,Unity作为强大的实时3D内容创作平台,其核心逻辑通常由C#驱动。然而,当我们需要进行复杂的数据分析、机器学习推理、科学计算…

2026/7/23 0:01:10

Chitchatter完整指南:免费开源的终极点对点安全聊天工具

Chitchatter完整指南:免费开源的终极点对点安全聊天工具 【免费下载链接】chitchatter Secure peer-to-peer chat that is serverless, decentralized, and ephemeral 项目地址: https://gitcode.com/gh_mirrors/ch/chitchatter Chitchatter是一款革命性的安…

2026/7/22 21:00:12

3个高效策略:快速掌握Axure中文界面配置

3个高效策略:快速掌握Axure中文界面配置 【免费下载链接】axure-cn Chinese language file for Axure RP. Axure RP 简体中文语言包。支持 Axure 11、10、9。不定期更新。 项目地址: https://gitcode.com/gh_mirrors/ax/axure-cn 还在为Axure RP的英文界面感…