记一次线上'事故'处理
今早十点左右(2019年12月23日 10:00), 项目运营反馈新版 App 有闪退问题,我放下手中开发工作,开始排查问题所在:经过查看崩溃日志发现,已经开始大面积影响线上用户了
15770939012210.jpg通过报错信息,我很快确定了问题所在: 新版 App 和旧版本之间本地缓存的兼容问题,由于新版本缓存数据中缓存的键值对新增,导致对新 key 存取值报错。
具体原因
项目中网约车模块由之前的「首汽约车」和「红旗智行」两个独立的子项目合并成独立的一个项目。由于平台的融合,项目中管理约车平台和用户类型的类有较大改动。由之前的单平台逻辑修改为现在多平台逻辑。新逻辑如下:
WX20191223-183759@2x.png新版本逻辑中将平台信息和用户类型信息同时保存到了一个字典中,属于字典套字典类型,工具类统一管理顶层字典。可以实现的功能为:用户在 App 中平台信息随时切换,用户类型信息随时切换。约车过程中平台信息也会随着约车状态变化。
突然想到,这里和 Runloop 中的 Mode 设置的逻辑很像,每个平台下的各个用户类型互不影响。对应不同 Mode 下的源互不影响
原因
新版本中只判断了 App 中是否有缓存,遗漏了缓存中没有「sqhq」平台的情况的适配。
只是判断了有没有缓存文件,有缓存但是没有「sqhq」平台的情况没有处理导致后面崩溃。
影响
1. 网约车整个模块
2. 用户退出 App.退出 App 会整体对平台置为最基本的「sqhq」类型
处理方案
对于用户:
卸载 App 重装,彻底清理缓存
对于开发:
重写缓存数据的处理,对于兼容问题引以为戒
下面是一些问题排查时候的记录
设计原因
整个工具类,只提供了类方法处理平台和用户类型的存取。所以缓存文件也放到了类的初始化方法 + initialize
中。
关于 + initialize 和 + load 方法
load 方法
在类或者分类添加到 OC runtime 时候调用,可在此方法中设置类相关的行为
类的 load 方法在新类和新分类添加或链接的时候调用,其中的方法实现会根据最后一次的 load 而确定。类初始化顺序如下
1. 先初始化自己链接的库文件
2. 初始化自己类
3. 初始化项目中 C++ 和 __attribute__(constructor)
4. 初始化动态链接自己的 frameworks
其中 load 方法的加载顺序为:superClass -> subClass -> category.
所以在 load 阶段不要调用其他类的方法,此时其他类的 load 可能还没加载。
initialize 方法
即类的初始化方法,仅为类的初始化,执行顺序位于上面第三步。从方法在类的声明周期内只会执行一次,即分类和类本身只会执行一次。如果做类或者分类的独立处理,需要在 load 方法中。
此方法调用顺序 superClass -> subClass
如果在子类调用中调用父类 initialize 可以通过 if (self == [ClassName self]) 来保护父类只执行一次
经验教训
- 对于向后兼容问题,需要注意,在测试过程中需要引起注意
- 随着用户数增多,突然觉得自己的代码变得更有意义了
网友评论