Blair Anderson
Blair Anderson

Reputation: 20171

Rails debounce delayed job background task? removing duplicates

Debouncing is a common method to postpone a function/job from executing until after certain time has passed.

Use-case: A conversation with active chatting from multiple users, they should not receive an email notification for each message typed. But more than likely after a few minutes of silence, if the messages are unread, the user should see a notification.

Delayed_Job

Has no solution, has related issues: https://github.com/collectiveidea/delayed_job/issues/72

Sidekiq

https://github.com/hummingbird-me/sidekiq-debounce

Upvotes: 4

Views: 1328

Answers (3)

Blair Anderson
Blair Anderson

Reputation: 20171

Doing yourself is not so bad.

class AdminJob
  def self.debounce(job, args={})
    handler = YAML.dump(job)
    count = Delayed::Job.where(handler: handler).where('locked_at IS NULL').delete_all
    Rails.logger.info("deleted: #{count} jobs")
    Delayed::Job.enqueue(job, args)
  end
end

Instead of writing:

Delayed::Job.enqueue(YourJobName.new(account_id), {run_at: 10.minutes.from_now})

You now write:

AdminJob.debounce(YourJobName.new(account_id), {run_at: 10.minutes.from_now})

Delayed job serializes your job params in YAML and then saves it to the database as handler. So if you call AdminJob.debounce(...) 10 times in a row, it will delete before each.

Make sure to give yourself time (5.minutes, etc) to give users to keep taking actions. If you run your job after 1 second, its likely they'll keep taking actions and trigger again.

Yes i'm answering my own question 3 years later...

Upvotes: 3

Johan Casier
Johan Casier

Reputation: 1

If you are using Delayed Job as the implementation for Active Job then take a look at the 'activejob-trackable' gem. https://github.com/ignatiusreza/activejob-trackable

It uses another table that tracks the jobs and can throttle and debounce.

Upvotes: 0

neboduus
neboduus

Reputation: 418

What I would do is schedule a periodic task, lets say every 5 minutes that checks if there is someone who has to be notified. Yes it seems an expensive operation, but for your use case I don't see (for now) others solutions. So lets say you have 10 users that uses a chat. Every 5 minutes you could check if there are users that didn't see some messages, and if so you notify them only if they are inactive from N minutes.

To schedule such task you could use crono gem. Check this answer.

Crono lets you do thing like that:

Crono.perform(CheckUsersToBeNotifiedJob).every 5.minutes

Upvotes: 0

Related Questions