resque-bus 0.2.10 → 0.3.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.
- data/README.mdown +69 -0
- data/lib/resque-bus.rb +18 -1
- data/lib/resque_bus/driver.rb +1 -1
- data/lib/resque_bus/heartbeat.rb +96 -0
- data/lib/resque_bus/version.rb +1 -1
- data/spec/driver_spec.rb +1 -1
- data/spec/heartbeat_spec.rb +46 -0
- metadata +5 -2
data/README.mdown
CHANGED
@@ -101,6 +101,75 @@ If you want retry to work for subscribing apps, you should run resque-scheduler
|
|
101
101
|
|
102
102
|
$ rake resquebus:driver resque:scheduler
|
103
103
|
|
104
|
+
### Heartbeat
|
105
|
+
|
106
|
+
We've found it useful to have the bus act like cron. Triggering timed jobs throughout the system. Resque Bus calls this a heartbeat.
|
107
|
+
It uses resque-scheduler to trigger the events. You can enable it in your Rakefile.
|
108
|
+
|
109
|
+
# resque.rake
|
110
|
+
namespace :resque do
|
111
|
+
task :setup => [:environment] do
|
112
|
+
ResqueBus.heartbeat!
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
Or add it to your `schedule.yml` directly
|
117
|
+
|
118
|
+
resquebus_heartbeat:
|
119
|
+
cron: "* * * * *"
|
120
|
+
class: "::ResqueBus::Heartbeat"
|
121
|
+
queue: resquebus_incoming
|
122
|
+
description: "I publish a heartbeat_minutes event every minute"
|
123
|
+
|
124
|
+
It is the equivalent of doing this every minute
|
125
|
+
|
126
|
+
seconds = minutes * (60)
|
127
|
+
hours = minutes / (60)
|
128
|
+
days = minutes / (60*24)
|
129
|
+
|
130
|
+
now = Time.at(seconds)
|
131
|
+
|
132
|
+
attributes = {}
|
133
|
+
|
134
|
+
|
135
|
+
now = Time.now
|
136
|
+
seconds = now.to_i
|
137
|
+
ResqueBus.publish("hearbeat_minutes", {
|
138
|
+
"epoch_seconds" => seconds,
|
139
|
+
"epoch_minutes" => seconds / 1.minute,
|
140
|
+
"epoch_hours" => seconds / 1.hour,
|
141
|
+
"epoch_days" => seconds / 1.day,
|
142
|
+
"minute" => now.min
|
143
|
+
"hour" => now.hour
|
144
|
+
"day" => now.day
|
145
|
+
"month" => now.month
|
146
|
+
"year" => now.year
|
147
|
+
"yday" => now.yday
|
148
|
+
"wday" => now.wday
|
149
|
+
})
|
150
|
+
|
151
|
+
This allows you do something like this:
|
152
|
+
|
153
|
+
ResqueBus.dispatch("app_c") do
|
154
|
+
# runs at 10:20, 11:20, etc
|
155
|
+
subscribe "once_an_hour", 'bus_event_type' => 'heartbeat_minutes', 'minute' => 20 do |attributes|
|
156
|
+
Sitemap.generate!
|
157
|
+
end
|
158
|
+
|
159
|
+
# runs every five minutes
|
160
|
+
subscribe "every_five_minutes", 'bus_event_type' => 'heartbeat_minutes' do |attributes|
|
161
|
+
next unless attributes["epoch_minutes"] % 5 == 0
|
162
|
+
HealthCheck.run!
|
163
|
+
end
|
164
|
+
|
165
|
+
# runs at 8am on the first of every month
|
166
|
+
subscribe "new_month_morning", 'bus_event_type' => 'heartbeat_minutes', 'day' => 1, hour' => 8, 'minute' => 0, do |attributes|
|
167
|
+
next unless attributes["epoch_minutes"] % 5 == 0
|
168
|
+
Token.old.expire!
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
|
104
173
|
### Compatibility
|
105
174
|
|
106
175
|
ResqueBus can live along side another instance of Resque that points at a different Redis server.
|
data/lib/resque-bus.rb
CHANGED
@@ -3,12 +3,12 @@ require "resque_bus/version"
|
|
3
3
|
require 'redis/namespace'
|
4
4
|
require 'resque'
|
5
5
|
|
6
|
-
|
7
6
|
module ResqueBus
|
8
7
|
|
9
8
|
autoload :Application, 'resque_bus/application'
|
10
9
|
autoload :Dispatch, 'resque_bus/dispatch'
|
11
10
|
autoload :Driver, 'resque_bus/driver'
|
11
|
+
autoload :Heartbeat, 'resque_bus/heartbeat'
|
12
12
|
autoload :Local, 'resque_bus/local'
|
13
13
|
autoload :Matcher, 'resque_bus/matcher'
|
14
14
|
autoload :Publisher, 'resque_bus/publisher'
|
@@ -71,6 +71,23 @@ module ResqueBus
|
|
71
71
|
def local_mode
|
72
72
|
@local_mode
|
73
73
|
end
|
74
|
+
|
75
|
+
def heartbeat!
|
76
|
+
# turn on the heartbeat
|
77
|
+
# should be down after loading scheduler yml if you do that
|
78
|
+
# otherwise, anytime
|
79
|
+
require 'resque/scheduler'
|
80
|
+
name = 'resquebus_hearbeat'
|
81
|
+
schedule = { 'class' => '::ResqueBus::Heartbeat',
|
82
|
+
'cron' => '* * * * *', # every minute
|
83
|
+
'queue' => incoming_queue,
|
84
|
+
'description' => 'I publish a heartbeat_minutes event every minute'
|
85
|
+
}
|
86
|
+
if Resque::Scheduler.dynamic
|
87
|
+
Resque.set_schedule(name, schedule)
|
88
|
+
end
|
89
|
+
Resque.schedule[name] = schedule
|
90
|
+
end
|
74
91
|
|
75
92
|
# Accepts:
|
76
93
|
# 1. A 'hostname:port' String
|
data/lib/resque_bus/driver.rb
CHANGED
@@ -0,0 +1,96 @@
|
|
1
|
+
module ResqueBus
|
2
|
+
# publishes event about the current time
|
3
|
+
class Heartbeat
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
def lock_key
|
8
|
+
"resquebus:heartbeat:lock"
|
9
|
+
end
|
10
|
+
|
11
|
+
def lock_seconds
|
12
|
+
60
|
13
|
+
end
|
14
|
+
|
15
|
+
def lock!
|
16
|
+
now = Time.now.to_i
|
17
|
+
timeout = now + lock_seconds + 2
|
18
|
+
|
19
|
+
# return true if we successfully acquired the lock
|
20
|
+
return timeout if Resque.redis.setnx(lock_key, timeout)
|
21
|
+
|
22
|
+
# see if the existing timeout is still valid and return false if it is
|
23
|
+
# (we cannot acquire the lock during the timeout period)
|
24
|
+
return 0 if now <= Resque.redis.get(lock_key).to_i
|
25
|
+
|
26
|
+
# otherwise set the timeout and ensure that no other worker has
|
27
|
+
# acquired the lock
|
28
|
+
if now > Resque.redis.getset(lock_key, timeout).to_i
|
29
|
+
return timeout
|
30
|
+
else
|
31
|
+
return 0
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def unlock!
|
36
|
+
Resque.redis.del(lock_key)
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
def redis_key
|
41
|
+
"resquebus:heartbeat:timestamp"
|
42
|
+
end
|
43
|
+
|
44
|
+
def get_saved_minute!
|
45
|
+
key = ResqueBus.redis.get(redis_key)
|
46
|
+
return nil if key.nil?
|
47
|
+
return key.to_i
|
48
|
+
end
|
49
|
+
|
50
|
+
def set_saved_minute!(epoch_minute)
|
51
|
+
ResqueBus.redis.set(redis_key, epoch_minute)
|
52
|
+
end
|
53
|
+
|
54
|
+
def perform
|
55
|
+
real_now = Time.now.to_i
|
56
|
+
run_until = lock! - 2
|
57
|
+
return if run_until < real_now
|
58
|
+
|
59
|
+
while((real_now = Time.now.to_i) < run_until)
|
60
|
+
minutes = real_now.to_i / 60
|
61
|
+
last = get_saved_minute!
|
62
|
+
if last
|
63
|
+
break if minutes <= last
|
64
|
+
minutes = last + 1
|
65
|
+
end
|
66
|
+
|
67
|
+
seconds = minutes * (60)
|
68
|
+
hours = minutes / (60)
|
69
|
+
days = minutes / (60*24)
|
70
|
+
|
71
|
+
now = Time.at(seconds)
|
72
|
+
|
73
|
+
attributes = {}
|
74
|
+
attributes["epoch_seconds"] = seconds
|
75
|
+
attributes["epoch_minutes"] = minutes
|
76
|
+
attributes["epoch_hours"] = hours
|
77
|
+
attributes["epoch_days"] = days
|
78
|
+
|
79
|
+
attributes["minute"] = now.min
|
80
|
+
attributes["hour"] = now.hour
|
81
|
+
attributes["day"] = now.day
|
82
|
+
attributes["month"] = now.month
|
83
|
+
attributes["year"] = now.year
|
84
|
+
attributes["yday"] = now.yday
|
85
|
+
attributes["wday"] = now.wday
|
86
|
+
|
87
|
+
ResqueBus.publish("heartbeat_minutes", attributes)
|
88
|
+
set_saved_minute!(minutes)
|
89
|
+
end
|
90
|
+
|
91
|
+
unlock!
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|
data/lib/resque_bus/version.rb
CHANGED
data/spec/driver_spec.rb
CHANGED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module ResqueBus
|
4
|
+
describe Heartbeat do
|
5
|
+
def now_attributes
|
6
|
+
{
|
7
|
+
"epoch_seconds" => (Time.now.to_i / 60) * 60, # rounded
|
8
|
+
"epoch_minutes" => Time.now.to_i / 60,
|
9
|
+
"epoch_hours" => Time.now.to_i / (60*60),
|
10
|
+
"epoch_days" => Time.now.to_i / (60*60*24),
|
11
|
+
"minute" => Time.now.min,
|
12
|
+
"hour" => Time.now.hour,
|
13
|
+
"day" => Time.now.day,
|
14
|
+
"month" => Time.now.month,
|
15
|
+
"year" => Time.now.year,
|
16
|
+
"yday" => Time.now.yday,
|
17
|
+
"wday" => Time.now.wday
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should publish the current time once" do
|
22
|
+
Timecop.freeze "12/12/2013 12:01:19" do
|
23
|
+
ResqueBus.should_receive(:publish).with("heartbeat_minutes", now_attributes)
|
24
|
+
Heartbeat.perform
|
25
|
+
end
|
26
|
+
|
27
|
+
Timecop.freeze "12/12/2013 12:01:40" do
|
28
|
+
Heartbeat.perform
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should publish a minute later" do
|
33
|
+
Timecop.freeze "12/12/2013 12:01:19" do
|
34
|
+
ResqueBus.should_receive(:publish).with("heartbeat_minutes", now_attributes)
|
35
|
+
Heartbeat.perform
|
36
|
+
end
|
37
|
+
|
38
|
+
debugger
|
39
|
+
|
40
|
+
Timecop.freeze "12/12/2013 12:02:01" do
|
41
|
+
ResqueBus.should_receive(:publish).with("heartbeat_minutes", now_attributes)
|
42
|
+
Heartbeat.perform
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: resque-bus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-09-
|
12
|
+
date: 2013-09-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: resque
|
@@ -164,6 +164,7 @@ files:
|
|
164
164
|
- lib/resque_bus/application.rb
|
165
165
|
- lib/resque_bus/dispatch.rb
|
166
166
|
- lib/resque_bus/driver.rb
|
167
|
+
- lib/resque_bus/heartbeat.rb
|
167
168
|
- lib/resque_bus/local.rb
|
168
169
|
- lib/resque_bus/matcher.rb
|
169
170
|
- lib/resque_bus/publisher.rb
|
@@ -182,6 +183,7 @@ files:
|
|
182
183
|
- spec/application_spec.rb
|
183
184
|
- spec/dispatch_spec.rb
|
184
185
|
- spec/driver_spec.rb
|
186
|
+
- spec/heartbeat_spec.rb
|
185
187
|
- spec/integration_spec.rb
|
186
188
|
- spec/matcher_spec.rb
|
187
189
|
- spec/publish_at_spec.rb
|
@@ -220,6 +222,7 @@ test_files:
|
|
220
222
|
- spec/application_spec.rb
|
221
223
|
- spec/dispatch_spec.rb
|
222
224
|
- spec/driver_spec.rb
|
225
|
+
- spec/heartbeat_spec.rb
|
223
226
|
- spec/integration_spec.rb
|
224
227
|
- spec/matcher_spec.rb
|
225
228
|
- spec/publish_at_spec.rb
|