resque_sqs 1.25.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +7 -0
  2. data/HISTORY.md +467 -0
  3. data/LICENSE +20 -0
  4. data/README.markdown +866 -0
  5. data/Rakefile +70 -0
  6. data/bin/resque-sqs +81 -0
  7. data/bin/resque-sqs-web +27 -0
  8. data/lib/resque_sqs/errors.rb +13 -0
  9. data/lib/resque_sqs/failure/airbrake.rb +33 -0
  10. data/lib/resque_sqs/failure/base.rb +73 -0
  11. data/lib/resque_sqs/failure/multiple.rb +59 -0
  12. data/lib/resque_sqs/failure/redis.rb +108 -0
  13. data/lib/resque_sqs/failure/redis_multi_queue.rb +89 -0
  14. data/lib/resque_sqs/failure.rb +113 -0
  15. data/lib/resque_sqs/helpers.rb +107 -0
  16. data/lib/resque_sqs/job.rb +346 -0
  17. data/lib/resque_sqs/log_formatters/quiet_formatter.rb +7 -0
  18. data/lib/resque_sqs/log_formatters/verbose_formatter.rb +7 -0
  19. data/lib/resque_sqs/log_formatters/very_verbose_formatter.rb +8 -0
  20. data/lib/resque_sqs/logging.rb +18 -0
  21. data/lib/resque_sqs/plugin.rb +66 -0
  22. data/lib/resque_sqs/server/helpers.rb +52 -0
  23. data/lib/resque_sqs/server/public/favicon.ico +0 -0
  24. data/lib/resque_sqs/server/public/idle.png +0 -0
  25. data/lib/resque_sqs/server/public/jquery-1.3.2.min.js +19 -0
  26. data/lib/resque_sqs/server/public/jquery.relatize_date.js +95 -0
  27. data/lib/resque_sqs/server/public/poll.png +0 -0
  28. data/lib/resque_sqs/server/public/ranger.js +78 -0
  29. data/lib/resque_sqs/server/public/reset.css +44 -0
  30. data/lib/resque_sqs/server/public/style.css +91 -0
  31. data/lib/resque_sqs/server/public/working.png +0 -0
  32. data/lib/resque_sqs/server/test_helper.rb +19 -0
  33. data/lib/resque_sqs/server/views/error.erb +1 -0
  34. data/lib/resque_sqs/server/views/failed.erb +29 -0
  35. data/lib/resque_sqs/server/views/failed_job.erb +50 -0
  36. data/lib/resque_sqs/server/views/failed_queues_overview.erb +24 -0
  37. data/lib/resque_sqs/server/views/key_sets.erb +19 -0
  38. data/lib/resque_sqs/server/views/key_string.erb +11 -0
  39. data/lib/resque_sqs/server/views/layout.erb +44 -0
  40. data/lib/resque_sqs/server/views/next_more.erb +22 -0
  41. data/lib/resque_sqs/server/views/overview.erb +4 -0
  42. data/lib/resque_sqs/server/views/queues.erb +58 -0
  43. data/lib/resque_sqs/server/views/stats.erb +62 -0
  44. data/lib/resque_sqs/server/views/workers.erb +109 -0
  45. data/lib/resque_sqs/server/views/working.erb +72 -0
  46. data/lib/resque_sqs/server.rb +271 -0
  47. data/lib/resque_sqs/stat.rb +57 -0
  48. data/lib/resque_sqs/tasks.rb +83 -0
  49. data/lib/resque_sqs/vendor/utf8_util/utf8_util_18.rb +91 -0
  50. data/lib/resque_sqs/vendor/utf8_util/utf8_util_19.rb +5 -0
  51. data/lib/resque_sqs/vendor/utf8_util.rb +20 -0
  52. data/lib/resque_sqs/version.rb +3 -0
  53. data/lib/resque_sqs/worker.rb +779 -0
  54. data/lib/resque_sqs.rb +479 -0
  55. data/lib/tasks/redis_sqs.rake +161 -0
  56. data/lib/tasks/resque_sqs.rake +2 -0
  57. data/test/airbrake_test.rb +27 -0
  58. data/test/failure_base_test.rb +15 -0
  59. data/test/job_hooks_test.rb +465 -0
  60. data/test/job_plugins_test.rb +230 -0
  61. data/test/logging_test.rb +24 -0
  62. data/test/plugin_test.rb +116 -0
  63. data/test/redis-test-cluster.conf +115 -0
  64. data/test/redis-test.conf +115 -0
  65. data/test/resque-web_test.rb +59 -0
  66. data/test/resque_failure_redis_test.rb +19 -0
  67. data/test/resque_hook_test.rb +165 -0
  68. data/test/resque_test.rb +278 -0
  69. data/test/stdout +42 -0
  70. data/test/test_helper.rb +228 -0
  71. data/test/worker_test.rb +1080 -0
  72. metadata +202 -0
