diff --git a/README b/README new file mode 100644 index 0000000..e69de29 diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..47e7ef4 --- /dev/null +++ b/Rakefile @@ -0,0 +1,10 @@ +require 'rake' +require 'rake/testtask' + +Rake::TestTask.new do |t| + t.libs << 'lib' + t.pattern = 'test/**/*_test.rb' + t.verbose = false +end + +task :default => :test diff --git a/lib/resque/heartbeat.rb b/lib/resque/heartbeat.rb new file mode 100644 index 0000000..36cf21e --- /dev/null +++ b/lib/resque/heartbeat.rb @@ -0,0 +1,70 @@ +require 'resque' + +module Resque + def self.prune_dead_workers + begin + Worker.all.each { |worker| worker.prune_if_dead } + rescue Exception => e + p e + end + end + + class Worker + def startup_with_heartbeat + startup_without_heartbeat + heart.run + end + alias startup_without_heartbeat startup + alias startup startup_with_heartbeat + + def heart + @heart ||= Heart.new(self) + end + + def prune_if_dead + unregister_worker if heart.last_beat_before?(5) + end + + class Heart + attr_reader :worker + + def initialize(worker) + @worker = worker + end + + def run + Thread.new { loop { sleep(2) && beat! } } + end + + def redis + @redis && connected? ? @redis : @redis = connect + end + + def connect + # apparently the Redis connection is not thread-safe, so we connect another instance + # see https://github.com/ezmobius/redis-rb/issues#issue/75 + redis = Redis.connect(:url => Travis.config['redis']['url']).tap { |redis| redis.client.connect } + Redis::Namespace.new(:resque, :redis => redis) + end + + def connected? + @redis.client.connected? + end + + def beat! + redis.sadd(:workers, worker) + redis.set("worker:#{worker}:heartbeat", Time.now.to_s) + rescue Exception => e + p e + end + + def last_beat_before?(seconds) + Time.parse(last_beat).utc < (Time.now.utc - seconds) rescue true + end + + def last_beat + Resque.redis.get("worker:#{worker}:heartbeat") || worker.started + end + end + end +end diff --git a/lib/resque_heartbeat.rb b/lib/resque_heartbeat.rb new file mode 100644 index 0000000..fad9009 --- /dev/null +++ b/lib/resque_heartbeat.rb @@ -0,0 +1 @@ +require 'resque/heartbeat' diff --git a/lib/resque_heartbeat/version.rb b/lib/resque_heartbeat/version.rb new file mode 100644 index 0000000..83624ec --- /dev/null +++ b/lib/resque_heartbeat/version.rb @@ -0,0 +1,3 @@ +module ResqueHeartbeat + VERSION = "0.0.1" +end diff --git a/resque-heartbeat.gemspec b/resque-heartbeat.gemspec new file mode 100644 index 0000000..561bde4 --- /dev/null +++ b/resque-heartbeat.gemspec @@ -0,0 +1,19 @@ +# encoding: utf-8 + +$:.unshift File.expand_path('../lib', __FILE__) +require 'resque_heartbeat/version' + +Gem::Specification.new do |s| + s.name = "resque-heartbeat" + s.version = ResqueHeartbeat::VERSION + s.authors = ["Sven Fuchs"] + s.email = "svenfuchs@artweb-design.de" + s.homepage = "http://github.com/svenfuchs/resque-heartbeat" + s.summary = "[summary]" + s.description = "[description]" + + s.files = `git ls-files app lib`.split("\n") + s.platform = Gem::Platform::RUBY + s.require_path = 'lib' + s.rubyforge_project = '[none]' +end