循环中缓存已更新却无法返回结果的问题排查
以下是几种可能导致循环内无法读取缓存的原因及对应的排查方法:
进程间缓存配置不匹配
Delayed Job工作进程和API服务器进程的Rails缓存配置可能存在差异,比如Redis的命名空间、实例地址或数据库编号不同。这会导致Delayed Job写入的缓存key在API进程中完全不可见,自然读不到结果。
排查方式:分别在两个进程中执行Rails.cache.send(:key_for, :recently_removed_lot_ids),对比生成的最终缓存key是否一致;也可以直接查看两个进程的config/environments/*.rb中的缓存配置项。任务执行耗时超出循环等待窗口
循环最多等待20秒(10次×2秒),但如果Lot相关的查询(比如ids_removed_from_syndication_in_last)本身耗时超过20秒,或者Delayed Job的worker队列堆积、没有及时拾取任务,那么在循环结束前缓存还未被写入。后续调用API时任务已经执行完成,所以能读到结果。
排查方式:查看Delayed Job的任务日志,确认任务的开始和完成时间,对比API请求的时间线;给LotService.cache_recently_removed_lot_ids添加日志,记录数据计算和缓存写入的总耗时。already_queued?方法逻辑错误
如果LotsRecentlyRemovedCacheJob.already_queued?的判断逻辑有误,比如误判任务已经在队列中,导致第一次循环时没有触发perform_later,那么循环期间缓存根本不会被写入,只有后续调用API时才会触发任务执行。
排查方式:在API代码中添加日志,打印LotsRecentlyRemovedCacheJob.already_queued?的返回值,确认第一次循环时是否正确触发了任务入队;查看Delayed Job的任务队列,确认任务是否在第一次API请求时被创建。缓存序列化/反序列化兼容性问题
若API进程和Delayed Job进程的Ruby、Rails版本不一致,或者缓存序列化器(如Marshal)存在兼容性问题,可能导致API进程无法正确反序列化缓存中的数组。不过后续调用能读到结果的话,这个概率较低,但仍可排查。
排查方式:在Delayed Job任务中写入缓存后,立即读取并打印缓存内容;在API进程的循环中也打印读取到的原始值,确认是nil还是反序列化后的异常值。
内容的提问来源于stack exchange,提问作者Michael Glenn

