Ruby 怎样使 Sidekiq 的任务一个一个执行

rookie · 2022年09月16日 · 最后由 EvanYa 回复于 2022年10月08日 · 1021 次阅读

目前写了一个任务去处理从其它平台推送的数据,但是如果平台同一时间推送多条数据的话 处理数据会出现问题 想请教一下有没有办法让 sidekiq 任务一个一个执行

放在一个队列,然后只给一个线程执行这个队列?

专门一个队列,单 worker 单线程处理。

sidekiq enterprise 支持频率限制 https://github.com/mperham/sidekiq/wiki/Ent-Rate-Limiting

或者换 good_job,频率限制也是开源的 https://github.com/bensheldon/good_job#activejob-concurrency

Rei 回复

谢谢 我试一下

lifuzho 回复

谢谢 我试试

concurrency 开 1 行不行

说到 sidekiq enterprise 的 rate limiter, 今天写 test case 的时候,发现有个 case 特别慢,花了挺久才定位是有个 sidekiq job 里调用外部接口用到了 rate limiter, 虽然 web 请求被 stub 掉了,但是 rate limiter 生效了... 导致这个 case 特别慢;

处理方法是判断 test 环境不加 limiter(不确定有没有其他更好的处理方法)

Sidekiq 7 增加了新特性可以指定某些队列的并发数 https://github.com/mperham/sidekiq/blob/7-0/docs/7.0-Upgrade.md#capsules

让 sidekiq 任务一个一个执行

把这句话换成串行,应该会更容易搜索答案。有两种方式

  • 【推荐】专门的 queue 来处理该 job,只在一个 worker 上消费该 queue,worker 的 concurrency 设为 1(楼上好几位都提到了)
  • 把 job 聚合起来,再另一个 job 按顺序执行(同步执行)。这个sidekiq-grouping gem 已经实现了该功能

如果不同平台的 job 可以并行执行,那我们可以对该 queue 做个分区

platform_name = 'A'
queue = "platform" + "_" + hash_algorithm(platform_name) % 3
MyJob.set(queue: queue).perform_async(params)
# worker1
:concurrency: 1
:queues:
  - ["platform_0", 1]

# worker2
:concurrency: 1
:queues:
  - ["platform_1", 1]

# worker3
:concurrency: 1
:queues:
  - ["platform_2", 1]

换 good_job,频率限制也是开源的 https://github.com/bensheldon/good_job#activejob-concurrency

good_job 是 Postgres-based 的异步任务框架,还是建议使用 sidekiq

  • sidekiq 基于 redis,redis 相比 pg,redis 运维成本低(问题少,至少不需要一个专门的 DBA)
  • redis 可以水平拓展读写能力,pg 只能水平扩展读
  • 相同配置下,redis 读写性能强很多
需要 登录 后方可回复, 如果你还没有账号请 注册新账号