Add the schedule message function to Hutch.
See hutch-schedule-demo how to integration with rails.
Add this line to your application's Gemfile:
gem 'hutch-schedule'And then execute:
$ bundle
Or install it yourself as:
$ gem install hutch-schedule
Use the code below to initialize the Hutch::Schedule
Hutch::Schedule.connectThey will do something below:
- Declear an topic exchange called
<hutch>.schedulejust for routing message to delay_queue<5s>. - Declear an queue named
<hutch>_delay_queue_<5s>and with some params:
- Set
x-dead-letter-exchange: <hutch>: let queue republish message to default exchange. - Set
x-message-ttl: <30.days>: to avoid the queue is to large, because there is no consumer with this queue.
- If ActiveJob is loaded. it will use
ActiveJob::Base.descendantsto register all ActiveJob class to one-job-per-consumer to Hutch::Consumer
| Name | Default Value | Description |
|---|---|---|
| worker_pool_size | 20 | Monkey patch the Hutch::Worker set the FixedThreadPool thread size(not the bunney ConsumerWorkPool size) |
| poller_interval | 1 | seconds of the poller to trigger, poller the message in BufferQueue submit to FixedThreadPool |
| poller_batch_size | 100 | the message size of every batch triggerd by the poller |
| redis_url | redis://127.0.0.1:6379/0 | Redis backend url for Ratelimit and Unique Job |
| ratelimit_bucket_interval | 1 | Ratelimit use the time bucket (seconds) to store the counts, lower the more accurate |
| worker_buffer_flush_interval | 6 | Monkey patch, flush the Hutch::Worker.@buffer_queue message to RabbitMQ check interval |
Let consumer to include Hutch::Enqueue then it has the ability of publishing message to RabbitMQ with the consume '<routing_key>'.
Only support enqueue Hash format message
- enqueue: just publish one message
- enqueue_in: publish one message and delay seconds
- enqueue_at: publish one message and auto calculate the seconds need to delay
- enqueue_uniq(_in/at): publish uniq message with uniq_key
According to the RabbitMQ TTL Message design limits (discus), We design the fixed delay level from seconds to hours, below is the details:
- seconds(4): 5s, 10s, 20s, 30s
- minutes(14): 1m, 2m, 3m, 4m, 5m, 6m, 7m, 8m, 9m, 10m, 20m, 30m, 40m, 50m
- hours(3): 1h, 2h, 3h
RabbitMQ is not fit for storage lot`s of delay message so if you want delay an message beyand 3 hours so you need to storage it into database or some place.
Let consumer to include Hutch::Threshold to get the ability of threshold the message consume. It's automatic included when
consumer include Hutch::Enqueue.
- static configuration
class PlanConsumer
include Hutch::Consumer
include Hutch::Enqueue
attempts 3
consume 'abc.plan'
# threshold 3 jobs per second
threshold rate: 3, interval: 1
end- dynamic lambada
class PlanConsumer
include Hutch::Consumer
include Hutch::Enqueue
attempts 3
consume 'abc.plan'
# threshold 2 jobs every 2 second with get_report context
threshold -> { { context: 'get_report', rate: 2, interval: 2 } }
endthreshold lambada need get return value must be a Hash and include:
- context: the limit context with current threshold
- rate: the rate speed of threshold
- interval: the time range of threshold
If you want use error retry, then:
- Add
Hutch::ErrorHandlers::MaxRetrytoHutch::Config.error_handlerslike below
Hutch::Config.error_handlers << Hutch::ErrorHandlers::MaxRetry.new- Let
Hutch::Consumerto includeHutch::Enqueueand setupattempts
class PlanConsumer
include Hutch::Consumer
include Hutch::Enqueue
attempts 3
consume 'abc.plan'
endError retry will use ActiveJob exponentially_longer algorithm (executes**4) + 2 seconds
Add an hutch.rb to conf/initializers:
# reuse Hutch config.yaml file
Hutch::Config.load_from_file(Rails.root.join('config', 'config.yaml'))
# replace error_handlers with Hutch::ErrorHandlers::MaxRetry
Hutch::Config.error_handlers = [Hutch::ErrorHandlers::MaxRetry.new]
# Init Hutch and Hutch::Schedule
Hutch::Schedule.connectThen you can enqueue message in Rails console like below:
PlanConsumer.enqueue(a: 1)
# or schedule message
PlanConsumer.enqueue_in(5.seconds, a: 1)Config rails to use :hutch active_job adapter:
config.active_job.queue_adapter = :hutch
config.active_job.queue_name_prefix = 'ajd'
class EmailJob < ApplicationJob
queue_as :email
retry_on StandardError, wait: :exponentially_longer
def perform(user_id)
user = User.find(user_id)
user.send_email
end
end
# in rails console, you can
EmailJob.perform_later(user.id)
# or
EmailJob.set(wait: 5.seconds).perform_later(user.id)Because we use monkey patch to add some new features so if you direct use hutch cli and don't have some place to require hutch-schedule gem it won't be function.
- When direct use hutch cli only have one hook for rails app to load external depencency so if the app is not an rails app right now will not working.
- Hutch Config files must load during rails app initlization because monkey patch
Hutch::Configneed to load and then to work
Bug reports and pull requests are welcome on GitHub at https://github.com/wppurking/hutch-schedule. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.
The gem is available as open source under the terms of the MIT License.
Use the repo: https://github.com/wppurking/hutch-schedule-demo
| Woker | Publish | Consume | Comment |
|---|---|---|---|
| Hutch | 13261 msg/s | 5700 msg/s | |
| ActiveJob | 6100 job/s | 1700 job/s | ActiveJob serilizer job get large message size slow the speed |
- add cron job support