前一段时间系统遇到一个很费解的问题,花了大半天的时间才找到原因。这个问题的场景稍微有点特殊,一般不容易碰到,因此也很容易被忽略。
背景
这个系统有上百个模块(dll),其中有些模块涉及到核心业务流程,客户的安全审计部门要求这些模块的任何变动都需要走审计流程。
这些核心dll在第一次发布的时候已经通过客户的审计,我们把这些核心dll提交到单独的git repostiory。
后续对一些非核心模块的改动后,为了避免核心dll被重新编译导致dll变动(因为所有的模块project都在同一个solution里),在打包的时候会直接用git repo上审计过的dll替换掉被重新编译的核心dll。
然而,就是因为dll替换的原因导致了这次问题。
问题的产生
最近,客户提出一个新功能,我们就新加了一个模块。新模块里面涉及到一些配置项,这些配置项的key是放在一个enum里, 配置项的值放在DB表里;这个配置项key的enum在一个公用的contract project里(这个是非审计dll)。
为了简化问题描述,下面虚构一下项目的结构。
更新前
- Demo.Contract – 不需要审计
- SystemSettings.cs
public enum SystemSettings
{
IS_A_ENABLED,
IS_B_ENABLED,
A_TIME_OUT,
}
- Bussiness.Core – 已经审计过的dll
- BussinessManager.cs
public class BussinessManager
{
var isBEnabled = _systemSettingsProvider.Get(SystemSettings.IS_B_ENABLED);
// Core Logic
}
更新后
新加的模块需要在SystemSettings enum里添加新的配置项key。
Bussiness.Core是审计dll,虽然会被重新编译到 (都在同一个solution里),但在最终打包的时候会用被审计过的dll替换掉。
public enum SystemSettings
{
IS_A_ENABLED,
IS_NEW_MODULE_ENABLED,
IS_B_ENABLED,
A_TIME_OUT,
}
- NewModule.NonCore
- NewBusinessManager
public class NewBussinessManager
{
var isNewModuleEnabled = _systemSettingsProvider.Get(SystemSettings.IS_NEW_MODULE_ENABLED); // 注: _systemSettingsProvider不在审计dll里
// New Module Logic
}
问题
升级过版本后,发现Bussiness.Core的业务逻辑不正确了,通过我上面的描述,大家应该能很容易看出问题所在。
身处当时的场景和我们解决问题的思路,
- 我们首先想到的是不是系统集成或服务器环境有问题,检查了一波没有什么问题。
- 再次确认我们新版本是不是误动了审计dll或版本发错了,检查了一波没有什么问题。
- 定位了许久基本确定是配置项没生效。我们检查了系统配置项的DB表,发现配置的值也没有问题。
搞了半天,这个问题处于焦灼状态,大家也没什么其他想法可能会导致这个问题;
这时我就联想到,很久之前在另一个项目碰到过因为网络不稳定原因导致传到服务器的包莫名的少了几KB,导致系统不工作。
因此我就建议,从环境里把对应的dll拿出来,反编译看一下。
原因
反编译之后,对照配置项的逻辑一看,然后大家就恍然大悟了。就是因为在enum中间添加了IS_NEW_MODULE_ENABLED,然后导致IS_B_ENABLED的值从1变成2。
而审计的dll里面引用的IS_B_ENABLED仍然是老的1(编译时就把enum 值塞进去了)。
解决办法
把新加的enum 值放在最下面。
总结
其实这个问题可以很早就发现,但因为种种原因导致没有在本地测到替换后的版本。
总体来说,这不仅是一个技术问题,也是一个流程控制问题。