resque_worker_heartbeat 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- data/lib/resque/heartbeat.rb +127 -0
- data/lib/resque_worker_heartbeat/version.rb +3 -0
- data/lib/resque_worker_heartbeat.rb +1 -0
- metadata +90 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MjM5MGNjODExZjhhNzJjOTAxNjU0ZTJmZjE0MGM3NmViYmNkM2I4Ng==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ZTk3NDY4ZjgyNjcwOGM3YzZjZmJhM2YxYjc1ZWE2OWVlODg4OTNmZQ==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
MDk5NDdhMjkyMzljZGY1ZjI5MWYxZWQ3NmI5YzYxM2ZjMWUxNjlmOWEyOTAz
|
10
|
+
ZTQ1MmQyNTE0NWEwMDUzYzEwZDVhN2Q3OTJlZmZjYjliMDE2YTA1YzdiOGI2
|
11
|
+
NDM3ZGJiMDcwOTE0Nzg1NDk4ODI2MDZhNzM2N2U3NTkzZTBmZWY=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MmQ1OGY1ZTQzZTJmNTE0MDllNGJkN2I3ZjA3YTY1YzdjNDU4NDAzYzg0NjA0
|
14
|
+
MzVmOWNlY2JjYjBjODI5ODI1ZmRjYTZmOWE1NGQ0NmQyODAzNjk0ZjhkMGRj
|
15
|
+
NGM0ODYyNjNkMDI4YTBlMTY0ODhmZjdiODNhMDlkYjdkYmE0NWM=
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'resque'
|
2
|
+
|
3
|
+
module Resque
|
4
|
+
class Worker
|
5
|
+
alias_method(:startup_without_heartbeat, :startup)
|
6
|
+
def startup_with_heartbeat
|
7
|
+
startup_without_heartbeat
|
8
|
+
heart.run
|
9
|
+
end
|
10
|
+
alias_method(:startup, :startup_with_heartbeat)
|
11
|
+
|
12
|
+
alias_method(:unregister_worker_without_heartbeat, :unregister_worker)
|
13
|
+
def unregister_worker_with_heartbeat(*args)
|
14
|
+
heart.stop
|
15
|
+
unregister_worker_without_heartbeat(*args)
|
16
|
+
end
|
17
|
+
alias_method(:unregister_worker, :unregister_worker_with_heartbeat)
|
18
|
+
|
19
|
+
def heart
|
20
|
+
@heart ||= Heart.new(self)
|
21
|
+
end
|
22
|
+
|
23
|
+
def remote_hostname
|
24
|
+
id.split(':').first
|
25
|
+
end
|
26
|
+
|
27
|
+
def dead?
|
28
|
+
return heart.dead?
|
29
|
+
end
|
30
|
+
|
31
|
+
def prune_if_dead
|
32
|
+
return nil unless dead?
|
33
|
+
|
34
|
+
Resque.logger.info "Pruning worker '#{remote_hostname}' from resque"
|
35
|
+
unregister_worker
|
36
|
+
end
|
37
|
+
|
38
|
+
class Heart
|
39
|
+
attr_reader :worker
|
40
|
+
|
41
|
+
def self.heartbeat_interval_seconds
|
42
|
+
ENV['HEARTBEAT_INTERVAL_SECONDS'] || 2
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.heartbeats_before_dead
|
46
|
+
ENV['HEARTBEATS_BEFORE_DEAD'] || 25
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
def initialize(worker)
|
51
|
+
@worker = worker
|
52
|
+
end
|
53
|
+
|
54
|
+
def run
|
55
|
+
@thrd ||= Thread.new do
|
56
|
+
loop do
|
57
|
+
begin
|
58
|
+
beat! && sleep(2)
|
59
|
+
rescue Exception => e
|
60
|
+
Resque.logger.error "Error while doing heartbeat: #{e} : #{e.backtrace}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def stop
|
67
|
+
Thread.kill(@thrd)
|
68
|
+
redis.del key
|
69
|
+
rescue
|
70
|
+
nil
|
71
|
+
end
|
72
|
+
|
73
|
+
def redis
|
74
|
+
Resque.redis
|
75
|
+
end
|
76
|
+
|
77
|
+
# you can send a redis wildcard to filter the workers you're looking for
|
78
|
+
def Heart.heartbeat_key(worker_name)
|
79
|
+
"worker:#{worker_name}:heartbeat"
|
80
|
+
end
|
81
|
+
|
82
|
+
def key
|
83
|
+
Heart.heartbeat_key worker.remote_hostname
|
84
|
+
end
|
85
|
+
|
86
|
+
def beat!
|
87
|
+
redis.sadd(:workers, worker)
|
88
|
+
redis.setex(key, Heart.heartbeat_interval_seconds * Heart.heartbeats_before_dead, '')
|
89
|
+
rescue Exception => e
|
90
|
+
Resque.logger.fatal "Unable to set the heartbeat for worker '#{worker.remote_hostname}': #{e} : #{e.backtrace}"
|
91
|
+
end
|
92
|
+
|
93
|
+
def dead?
|
94
|
+
!redis.exists(key)
|
95
|
+
end
|
96
|
+
|
97
|
+
def ttl
|
98
|
+
Resque.redis.ttl key
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# NOTE: this assumes all of your workers are putting out heartbeats
|
104
|
+
def self.prune_dead_workers!
|
105
|
+
begin
|
106
|
+
beats = Resque.redis.keys(Worker::Heart.heartbeat_key('*'))
|
107
|
+
Worker.all.each do |worker|
|
108
|
+
worker.prune_if_dead
|
109
|
+
|
110
|
+
# remove the worker from consideration
|
111
|
+
beats.delete worker.heart.key
|
112
|
+
end
|
113
|
+
|
114
|
+
# at this point, beats only contains stuff from workers we don't even know about. Ditch 'em.
|
115
|
+
beats.each do |key|
|
116
|
+
Resque.logger.info "Removing #{key} from heartbeats because the worker isn't talking to Resque."
|
117
|
+
Resque.redis.del key
|
118
|
+
end
|
119
|
+
rescue Exception => e
|
120
|
+
p e
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def self.dead_workers
|
125
|
+
Worker.all.select{|w| w.dead?}
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'resque/heartbeat'
|
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: resque_worker_heartbeat
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sven Fuchs
|
8
|
+
- Jon Phillips
|
9
|
+
- Andy Sykes
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2014-01-17 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: resque
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.25.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - ~>
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: 1.25.0
|
29
|
+
- !ruby/object:Gem::Dependency
|
30
|
+
name: rspec
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - ! '>='
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '0'
|
36
|
+
type: :development
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ! '>='
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
- !ruby/object:Gem::Dependency
|
44
|
+
name: rake
|
45
|
+
requirement: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ! '>='
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
type: :development
|
51
|
+
prerelease: false
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ! '>='
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
description: Gives Resque workers a heartbeat to allow dead worker detection
|
58
|
+
email: developers@forward3d.com
|
59
|
+
executables: []
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- lib/resque/heartbeat.rb
|
64
|
+
- lib/resque_worker_heartbeat.rb
|
65
|
+
- lib/resque_worker_heartbeat/version.rb
|
66
|
+
homepage: https://github.com/forward3d/resque_worker_heartbeat
|
67
|
+
licenses:
|
68
|
+
- MIT
|
69
|
+
metadata: {}
|
70
|
+
post_install_message:
|
71
|
+
rdoc_options: []
|
72
|
+
require_paths:
|
73
|
+
- lib
|
74
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ! '>='
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
requirements: []
|
85
|
+
rubyforge_project:
|
86
|
+
rubygems_version: 2.1.11
|
87
|
+
signing_key:
|
88
|
+
specification_version: 4
|
89
|
+
summary: Gives Resque workers a heartbeat to allow dead worker detection
|
90
|
+
test_files: []
|