@@ -0,0 +1,116 @@
1
+ require 'test_helper'
2
+
3
+ context "ResqueSqs::Plugin finding hooks" do
4
+ module SimplePlugin
5
+ extend self
6
+ def before_perform1; end
7
+ def before_perform; end
8
+ def before_perform2; end
9
+ def after_perform1; end
10
+ def after_perform; end
11
+ def after_perform2; end
12
+ def perform; end
13
+ def around_perform1; end
14
+ def around_perform; end
15
+ def around_perform2; end
16
+ def on_failure1; end
17
+ def on_failure; end
18
+ def on_failure2; end
19
+ end
20
+
21
+ test "before_perform hooks are found and sorted" do
22
+ assert_equal ["before_perform", "before_perform1", "before_perform2"], ResqueSqs::Plugin.before_hooks(SimplePlugin).map {|m| m.to_s}
23
+ end
24
+
25
+ test "after_perform hooks are found and sorted" do
26
+ assert_equal ["after_perform", "after_perform1", "after_perform2"], ResqueSqs::Plugin.after_hooks(SimplePlugin).map {|m| m.to_s}
27
+ end
28
+
29
+ test "around_perform hooks are found and sorted" do
30
+ assert_equal ["around_perform", "around_perform1", "around_perform2"], ResqueSqs::Plugin.around_hooks(SimplePlugin).map {|m| m.to_s}
31
+ end
32
+
33
+ test "on_failure hooks are found and sorted" do
34
+ assert_equal ["on_failure", "on_failure1", "on_failure2"], ResqueSqs::Plugin.failure_hooks(SimplePlugin).map {|m| m.to_s}
35
+ end
36
+ end
37
+
38
+ context "ResqueSqs::Plugin linting" do
39
+ module ::BadBefore
40
+ def self.before_perform; end
41
+ end
42
+ module ::BadAfter
43
+ def self.after_perform; end
44
+ end
45
+ module ::BadAround
46
+ def self.around_perform; end
47
+ end
48
+ module ::BadFailure
49
+ def self.on_failure; end
50
+ end
51
+
52
+ test "before_perform must be namespaced" do
53
+ begin
54
+ ResqueSqs::Plugin.lint(BadBefore)
55
+ assert false, "should have failed"
56
+ rescue ResqueSqs::Plugin::LintError => e
57
+ assert_equal "BadBefore.before_perform is not namespaced", e.message
58
+ end
59
+ end
60
+
61
+ test "after_perform must be namespaced" do
62
+ begin
63
+ ResqueSqs::Plugin.lint(BadAfter)
64
+ assert false, "should have failed"
65
+ rescue ResqueSqs::Plugin::LintError => e
66
+ assert_equal "BadAfter.after_perform is not namespaced", e.message
67
+ end
68
+ end
69
+
70
+ test "around_perform must be namespaced" do
71
+ begin
72
+ ResqueSqs::Plugin.lint(BadAround)
73
+ assert false, "should have failed"
74
+ rescue ResqueSqs::Plugin::LintError => e
75
+ assert_equal "BadAround.around_perform is not namespaced", e.message
76
+ end
77
+ end
78
+
79
+ test "on_failure must be namespaced" do
80
+ begin
81
+ ResqueSqs::Plugin.lint(BadFailure)
82
+ assert false, "should have failed"
83
+ rescue ResqueSqs::Plugin::LintError => e
84
+ assert_equal "BadFailure.on_failure is not namespaced", e.message
85
+ end
86
+ end
87
+
88
+ module GoodBefore
89
+ def self.before_perform1; end
90
+ end
91
+ module GoodAfter
92
+ def self.after_perform1; end
93
+ end
94
+ module GoodAround
95
+ def self.around_perform1; end
96
+ end
97
+ module GoodFailure
98
+ def self.on_failure1; end
99
+ end
100
+
101
+ test "before_perform1 is an ok name" do
102
+ ResqueSqs::Plugin.lint(GoodBefore)
103
+ end
104
+
105
+ test "after_perform1 is an ok name" do
106
+ ResqueSqs::Plugin.lint(GoodAfter)
107
+ end
108
+
109
+ test "around_perform1 is an ok name" do
110
+ ResqueSqs::Plugin.lint(GoodAround)
111
+ end
112
+
113
+ test "on_failure1 is an ok name" do
114
+ ResqueSqs::Plugin.lint(GoodFailure)
115
+ end
116
+ end
@@ -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 ./test/redis-test-cluster.pid
10
+
11
+ # Accept connections on the specified port, default is 6379
12
+ port 9737
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-cluster.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 ./test/
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,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 ./test/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 ./test/
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,59 @@
1
+ require 'test_helper'
2
+ require 'resque_sqs/server/test_helper'
3
+
4
+ # Root path test
5
+ context "on GET to /" do
6
+ setup { get "/" }
7
+
8
+ test "redirect to overview" do
9
+ follow_redirect!
10
+ end
11
+ end
12
+
13
+ # Global overview
14
+ context "on GET to /overview" do
15
+ setup { get "/overview" }
16
+
17
+ test "should at least display 'queues'" do
18
+ assert last_response.body.include?('Queues')
19
+ end
20
+ end
21
+
22
+ # Working jobs
23
+ context "on GET to /working" do
24
+ setup { get "/working" }
25
+
26
+ should_respond_with_success
27
+ end
28
+
29
+ # Failed
30
+ context "on GET to /failed" do
31
+ setup { get "/failed" }
32
+
33
+ should_respond_with_success
34
+ end
35
+
36
+ # Stats
37
+ context "on GET to /stats/resque" do
38
+ setup { get "/stats/resque" }
39
+
40
+ should_respond_with_success
41
+ end
42
+
43
+ context "on GET to /stats/redis" do
44
+ setup { get "/stats/redis" }
45
+
46
+ should_respond_with_success
47
+ end
48
+
49
+ context "on GET to /stats/resque" do
50
+ setup { get "/stats/keys" }
51
+
52
+ should_respond_with_success
53
+ end
54
+
55
+ context "also works with slash at the end" do
56
+ setup { get "/working/" }
57
+
58
+ should_respond_with_success
59
+ end
@@ -0,0 +1,19 @@
1
+ require 'test_helper'
2
+ require 'resque_sqs/failure/redis'
3
+
4
+ context "ResqueSqs::Failure::Redis" do
5
+ setup do
6
+ @bad_string = [39, 52, 127, 86, 93, 95, 39].map { |c| c.chr }.join
7
+ exception = StandardError.exception(@bad_string)
8
+ worker = ResqueSqs::Worker.new(:test)
9
+ queue = "queue"
10
+ payload = { "class" => Object, "args" => 3 }
11
+ @redis_backend = ResqueSqs::Failure::Redis.new(exception, worker, queue, payload)
12
+ end
13
+
14
+ test 'cleans up bad strings before saving the failure, in order to prevent errors on the resque UI' do
15
+ # test assumption: the bad string should not be able to round trip though JSON
16
+ @redis_backend.save
17
+ ResqueSqs::Failure::Redis.all # should not raise an error
18
+ end
19
+ end
@@ -0,0 +1,165 @@
1
+ require 'test_helper'
2
+ require 'tempfile'
3
+
4
+ describe "Resque Hooks" do
5
+ before do
6
+ ResqueSqs.redis.flushall
7
+
8
+ ResqueSqs.before_first_fork = nil
9
+ ResqueSqs.before_fork = nil
10
+ ResqueSqs.after_fork = nil
11
+
12
+ @worker = ResqueSqs::Worker.new(:jobs)
13
+
14
+ $called = false
15
+
16
+ class CallNotifyJob
17
+ def self.perform
18
+ $called = true
19
+ end
20
+ end
21
+ end
22
+
23
+ it 'retrieving hooks if none have been set' do
24
+ assert_equal [], ResqueSqs.before_first_fork
25
+ assert_equal [], ResqueSqs.before_fork
26
+ assert_equal [], ResqueSqs.after_fork
27
+ end
28
+
29
+ it 'it calls before_first_fork once' do
30
+ counter = 0
31
+
32
+ ResqueSqs.before_first_fork { counter += 1 }
33
+ 2.times { ResqueSqs::Job.create(:jobs, CallNotifyJob) }
34
+
35
+ assert_equal(0, counter)
36
+ @worker.work(0)
37
+ assert_equal(1, counter)
38
+ end
39
+
40
+ it 'it calls before_fork before each job' do
41
+ counter = 0
42
+
43
+ ResqueSqs.before_fork { counter += 1 }
44
+ 2.times { ResqueSqs::Job.create(:jobs, CallNotifyJob) }
45
+
46
+ assert_equal(0, counter)
47
+ @worker.work(0)
48
+ assert_equal(2, counter)
49
+ end
50
+
51
+ it 'it calls after_fork after each job' do
52
+ skip("TRAAAVIS!!!!") if RUBY_VERSION == "1.8.7"
53
+ # We have to stub out will_fork? to return true, which is going to cause an actual fork(). As such, the
54
+ # exit!(true) will be called in Worker#work; to share state, use a tempfile
55
+ file = Tempfile.new("resque_after_fork")
56
+
57
+ begin
58
+ File.open(file.path, "w") {|f| f.write(0)}
59
+ ResqueSqs.after_fork do
60
+ val = File.read(file).strip.to_i
61
+ File.open(file.path, "w") {|f| f.write(val + 1)}
62
+ end
63
+ 2.times { ResqueSqs::Job.create(:jobs, CallNotifyJob) }
64
+
65
+ val = File.read(file.path).strip.to_i
66
+ assert_equal(0, val)
67
+ @worker.stubs(:will_fork?).returns(true)
68
+ @worker.work(0)
69
+ val = File.read(file.path).strip.to_i
70
+ assert_equal(2, val)
71
+ ensure
72
+ file.delete
73
+ end
74
+ end
75
+
76
+ it 'it calls before_first_fork before forking' do
77
+ ResqueSqs.before_first_fork { assert(!$called) }
78
+
79
+ ResqueSqs::Job.create(:jobs, CallNotifyJob)
80
+ @worker.work(0)
81
+ end
82
+
83
+ it 'it calls before_fork before forking' do
84
+ ResqueSqs.before_fork { assert(!$called) }
85
+
86
+ ResqueSqs::Job.create(:jobs, CallNotifyJob)
87
+ @worker.work(0)
88
+ end
89
+
90
+ it 'it calls after_fork after forking' do
91
+ ResqueSqs.after_fork { assert($called) }
92
+
93
+ ResqueSqs::Job.create(:jobs, CallNotifyJob)
94
+ @worker.work(0)
95
+ end
96
+
97
+ it 'it registers multiple before_first_forks' do
98
+ first = false
99
+ second = false
100
+
101
+ ResqueSqs.before_first_fork { first = true }
102
+ ResqueSqs.before_first_fork { second = true }
103
+ ResqueSqs::Job.create(:jobs, CallNotifyJob)
104
+
105
+ assert(!first && !second)
106
+ @worker.work(0)
107
+ assert(first && second)
108
+ end
109
+
110
+ it 'it registers multiple before_forks' do
111
+ first = false
112
+ second = false
113
+
114
+ ResqueSqs.before_fork { first = true }
115
+ ResqueSqs.before_fork { second = true }
116
+ ResqueSqs::Job.create(:jobs, CallNotifyJob)
117
+
118
+ assert(!first && !second)
119
+ @worker.work(0)
120
+ assert(first && second)
121
+ end
122
+
123
+ it 'flattens hooks on assignment' do
124
+ first = false
125
+ second = false
126
+ ResqueSqs.before_fork = [Proc.new { first = true }, Proc.new { second = true }]
127
+ ResqueSqs::Job.create(:jobs, CallNotifyJob)
128
+
129
+ assert(!first && !second)
130
+ @worker.work(0)
131
+ assert(first && second)
132
+ end
133
+
134
+ it 'it registers multiple after_forks' do
135
+ # We have to stub out will_fork? to return true, which is going to cause an actual fork(). As such, the
136
+ # exit!(true) will be called in Worker#work; to share state, use a tempfile
137
+ file = Tempfile.new("resque_after_fork_first")
138
+ file2 = Tempfile.new("resque_after_fork_second")
139
+ begin
140
+ File.open(file.path, "w") {|f| f.write(1)}
141
+ File.open(file2.path, "w") {|f| f.write(2)}
142
+
143
+ ResqueSqs.after_fork do
144
+ val = File.read(file.path).strip.to_i
145
+ File.open(file.path, "w") {|f| f.write(val + 1)}
146
+ end
147
+
148
+ ResqueSqs.after_fork do
149
+ val = File.read(file2.path).strip.to_i
150
+ File.open(file2.path, "w") {|f| f.write(val + 1)}
151
+ end
152
+ ResqueSqs::Job.create(:jobs, CallNotifyJob)
153
+
154
+ @worker.stubs(:will_fork?).returns(true)
155
+ @worker.work(0)
156
+ val = File.read(file.path).strip.to_i
157
+ val2 = File.read(file2.path).strip.to_i
158
+ assert_equal(val, 2)
159
+ assert_equal(val2, 3)
160
+ ensure
161
+ file.delete
162
+ file2.delete
163
+ end
164
+ end
165
+ end