resque-loner 1.0.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,115 @@
1
+ # Redis configuration file example
2
+
3
+ # By default Redis does not run as a daemon. Use 'yes' if you need it.
4
+ # Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
5
+ daemonize yes
6
+
7
+ # When run as a daemon, Redis write a pid file in /var/run/redis.pid by default.
8
+ # You can specify a custom pid file location here.
9
+ pidfile ./spec/redis-test.pid
10
+
11
+ # Accept connections on the specified port, default is 6379
12
+ port 9736
13
+
14
+ # If you want you can bind a single interface, if the bind option is not
15
+ # specified all the interfaces will listen for connections.
16
+ #
17
+ # bind 127.0.0.1
18
+
19
+ # Close the connection after a client is idle for N seconds (0 to disable)
20
+ timeout 300
21
+
22
+ # Save the DB on disk:
23
+ #
24
+ # save <seconds> <changes>
25
+ #
26
+ # Will save the DB if both the given number of seconds and the given
27
+ # number of write operations against the DB occurred.
28
+ #
29
+ # In the example below the behaviour will be to save:
30
+ # after 900 sec (15 min) if at least 1 key changed
31
+ # after 300 sec (5 min) if at least 10 keys changed
32
+ # after 60 sec if at least 10000 keys changed
33
+ save 900 1
34
+ save 300 10
35
+ save 60 10000
36
+
37
+ # The filename where to dump the DB
38
+ dbfilename dump.rdb
39
+
40
+ # For default save/load DB in/from the working directory
41
+ # Note that you must specify a directory not a file name.
42
+ dir ./spec/
43
+
44
+ # Set server verbosity to 'debug'
45
+ # it can be one of:
46
+ # debug (a lot of information, useful for development/testing)
47
+ # notice (moderately verbose, what you want in production probably)
48
+ # warning (only very important / critical messages are logged)
49
+ loglevel debug
50
+
51
+ # Specify the log file name. Also 'stdout' can be used to force
52
+ # the demon to log on the standard output. Note that if you use standard
53
+ # output for logging but daemonize, logs will be sent to /dev/null
54
+ logfile stdout
55
+
56
+ # Set the number of databases. The default database is DB 0, you can select
57
+ # a different one on a per-connection basis using SELECT <dbid> where
58
+ # dbid is a number between 0 and 'databases'-1
59
+ databases 16
60
+
61
+ ################################# REPLICATION #################################
62
+
63
+ # Master-Slave replication. Use slaveof to make a Redis instance a copy of
64
+ # another Redis server. Note that the configuration is local to the slave
65
+ # so for example it is possible to configure the slave to save the DB with a
66
+ # different interval, or to listen to another port, and so on.
67
+
68
+ # slaveof <masterip> <masterport>
69
+
70
+ ################################## SECURITY ###################################
71
+
72
+ # Require clients to issue AUTH <PASSWORD> before processing any other
73
+ # commands. This might be useful in environments in which you do not trust
74
+ # others with access to the host running redis-server.
75
+ #
76
+ # This should stay commented out for backward compatibility and because most
77
+ # people do not need auth (e.g. they run their own servers).
78
+
79
+ # requirepass foobared
80
+
81
+ ################################### LIMITS ####################################
82
+
83
+ # Set the max number of connected clients at the same time. By default there
84
+ # is no limit, and it's up to the number of file descriptors the Redis process
85
+ # is able to open. The special value '0' means no limts.
86
+ # Once the limit is reached Redis will close all the new connections sending
87
+ # an error 'max number of clients reached'.
88
+
89
+ # maxclients 128
90
+
91
+ # Don't use more memory than the specified amount of bytes.
92
+ # When the memory limit is reached Redis will try to remove keys with an
93
+ # EXPIRE set. It will try to start freeing keys that are going to expire
94
+ # in little time and preserve keys with a longer time to live.
95
+ # Redis will also try to remove objects from free lists if possible.
96
+ #
97
+ # If all this fails, Redis will start to reply with errors to commands
98
+ # that will use more memory, like SET, LPUSH, and so on, and will continue
99
+ # to reply to most read-only commands like GET.
100
+ #
101
+ # WARNING: maxmemory can be a good idea mainly if you want to use Redis as a
102
+ # 'state' server or cache, not as a real DB. When Redis is used as a real
103
+ # database the memory usage will grow over the weeks, it will be obvious if
104
+ # it is going to use too much memory in the long run, and you'll have the time
105
+ # to upgrade. With maxmemory after the limit is reached you'll start to get
106
+ # errors for write operations, and this may even lead to DB inconsistency.
107
+
108
+ # maxmemory <bytes>
109
+
110
+ ############################### ADVANCED CONFIG ###############################
111
+
112
+ # Glue small output buffers together in order to send small replies in a
113
+ # single TCP packet. Uses a bit more CPU but most of the times it is a win
114
+ # in terms of number of queries per second. Use 'yes' if unsure.
115
+ glueoutputbuf yes
@@ -0,0 +1,14 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'rspec'
4
+
5
+ require 'ruby-debug'
6
+ require 'mock_redis'
7
+ require 'resque'
8
+ require 'resque-loner'
9
+
10
+ RSpec.configure do |config|
11
+ config.before(:suite) do
12
+ Resque.redis = MockRedis.new
13
+ end
14
+ end
@@ -0,0 +1,159 @@
1
+ # Inspired by rabbitmq.rake the Redbox project at http://github.com/rick/redbox/tree/master
2
+ require 'fileutils'
3
+ require 'open-uri'
4
+ require 'pathname'
5
+
6
+ class RedisRunner
7
+
8
+ def self.redis_dir
9
+ @redis_dir ||= if ENV['PREFIX']
10
+ Pathname.new(ENV['PREFIX'])
11
+ else
12
+ Pathname.new(`which redis-server`) + '..' + '..'
13
+ end
14
+ end
15
+
16
+ def self.bin_dir
17
+ redis_dir + 'bin'
18
+ end
19
+
20
+ def self.config
21
+ @config ||= if File.exists?(redis_dir + 'etc/redis.conf')
22
+ redis_dir + 'etc/redis.conf'
23
+ else
24
+ redis_dir + '../etc/redis.conf'
25
+ end
26
+ end
27
+
28
+ def self.dtach_socket
29
+ '/tmp/redis.dtach'
30
+ end
31
+
32
+ # Just check for existance of dtach socket
33
+ def self.running?
34
+ File.exists? dtach_socket
35
+ end
36
+
37
+ def self.start
38
+ puts 'Detach with Ctrl+\ Re-attach with rake redis:attach'
39
+ sleep 1
40
+ command = "#{bin_dir}/dtach -A #{dtach_socket} #{bin_dir}/redis-server #{config}"
41
+ sh command
42
+ end
43
+
44
+ def self.attach
45
+ exec "#{bin_dir}/dtach -a #{dtach_socket}"
46
+ end
47
+
48
+ def self.stop
49
+ sh 'echo "SHUTDOWN" | nc localhost 6379'
50
+ end
51
+
52
+ end
53
+
54
+ namespace :redis do
55
+
56
+ desc 'About redis'
57
+ task :about do
58
+ puts "\nSee http://code.google.com/p/redis/ for information about redis.\n\n"
59
+ end
60
+
61
+ desc 'Start redis'
62
+ task :start do
63
+ RedisRunner.start
64
+ end
65
+
66
+ desc 'Stop redis'
67
+ task :stop do
68
+ RedisRunner.stop
69
+ end
70
+
71
+ desc 'Restart redis'
72
+ task :restart do
73
+ RedisRunner.stop
74
+ RedisRunner.start
75
+ end
76
+
77
+ desc 'Attach to redis dtach socket'
78
+ task :attach do
79
+ RedisRunner.attach
80
+ end
81
+
82
+ desc 'Install the latest verison of Redis from Github (requires git, duh)'
83
+ task :install => [:about, :download, :make] do
84
+ bin_dir = '/usr/bin'
85
+ conf_dir = '/etc'
86
+
87
+ if ENV['PREFIX']
88
+ bin_dir = "#{ENV['PREFIX']}/bin"
89
+ sh "mkdir -p #{bin_dir}" unless File.exists?("#{bin_dir}")
90
+
91
+ conf_dir = "#{ENV['PREFIX']}/etc"
92
+ sh "mkdir -p #{conf_dir}" unless File.exists?("#{conf_dir}")
93
+ end
94
+
95
+ %w(redis-benchmark redis-cli redis-server).each do |bin|
96
+ sh "cp /tmp/redis/#{bin} #{bin_dir}"
97
+ end
98
+
99
+ puts "Installed redis-benchmark, redis-cli and redis-server to #{bin_dir}"
100
+
101
+ unless File.exists?("#{conf_dir}/redis.conf")
102
+ sh "cp /tmp/redis/redis.conf #{conf_dir}/redis.conf"
103
+ puts "Installed redis.conf to #{conf_dir} \n You should look at this file!"
104
+ end
105
+ end
106
+
107
+ task :make do
108
+ sh "cd /tmp/redis && make clean"
109
+ sh "cd /tmp/redis && make"
110
+ end
111
+
112
+ desc "Download package"
113
+ task :download do
114
+ sh 'rm -rf /tmp/redis/' if File.exists?("/tmp/redis/.svn")
115
+ sh 'git clone git://github.com/antirez/redis.git /tmp/redis' unless File.exists?('/tmp/redis')
116
+ sh "cd /tmp/redis && git pull" if File.exists?("/tmp/redis/.git")
117
+ end
118
+
119
+ end
120
+
121
+ namespace :dtach do
122
+
123
+ desc 'About dtach'
124
+ task :about do
125
+ puts "\nSee http://dtach.sourceforge.net/ for information about dtach.\n\n"
126
+ end
127
+
128
+ desc 'Install dtach 0.8 from source'
129
+ task :install => [:about, :download, :make] do
130
+
131
+ bin_dir = "/usr/bin"
132
+
133
+ if ENV['PREFIX']
134
+ bin_dir = "#{ENV['PREFIX']}/bin"
135
+ sh "mkdir -p #{bin_dir}" unless File.exists?("#{bin_dir}")
136
+ end
137
+
138
+ sh "cp /tmp/dtach-0.8/dtach #{bin_dir}"
139
+ end
140
+
141
+ task :make do
142
+ sh 'cd /tmp/dtach-0.8/ && ./configure && make'
143
+ end
144
+
145
+ desc "Download package"
146
+ task :download do
147
+ unless File.exists?('/tmp/dtach-0.8.tar.gz')
148
+ require 'net/http'
149
+
150
+ url = 'http://downloads.sourceforge.net/project/dtach/dtach/0.8/dtach-0.8.tar.gz'
151
+ open('/tmp/dtach-0.8.tar.gz', 'wb') do |file| file.write(open(url).read) end
152
+ end
153
+
154
+ unless File.directory?('/tmp/dtach-0.8')
155
+ sh 'cd /tmp && tar xzf dtach-0.8.tar.gz'
156
+ end
157
+ end
158
+ end
159
+
@@ -0,0 +1,2 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
2
+ require 'resque/tasks'
@@ -0,0 +1,25 @@
1
+ require 'test_helper'
2
+
3
+ begin
4
+ require 'hoptoad_notifier'
5
+ rescue LoadError
6
+ warn "Install hoptoad_notifier gem to run Hoptoad tests."
7
+ end
8
+
9
+ if defined? HoptoadNotifier
10
+ context "Hoptoad" do
11
+ test "should be notified of an error" do
12
+ exception = StandardError.new("BOOM")
13
+ worker = Resque::Worker.new(:test)
14
+ queue = "test"
15
+ payload = {'class' => Object, 'args' => 66}
16
+
17
+ HoptoadNotifier.expects(:notify_or_ignore).with(
18
+ exception,
19
+ :parameters => {:payload_class => 'Object', :payload_args => '66'})
20
+
21
+ backend = Resque::Failure::Hoptoad.new(exception, worker, queue, payload)
22
+ backend.save
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,323 @@
1
+ require 'test_helper'
2
+
3
+ context "Resque::Job before_perform" do
4
+ include PerformJob
5
+
6
+ class ::BeforePerformJob
7
+ def self.before_perform_record_history(history)
8
+ history << :before_perform
9
+ end
10
+
11
+ def self.perform(history)
12
+ history << :perform
13
+ end
14
+ end
15
+
16
+ test "it runs before_perform before perform" do
17
+ result = perform_job(BeforePerformJob, history=[])
18
+ assert_equal true, result, "perform returned true"
19
+ assert_equal history, [:before_perform, :perform]
20
+ end
21
+
22
+ class ::BeforePerformJobFails
23
+ def self.before_perform_fail_job(history)
24
+ history << :before_perform
25
+ raise StandardError
26
+ end
27
+ def self.perform(history)
28
+ history << :perform
29
+ end
30
+ end
31
+
32
+ test "raises an error and does not perform if before_perform fails" do
33
+ history = []
34
+ assert_raises StandardError do
35
+ perform_job(BeforePerformJobFails, history)
36
+ end
37
+ assert_equal history, [:before_perform], "Only before_perform was run"
38
+ end
39
+
40
+ class ::BeforePerformJobAborts
41
+ def self.before_perform_abort(history)
42
+ history << :before_perform
43
+ raise Resque::Job::DontPerform
44
+ end
45
+ def self.perform(history)
46
+ history << :perform
47
+ end
48
+ end
49
+
50
+ test "does not perform if before_perform raises Resque::Job::DontPerform" do
51
+ result = perform_job(BeforePerformJobAborts, history=[])
52
+ assert_equal false, result, "perform returned false"
53
+ assert_equal history, [:before_perform], "Only before_perform was run"
54
+ end
55
+ end
56
+
57
+ context "Resque::Job after_perform" do
58
+ include PerformJob
59
+
60
+ class ::AfterPerformJob
61
+ def self.perform(history)
62
+ history << :perform
63
+ end
64
+ def self.after_perform_record_history(history)
65
+ history << :after_perform
66
+ end
67
+ end
68
+
69
+ test "it runs after_perform after perform" do
70
+ result = perform_job(AfterPerformJob, history=[])
71
+ assert_equal true, result, "perform returned true"
72
+ assert_equal history, [:perform, :after_perform]
73
+ end
74
+
75
+ class ::AfterPerformJobFails
76
+ def self.perform(history)
77
+ history << :perform
78
+ end
79
+ def self.after_perform_fail_job(history)
80
+ history << :after_perform
81
+ raise StandardError
82
+ end
83
+ end
84
+
85
+ test "raises an error but has already performed if after_perform fails" do
86
+ history = []
87
+ assert_raises StandardError do
88
+ perform_job(AfterPerformJobFails, history)
89
+ end
90
+ assert_equal history, [:perform, :after_perform], "Only after_perform was run"
91
+ end
92
+ end
93
+
94
+ context "Resque::Job around_perform" do
95
+ include PerformJob
96
+
97
+ class ::AroundPerformJob
98
+ def self.perform(history)
99
+ history << :perform
100
+ end
101
+ def self.around_perform_record_history(history)
102
+ history << :start_around_perform
103
+ yield
104
+ history << :finish_around_perform
105
+ end
106
+ end
107
+
108
+ test "it runs around_perform then yields in order to perform" do
109
+ result = perform_job(AroundPerformJob, history=[])
110
+ assert_equal true, result, "perform returned true"
111
+ assert_equal history, [:start_around_perform, :perform, :finish_around_perform]
112
+ end
113
+
114
+ class ::AroundPerformJobFailsBeforePerforming
115
+ def self.perform(history)
116
+ history << :perform
117
+ end
118
+ def self.around_perform_fail(history)
119
+ history << :start_around_perform
120
+ raise StandardError
121
+ yield
122
+ history << :finish_around_perform
123
+ end
124
+ end
125
+
126
+ test "raises an error and does not perform if around_perform fails before yielding" do
127
+ history = []
128
+ assert_raises StandardError do
129
+ perform_job(AroundPerformJobFailsBeforePerforming, history)
130
+ end
131
+ assert_equal history, [:start_around_perform], "Only part of around_perform was run"
132
+ end
133
+
134
+ class ::AroundPerformJobFailsWhilePerforming
135
+ def self.perform(history)
136
+ history << :perform
137
+ raise StandardError
138
+ end
139
+ def self.around_perform_fail_in_yield(history)
140
+ history << :start_around_perform
141
+ begin
142
+ yield
143
+ ensure
144
+ history << :ensure_around_perform
145
+ end
146
+ history << :finish_around_perform
147
+ end
148
+ end
149
+
150
+ test "raises an error but may handle exceptions if perform fails" do
151
+ history = []
152
+ assert_raises StandardError do
153
+ perform_job(AroundPerformJobFailsWhilePerforming, history)
154
+ end
155
+ assert_equal history, [:start_around_perform, :perform, :ensure_around_perform], "Only part of around_perform was run"
156
+ end
157
+
158
+ class ::AroundPerformJobDoesNotHaveToYield
159
+ def self.perform(history)
160
+ history << :perform
161
+ end
162
+ def self.around_perform_dont_yield(history)
163
+ history << :start_around_perform
164
+ history << :finish_around_perform
165
+ end
166
+ end
167
+
168
+ test "around_perform is not required to yield" do
169
+ history = []
170
+ result = perform_job(AroundPerformJobDoesNotHaveToYield, history)
171
+ assert_equal false, result, "perform returns false"
172
+ assert_equal history, [:start_around_perform, :finish_around_perform], "perform was not run"
173
+ end
174
+ end
175
+
176
+ context "Resque::Job on_failure" do
177
+ include PerformJob
178
+
179
+ class ::FailureJobThatDoesNotFail
180
+ def self.perform(history)
181
+ history << :perform
182
+ end
183
+ def self.on_failure_record_failure(exception, history)
184
+ history << exception.message
185
+ end
186
+ end
187
+
188
+ test "it does not call on_failure if no failures occur" do
189
+ result = perform_job(FailureJobThatDoesNotFail, history=[])
190
+ assert_equal true, result, "perform returned true"
191
+ assert_equal history, [:perform]
192
+ end
193
+
194
+ class ::FailureJobThatFails
195
+ def self.perform(history)
196
+ history << :perform
197
+ raise StandardError, "oh no"
198
+ end
199
+ def self.on_failure_record_failure(exception, history)
200
+ history << exception.message
201
+ end
202
+ end
203
+
204
+ test "it calls on_failure with the exception and then re-raises the exception" do
205
+ history = []
206
+ assert_raises StandardError do
207
+ perform_job(FailureJobThatFails, history)
208
+ end
209
+ assert_equal history, [:perform, "oh no"]
210
+ end
211
+
212
+ class ::FailureJobThatFailsBadly
213
+ def self.perform(history)
214
+ history << :perform
215
+ raise SyntaxError, "oh no"
216
+ end
217
+ def self.on_failure_record_failure(exception, history)
218
+ history << exception.message
219
+ end
220
+ end
221
+
222
+ test "it calls on_failure even with bad exceptions" do
223
+ history = []
224
+ assert_raises SyntaxError do
225
+ perform_job(FailureJobThatFailsBadly, history)
226
+ end
227
+ assert_equal history, [:perform, "oh no"]
228
+ end
229
+ end
230
+
231
+ context "Resque::Job after_enqueue" do
232
+ include PerformJob
233
+
234
+ class ::AfterEnqueueJob
235
+ @queue = :jobs
236
+ def self.after_enqueue_record_history(history)
237
+ history << :after_enqueue
238
+ end
239
+
240
+ def self.perform(history)
241
+ end
242
+ end
243
+
244
+ test "the after enqueue hook should run" do
245
+ history = []
246
+ @worker = Resque::Worker.new(:jobs)
247
+ Resque.enqueue(AfterEnqueueJob, history)
248
+ @worker.work(0)
249
+ assert_equal history, [:after_enqueue], "after_enqueue was not run"
250
+ end
251
+ end
252
+
253
+ context "Resque::Job all hooks" do
254
+ include PerformJob
255
+
256
+ class ::VeryHookyJob
257
+ def self.before_perform_record_history(history)
258
+ history << :before_perform
259
+ end
260
+ def self.around_perform_record_history(history)
261
+ history << :start_around_perform
262
+ yield
263
+ history << :finish_around_perform
264
+ end
265
+ def self.perform(history)
266
+ history << :perform
267
+ end
268
+ def self.after_perform_record_history(history)
269
+ history << :after_perform
270
+ end
271
+ def self.on_failure_record_history(exception, history)
272
+ history << exception.message
273
+ end
274
+ end
275
+
276
+ test "the complete hook order" do
277
+ result = perform_job(VeryHookyJob, history=[])
278
+ assert_equal true, result, "perform returned true"
279
+ assert_equal history, [
280
+ :before_perform,
281
+ :start_around_perform,
282
+ :perform,
283
+ :finish_around_perform,
284
+ :after_perform
285
+ ]
286
+ end
287
+
288
+ class ::VeryHookyJobThatFails
289
+ def self.before_perform_record_history(history)
290
+ history << :before_perform
291
+ end
292
+ def self.around_perform_record_history(history)
293
+ history << :start_around_perform
294
+ yield
295
+ history << :finish_around_perform
296
+ end
297
+ def self.perform(history)
298
+ history << :perform
299
+ end
300
+ def self.after_perform_record_history(history)
301
+ history << :after_perform
302
+ raise StandardError, "oh no"
303
+ end
304
+ def self.on_failure_record_history(exception, history)
305
+ history << exception.message
306
+ end
307
+ end
308
+
309
+ test "the complete hook order with a failure at the last minute" do
310
+ history = []
311
+ assert_raises StandardError do
312
+ perform_job(VeryHookyJobThatFails, history)
313
+ end
314
+ assert_equal history, [
315
+ :before_perform,
316
+ :start_around_perform,
317
+ :perform,
318
+ :finish_around_perform,
319
+ :after_perform,
320
+ "oh no"
321
+ ]
322
+ end
323
+ end