最近实在是太忙了,尤其是上线一个大版本除了一些事故,所以有必要整理下。
在使用安全令确认之后,登录界面立马又自动跳回输入密码的页面。
我第一反应就是打开调试工具看看有没有报错,的确是有些错误信息。但是这个错误信息是之前就有的。
第二就是打开google搜索下看看有没有人碰到了一样的问题。
在折腾了几个小时之后,一无所获。没办法只好硬着头皮去请教大佬,原来大佬之前就已经遇到过这个问题了。
大佬给出的解决方式是:需要使用同一个的QWebEngineProfile
我仔细说下是什么意思:
1、我们项目登录页面使用到了QWebEngine控件是继承了QtExtWebEngineView,而QtExtWebEngineView又是继承了QtWebEngineView。
2、因为我们有一些特殊的要求所以重写QWebEnginePage。
那么子类控件在初始化的时候会先初始化父类QtExtWebEngineView,而这个父类里面调用了setPage()函数。
在父类初始化完成之后,在子类里面又再次调用了setPage(),使用的是我们自定义QWebEnginePage。
而在调用setPage()时,每次都会重新new 一个QWebEngineProfile。两个不同的QWebEngineProfile,所以就造成了上面的问题。
解决方案:不再调用父类的setPage(),而是延迟到子类中调用
崩溃原因:链式调用
发现这个问题有点偶然性,上线后的第二天下午。我突然想起来这次发布新版本怎么一点消息都没有,根据以往的经验升级这么的事情总要有点幺蛾子才对啊,我就有点好奇,就上了网站看看崩溃收集日志。
一看,就蒙了。崩溃数目直线上升,都已经上千了。
立马下载了dump文件和日志。(这里插入另外一件事件PDB文件被覆盖了,无法进行更详细的分析。)只能依靠日志文件。
经过紧张的一个小时分析之后,发现玩家在玩第二把游戏的时候,突然就崩溃了。
然后着手测试果然崩溃了,崩溃点的代码类似如下,这段代码在第一次调用的时候还没有崩溃,在第二次必崩。
{
QSet<QString> str_set(m_data_.values().begin(), m_data_.values().end());
// QList str_list;
}
我分析了崩溃的原因:
最后修改如下:
{
QList<QString> str_list = m_data_.values();
QSet<QString> str_set(str_list.begin(), str_list.end());
}
最大的问题来了。
当我把bug修复好之后,QA在回归没有问题之后,就准备再上线更新。到此问题已经解决了。万万没想到就是在更新这里出问题了。
简单一句话:更新程序失败了。
刹那间,大家都沉默了。
还得要排查什么原因造成的。最后发现也是升级造成的。
因为升级高版本我们使用了QWebEngine作为浏览器,而QWebEngine是个独立的进程,它占用了一些资源文件。
而我们的升级程序还有个备份文件功能,用来做升级失败的时候还原的。升级程序一直删除文件失败,从而导致了更新失败。
我们就在分析代码还有没有其他的路径可以更新,结果就只有一条路更新。
当务之急,我们就立马关闭了升级的渠道。阻止用户暂时的升级。
然后让PM准备出个公告,让已经升级的用户自己手动去官网下载重新安装。
至此,又是个不眠夜啊。
在这次的升级过程,还有许多地方做得不到位,需要改进。
1、没有及时反馈线上的真实情况,比如邮件通知崩溃数。事后已经加了邮件通知。
2、出现情况没有及时关闭用户的更新通道,导致受影响的用户不断的增加。
3、更新程序的太单一,需要重构。
4、PDB文件的没有管理好,带来事后分析的难度。
总结起来其实就是一句话,缺少反馈机制,导致我们反应很迟钝。
更新其实是个很小,很不起眼的功能,但是真的非常重要。侧面反映对版本的控制很弱。
事后想想还是挺后怕的,一旦发现的更晚,那就是影响到了全量用户,就是个很严重的事故了。
所以一定要建立一个快速,强力的反馈回路,才能做到对事故的应激反应。