我目前正在开发一个与 meritmoot.com (该项目处于开发阶段,采用滚动发布模式)相关的插件。由于该项目使用了外部数据,我使用了一个长时间运行的 Sidekiq 任务。但不幸的是,出于某种原因,该任务会不断重新启动内部任务代码,既没有标记任务失败,也没有输出任何错误信息。请问 Sidekiq 是否有某些配置或机制可能导致这种重启行为?
在我最近一次任务(本应每天仅执行一次)中,该任务与“签到”(Roll Calls)相关,却在没有报错的情况下于以下时间点反复重启:
0 小时 58 分 42 秒(首次迭代开始时间)
1 小时 30 分 12 秒(第一次重启)
2 小时 1 分 1 秒(第二次重启)
3 小时 46 分 49 秒
4 小时 17 分 11 秒
4 小时 47 分 33 秒
该任务未能完成,所有进度都被重置。值得注意的是,我有自己的日志记录流程,会重定向内部代码的 stderr 和 stdout,但我怀疑这不会干扰 Sidekiq。(如果你需要查看,我可以提供,这对开发非常有用!)
我可以在代码中保存已完成的进度,但更希望采用更简单的流程,因为保存进度会带来额外开销。请问是否有我可能忽略的 Sidekiq 配置或机制,导致我的代码触发重启?
Falco
(Falco)
2020 年5 月 8 日 02:00
2
所以你想要一个每次运行故意耗时超过一小时的 Sidekiq 任务?能再详细解释一下原因吗?
2 个赞
我正在接收大量外部数据,并将其存储在我的网站内部。这些数据涉及美国国会信息。
编辑:例如公开可用的法案、投票记录以及议员信息。
1 个赞
您是否遇到内存不足的问题?在我们的托管服务中,Sidekiq 已设置为在内存使用过高时自动重启。
2 个赞
这里的 memory 是指数据库或硬盘内存吗?我确实占用了很多这类资源。目前我正在参考 @pfaffman 的一个稍作修改的建议:我 fork 一个进程,让主线程退出,但生成一个具有相同上下文的子进程(相对于 Sidekiq 来说,这本质上是一个外部脚本)。
1 个赞
测试来自 https://stackoverflow.com/questions/806267/how-to-fire-and-forget-a-subprocess#806326 的以下模式以解决问题:
pid = Process.fork
if pid.nil? then
# 在子进程中
exec "whatever --take-very-long"
else
# 在父进程中
Process.detach(pid)
end
这是一个有点奇怪的问题,但我所连接的 API 没有更新功能,因此我基本上是通过每天重新下载 API 的大量数据来刷新数据:
几个小时后我会告诉你进展如何。
编辑:又停止了——我想我会定期保存进度,并研究如何使其更高效。
1 个赞
sam
(Sam Saffron)
2020 年5 月 13 日 02:49
8
与其这样做,为什么不教你的工作分成更小的块来处理?真的需要花费4个小时吗?先同步10个主题,再同步另外10个……以此类推。
Sidekiq 本身没有终止长时间运行作业的功能,但应用的重建会做到这一点,甚至通过 Web UI 进行的升级也会如此。
4 个赞
感谢所有的帮助!
我最终移除了进程代码,因为效果不佳。重启任务只是掩盖了一个根本问题:效率太低 。我现在改用了以下方法:
编写批量 SQL 代码(比顺序执行快得多),检测真正需要更新的情况,并允许我跳过使用 PostRevisor 类来重新更新未变更的项目。
通过使用持久连接以及其他数据点(包括压缩项,在可能的情况下)来提高通过 HTTP 检索数据的效率。
我发现编写批量 SQL 命令能带来巨大的速度提升。我正在更新的是:
post 表:cooked、last_updated 列
topic 表:title、last_updated 列
我的下一个想法是完全跳过 PostRevisor,采用类似以下的方案:
将数据移动到临时表
UPDATE topics FROM temp_table
SET topics.title = temp_table.title, topics.last_updated = temp_table.last_updated
WHERE topics.id = temp_table.id AND topics.title != temp_table.title
UPDATE posts FROM temp_table
SET posts.raw = temp_table.raw, posts.last_updated = temp_table.last_updated
WHERE posts.id = temp_table.id AND posts.raw != temp_table.raw
然后触发搜索重新索引任务,因为标题和内容已更改。
我是否忽略了什么?Discourse 系统很复杂,跳过 PostRevisor 让我感觉可能会触碰到我不熟悉的表(例如 post_stats、post_timings、post_uploads、quoted_posts,这些我在数据库中见过)。不过,我也不需要 PostRevisor 提供的所有验证功能,因为系统是从一个可信且可预测的来源获取这些修订的。这个方案似乎有点碰运气。
你怎么看?
1 个赞
更新说明:由于发现一段时间内出现了异常数量的更新,我进行了一些代码检查,结果发现存在一个问题,导致某些原始 JSON 格式实际上并未变更的数据项被不必要地更新。一旦该错误得到修复,上述操作可能就不再需要了🙏。早知道就该先做测试……那样就能节省我大量 时间了。不过,我可能还是会尝试一下上述方案,只是不会作为优先事项。它在我更改数据呈现格式时,有助于快速更新。而且代码已经写好了,只是尚未测试。
1 个赞
批量更新代码已完成——您是否希望在它更加稳定后将其推送到特定分支?该代码的使用场景较为特定,但就其功能而言,能够快速更新成千上万条记录,包括标签。它是基于 TopicsBulkAction 扩展构建的。如果您需要更详细的信息,以下是我编写的 README:
# 输入
# - 哈希列表,每个哈希包含:cooked、post_id、topic_id、title、updated_at、tags(raw 将指向 cooked)
# [{post_id: #, cooked: "", topic_id: #, title: "", updated_at: date_time, tags: [{tag: "", tagGroup: ""}, ... ] } , ... ]
# - category_name:被更新类别的名称。此字段用于搜索索引。
# 列表项中可包含的可选哈希属性:
# - raw:若未包含,则默认等于 cooked。
# - fancy_title:若未包含,则默认等于 title。
# - slug:若未包含,则从 title 生成(这与 URL 相关)。
# 使用场景:以高效方式定期从不断变化的非 Discourse 后端数据源更新主题,以同步更新信息。
# 注意:此代码并非用于一般的帖子或主题发布,而是专门用于更新主题的标题及其主帖。
# 如需进行一般性帖子修订,请前往 lib/post_revisor.rb 中的 PostRevisor。
# - 假设数据已预处理(cooked)、自定义 cooked 或直接按原样使用。数据未经过验证。
# - 如果您的 raw 等于 cooked,则在创建帖子时应设置 (cook_methods: Post.cook_methods[:raw_html])。
# 这适用于您编写自定义 HTML 并在帖子内部显示的情况。
# 否则,Discourse 未来可能会重新处理(re-cook)该内容,这将带来问题。请确保信息来源可信,且其内容已正确转义。
# - 如果上述方式不理想,请确保包含 raw 字段,在创建帖子时设置正确的 cook 方法(以防系统重新处理),
# 将 raw 通过您选择的 cook 方法处理,并在哈希中包含 raw 以及处理后的 cooked 内容。
# - 通过记录帖子处理前后的字数差异,并将其传递给主题,来跟踪字数统计。
# - 以类似方式跟踪标签数量。
1 个赞