Tempo Team Planning 死循环分析与解决思路

故障现象

  • 使用 Tempo Team Planning 的时候, 在创建 Plan 并选择 project 类型查询时, project 下拉框会卡死, 紧接着整个浏览器会卡死.

故障分析

  1. 使用 Chrome 打开 Tempo Team Planning 的页面, 调出 Developer Tools(Win 系统按快捷键 F12)
  2. 清空”Console”和”Network”选项卡中的记录(这是在分析多次后才这样做, 前期分析时可以看看 Console 和 Network 中是否有什么有用的信息, 没有的话以后可以清空掉)
  3. 选中一个日期, 在页面左侧的”Create Plan”面板中选中”Plan item type”为”Project”
  4. 点击”Plan item”的下拉框, 即可出现下图情况
    获取项目权限
    这里可以看到, 瞬间出现了 2500+个请求, 并且可以看到请求类型时xhr. 在这个瞬间并发和等待服务器返回的过程中, 可以看到 Chrome 的 CPU 占用了如下:
    Chrome CPU
  5. 这时我们再看看这么多的请求, 返回的都是什么
    获取项目权限详情
    可以看到, 原来请求的是每个项目对应的权限信息, 再细看, 会发现除了请求 url 后面的时间戳, 基本上都是重复的 url. 而点击每个重复的 url 返回的信息, 也都是一样的.
  6. 这就可以猜测, 实际上这重复请求的 url 应该是插件的 bug, 可能是因为前面的请求没有及时返回, 就不停的请求, 直到真实的项目数对应的请求都返回了, 才会停止请求.
    而请求的申请是异步的, 所以插件就会在前一批请求没有返回的时候又申请一批请求. 就如此的申请了 2500+个请求.
  7. 并且可以看到在最开始的请求中, 有一条是用来查询有多少项目
    获取项目权限详情
    这里可以看到有 47 个项目, 那么实际上在发出请求 47 个项目权限信息时就可以不用再发送请求了.

故障梳理

  • Tempo Team Planning 插件在请求 project 列表后, 需要查询每个 project 的对应操作权限并保存下来以后使用
  • Tempo Team Planning 使用了异步批量查询 project 权限的办法, 一个批次的量是 project 的总数, 并在每个 url 后面加上了时间戳(加上时间戳用于防止浏览器认为是无限调用而强迫停止, 并且可以让服务器知道你没有在重复调用这个借口)
  • Tempo Team Planning 查询了权限后没有增加足够长的超时时间(甚至感觉连一秒都没加), 而且服务器不可能那么快返回 Tempo Team Planning 请求的数据
  • Tempo Team Planning 就会判定为服务器超时, 尝试又一次发送异步的批量查询, 此时服务器依然没有返回数据. 那么 Tempo Team Planning 就会无限循环下去, 直到第一批的权限查询的请求都有返回了, 才停止重复查询在这个几乎无限循环查询的情况下, 就会导致 CPU 占用极高, 直到第一批查询返回了, CPU 使用率才会慢慢降下来.

解决思路

既然梳理出来故障原因, 那么可以采取两个方法解决问题

修改插件源码

由于修改插件需要定位插件包里对于的 js 文件, 而在 Developer Tools 中调试的 js 文件又都是压缩处理过了, 问题函数不好定位, 并且每次修改完插件后要传到服务器上调试, 周期非常长. 所以就不考虑这个方案了.

拦截机制

有没有这样的一种机制:

  1. 可以在页面加载的时候插入一段自己写的 js 代码, 用于拦截 xhr 请求.
  2. 将符合规则的 url 请求保存到一个数组中.
  3. 每次遇到符合规则的请求就对比这个数组, 如果这个数组里没有这个 url 请求就放行, 并保存到这个数组中. 如果有这个请求就拦截. 这样就能最大程度减少损耗

以上逻辑就可以解决大批量提交请求的时候导致 CPU 使用率升高的问题.

优化拦截机制

  • 以上的拦截机制会有两个问题
  1. 假设我们的项目只有 50 个, 那么后面对于数组的查询和对比就是多余的了.
    所以可以在 Tempo Team Planning 获取到 project 列表的时候统计出这个列表的元素个数.
    那么这个数组的元素就是 50 个, 那么只要当数组长度大于 50 的时候, 就直接拦截符合规则的请求即可.

  2. 数组被填充完毕后, 想要再次获取到 project 信息就必须让浏览器刷新, 否则所有请求都会被拦截.
    这时候可以对这个数组当长度大于 0 时进行 30 秒钟一次的清理

Chrome 插件

多方了解过后, 选择了 Chrome 插件, 对于此插件的代码分析, 后续会发布出来.

参考

插件 GITHUB 库
Tempo Team Planning 死循环 bug 解决方案
JTP UnLoop 插件分析

显示 Gitment 评论