## Resque stuck queue Ever run into that? Sucks, eh? This should enable a way to fire some handler when jobs aren't occurring within a certain timeframe. ## How it works When you call `start` you are essentially starting two threads that will continiously run until `stop` is called or until the process shuts down. One thread is responsible for pushing a 'heartbeat' job to resque which will essentially refresh a specific key in redis every time that job is processed. The other thread is a continious loop that will check redis (bypassing resque) for that key and check what the latest time the hearbeat job successfully updated that key. It will trigger a pre-defined proc (see below) if the last time the hearbeat job updated that key is older than the trigger_timeout setting (see below). ## Usage Configure it first:
# how often to push that 'heartbeat' job to refresh the latest time it worked.
Resque::StuckQueue.config[:heartbeat] = 5.minutes

# since there is an realistic and acceptable lag for job queues, set this to how much you're
# willing to accept between the current time and when the last hearbeat job went through.
#
# obviously, take the heartbeat into consideration when setting this
Resque::StuckQueue.config[:trigger_timeout] = 10.hours

# what gets triggered when resque-stuck-queue will detect the latest heartbeat is older than the trigger_timeout time set above.
#
# triggering will update the key, so you'll have to wait the trigger_timeout again 
# in order for it to trigger again even if workers are still stale.
Resque::StuckQueue.config[:handler] = proc { send_email }

# optional, in case you want to set your own name for the key that will be used as the last good hearbeat time
Resque::StuckQueue.config[:global_key] = "name-the-refresh-key-as-you-please"

# optional, if you want the resque-stuck-queue threads to explicitly raise, default is false
Resque::StuckQueue.config[:abort_on_exception] = true

# optional, pass a logger. Default a ruby logger will be instantiated. Needs to respond to that interface.
Resque::StuckQueue.config[:logger] = Logger.new($stdout)

Then start it:
Resque::StuckQueue.start                # blocking
Resque::StuckQueue.start_in_background  # sugar for Thread.new { Resque::StuckQueue.start }
Stopping it consists of the same idea:
Resque::StuckQueue.stop                 # this will block until the threads end their current iteration
Resque::StuckQueue.force_stop!          # force kill those threads and let's move on
## Deployment/Integration * Include this in the app in a config initializer of some sort. Note though, the resque-stuck threads will live alongside the app server process so you will need to explicitely handle `start` _and_ `stop`. If you're deployed in a forking-server environment and the whatever process has this does not get restarted the threads will keep on going indefinitely. * Run this as a daemon somewhere alongside the app/in your setup. ## Tests Run the tests: `bundle; bundle exec rake`