sidetiq 0.3.7 → 0.4.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/CHANGELOG.md +16 -0
- data/LICENSE +2 -2
- data/README.md +9 -16
- data/Rakefile +2 -7
- data/examples/Procfile +2 -0
- data/examples/config.ru +15 -0
- data/examples/server.rb +17 -0
- data/examples/workers/failing.rb +13 -0
- data/examples/workers/simple.rb +10 -0
- data/lib/sidetiq/actor/clock.rb +31 -0
- data/lib/sidetiq/actor/handler.rb +7 -0
- data/lib/sidetiq/actor.rb +38 -0
- data/lib/sidetiq/api.rb +109 -0
- data/lib/sidetiq/clock.rb +3 -118
- data/lib/sidetiq/config.rb +8 -0
- data/lib/sidetiq/handler.rb +50 -0
- data/lib/sidetiq/lock/meta_data.rb +53 -0
- data/lib/sidetiq/lock/redis.rb +115 -0
- data/lib/sidetiq/lock/watcher.rb +41 -0
- data/lib/sidetiq/logging.rb +12 -0
- data/lib/sidetiq/middleware/history.rb +58 -0
- data/lib/sidetiq/schedulable.rb +6 -7
- data/lib/sidetiq/supervisor.rb +50 -0
- data/lib/sidetiq/version.rb +6 -3
- data/lib/sidetiq/views/_home_nav.erb +16 -0
- data/lib/sidetiq/views/_worker_nav.erb +22 -0
- data/lib/sidetiq/views/assets/styles.css +36 -0
- data/lib/sidetiq/views/history.erb +48 -0
- data/lib/sidetiq/views/locks.erb +48 -0
- data/lib/sidetiq/views/schedule.erb +59 -0
- data/lib/sidetiq/views/sidetiq.erb +39 -28
- data/lib/sidetiq/web.rb +36 -16
- data/lib/sidetiq.rb +34 -114
- data/sidetiq.gemspec +5 -2
- data/tasks/bundler.task +1 -0
- data/tasks/minitest.task +6 -0
- data/test/fixtures/optional_arguments_worker.rb +8 -0
- data/test/helper.rb +21 -6
- data/test/test_clock.rb +16 -24
- data/test/test_history.rb +60 -0
- data/test/test_lock_meta_data.rb +90 -0
- data/test/test_lock_redis.rb +63 -0
- data/test/test_version.rb +2 -1
- data/test/test_watcher.rb +24 -0
- data/test/test_web.rb +26 -2
- metadata +80 -12
- data/examples/simple.rb +0 -22
- data/lib/sidetiq/lock.rb +0 -63
- data/lib/sidetiq/middleware.rb +0 -23
- data/lib/sidetiq/views/sidetiq_details.erb +0 -49
- data/test/test_lock.rb +0 -30
- data/test/test_middleware.rb +0 -18
data/lib/sidetiq/web.rb
CHANGED
@@ -5,38 +5,50 @@ module Sidetiq
|
|
5
5
|
VIEWS = File.expand_path('views', File.dirname(__FILE__))
|
6
6
|
|
7
7
|
def self.registered(app)
|
8
|
-
app.
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
app.get "/sidetiq" do
|
9
|
+
@schedules = Sidetiq.schedules
|
10
|
+
@time = Sidetiq.clock.gettime
|
11
|
+
erb File.read(File.join(VIEWS, 'sidetiq.erb'))
|
12
|
+
end
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
14
|
+
app.get "/sidetiq/locks" do
|
15
|
+
@locks = Sidetiq::Lock::Redis.all.map(&:meta_data)
|
16
|
+
|
17
|
+
erb File.read(File.join(VIEWS, 'locks.erb'))
|
16
18
|
end
|
17
19
|
|
18
|
-
app.get "/sidetiq" do
|
19
|
-
|
20
|
-
|
21
|
-
|
20
|
+
app.get "/sidetiq/:name/schedule" do
|
21
|
+
halt 404 unless (name = params[:name])
|
22
|
+
|
23
|
+
@time = Sidetiq.clock.gettime
|
24
|
+
|
25
|
+
@worker, @schedule = Sidetiq.schedules.select do |worker, _|
|
26
|
+
worker.name == name
|
27
|
+
end.flatten
|
28
|
+
|
29
|
+
erb File.read(File.join(VIEWS, 'schedule.erb'))
|
22
30
|
end
|
23
31
|
|
24
|
-
app.get "/sidetiq/:name" do
|
32
|
+
app.get "/sidetiq/:name/history" do
|
25
33
|
halt 404 unless (name = params[:name])
|
26
34
|
|
27
|
-
@time =
|
35
|
+
@time = Sidetiq.clock.gettime
|
28
36
|
|
29
|
-
@worker, @schedule =
|
37
|
+
@worker, @schedule = Sidetiq.schedules.select do |worker, _|
|
30
38
|
worker.name == name
|
31
39
|
end.flatten
|
32
40
|
|
33
|
-
|
41
|
+
@history = Sidekiq.redis do |redis|
|
42
|
+
redis.lrange("sidetiq:#{@worker.name}:history", 0, -1)
|
43
|
+
end
|
44
|
+
|
45
|
+
erb File.read(File.join(VIEWS, 'history.erb'))
|
34
46
|
end
|
35
47
|
|
36
48
|
app.post "/sidetiq/:name/trigger" do
|
37
49
|
halt 404 unless (name = params[:name])
|
38
50
|
|
39
|
-
worker, _ =
|
51
|
+
worker, _ = Sidetiq.schedules.select do |w, _|
|
40
52
|
w.name == name
|
41
53
|
end.flatten
|
42
54
|
|
@@ -44,6 +56,14 @@ module Sidetiq
|
|
44
56
|
|
45
57
|
redirect "#{root_path}sidetiq"
|
46
58
|
end
|
59
|
+
|
60
|
+
app.post "/sidetiq/:name/unlock" do
|
61
|
+
halt 404 unless (name = params[:name])
|
62
|
+
|
63
|
+
Sidetiq::Lock::Redis.new(name).unlock!
|
64
|
+
|
65
|
+
redirect "#{root_path}sidetiq/locks"
|
66
|
+
end
|
47
67
|
end
|
48
68
|
end
|
49
69
|
end
|
data/lib/sidetiq.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
# stdlib
|
2
|
-
require 'monitor'
|
3
2
|
require 'ostruct'
|
4
3
|
require 'singleton'
|
5
4
|
require 'socket'
|
@@ -7,134 +6,55 @@ require 'socket'
|
|
7
6
|
# gems
|
8
7
|
require 'ice_cube'
|
9
8
|
require 'sidekiq'
|
9
|
+
require 'celluloid'
|
10
10
|
|
11
11
|
# internal
|
12
12
|
require 'sidetiq/config'
|
13
|
+
require 'sidetiq/logging'
|
14
|
+
require 'sidetiq/api'
|
13
15
|
require 'sidetiq/clock'
|
14
|
-
require 'sidetiq/
|
15
|
-
require 'sidetiq/
|
16
|
+
require 'sidetiq/handler'
|
17
|
+
require 'sidetiq/lock/meta_data'
|
18
|
+
require 'sidetiq/lock/redis'
|
16
19
|
require 'sidetiq/schedule'
|
17
20
|
require 'sidetiq/schedulable'
|
18
21
|
require 'sidetiq/version'
|
19
22
|
|
23
|
+
# middleware
|
24
|
+
require 'sidetiq/middleware/history'
|
25
|
+
|
26
|
+
# actor topology
|
27
|
+
require 'sidetiq/actor'
|
28
|
+
require 'sidetiq/actor/clock'
|
29
|
+
require 'sidetiq/actor/handler'
|
30
|
+
require 'sidetiq/supervisor'
|
31
|
+
|
20
32
|
# The Sidetiq namespace.
|
21
33
|
module Sidetiq
|
34
|
+
include Sidetiq::API
|
35
|
+
|
36
|
+
# Expose all instance methods as singleton methods.
|
37
|
+
extend self
|
38
|
+
|
22
39
|
class << self
|
23
40
|
# Public: Setter for the Sidetiq logger.
|
24
41
|
attr_writer :logger
|
42
|
+
end
|
25
43
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
# Public: Returns an Array of workers including Sidetiq::Schedulable.
|
34
|
-
def workers
|
35
|
-
schedules.keys
|
36
|
-
end
|
37
|
-
|
38
|
-
# Public: Returns a Hash of Sidetiq::Schedule instances.
|
39
|
-
def schedules
|
40
|
-
Clock.mon_synchronize do
|
41
|
-
Clock.schedules.dup
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
# Public: Currently scheduled recurring jobs.
|
46
|
-
#
|
47
|
-
# worker - A Sidekiq::Worker class or String of the class name (optional)
|
48
|
-
# block - An optional block that can be given to which each
|
49
|
-
# Sidekiq::SortedEntry instance corresponding to a scheduled job will
|
50
|
-
# be yielded.
|
51
|
-
#
|
52
|
-
# Examples
|
53
|
-
#
|
54
|
-
# Sidetiq.scheduled
|
55
|
-
# # => [#<Sidekiq::SortedEntry>, ...]
|
56
|
-
#
|
57
|
-
# Sidetiq.scheduled(MyWorker)
|
58
|
-
# # => [#<Sidekiq::SortedEntry>, ...]
|
59
|
-
#
|
60
|
-
# Sidetiq.scheduled("MyWorker")
|
61
|
-
# # => [#<Sidekiq::SortedEntry>, ...]
|
62
|
-
#
|
63
|
-
# Sidetiq.scheduled do |job|
|
64
|
-
# # do stuff ...
|
65
|
-
# end
|
66
|
-
# # => [#<Sidekiq::SortedEntry>, ...]
|
67
|
-
#
|
68
|
-
# Sidetiq.scheduled(MyWorker) do |job|
|
69
|
-
# # do stuff ...
|
70
|
-
# end
|
71
|
-
# # => [#<Sidekiq::SortedEntry>, ...]
|
72
|
-
#
|
73
|
-
# Sidetiq.scheduled("MyWorker") do |job|
|
74
|
-
# # do stuff ...
|
75
|
-
# end
|
76
|
-
# # => [#<Sidekiq::SortedEntry>, ...]
|
77
|
-
#
|
78
|
-
# Yields each Sidekiq::SortedEntry instance.
|
79
|
-
# Returns an Array of Sidekiq::SortedEntry objects.
|
80
|
-
def scheduled(worker = nil, &block)
|
81
|
-
filter_set(Sidekiq::ScheduledSet.new, worker, &block)
|
82
|
-
end
|
83
|
-
|
84
|
-
# Public: Recurring jobs currently scheduled for retries.
|
85
|
-
#
|
86
|
-
# worker - A Sidekiq::Worker class or String of the class name (optional)
|
87
|
-
# block - An optional block that can be given to which each
|
88
|
-
# Sidekiq::SortedEntry instance corresponding to a scheduled job will
|
89
|
-
# be yielded.
|
90
|
-
#
|
91
|
-
# Examples
|
92
|
-
#
|
93
|
-
# Sidetiq.retries
|
94
|
-
# # => [#<Sidekiq::SortedEntry>, ...]
|
95
|
-
#
|
96
|
-
# Sidetiq.retries(MyWorker)
|
97
|
-
# # => [#<Sidekiq::SortedEntry>, ...]
|
98
|
-
#
|
99
|
-
# Sidetiq.retries("MyWorker")
|
100
|
-
# # => [#<Sidekiq::SortedEntry>, ...]
|
101
|
-
#
|
102
|
-
# Sidetiq.retries do |job|
|
103
|
-
# # do stuff ...
|
104
|
-
# end
|
105
|
-
# # => [#<Sidekiq::SortedEntry>, ...]
|
106
|
-
#
|
107
|
-
# Sidetiq.retries(MyWorker) do |job|
|
108
|
-
# # do stuff ...
|
109
|
-
# end
|
110
|
-
# # => [#<Sidekiq::SortedEntry>, ...]
|
111
|
-
#
|
112
|
-
# Sidetiq.retries("MyWorker") do |job|
|
113
|
-
# # do stuff ...
|
114
|
-
# end
|
115
|
-
# # => [#<Sidekiq::SortedEntry>, ...]
|
116
|
-
#
|
117
|
-
# Yields each Sidekiq::SortedEntry instance.
|
118
|
-
# Returns an Array of Sidekiq::SortedEntry objects.
|
119
|
-
def retries(worker = nil, &block)
|
120
|
-
filter_set(Sidekiq::RetrySet.new, worker, &block)
|
121
|
-
end
|
122
|
-
|
123
|
-
private
|
124
|
-
|
125
|
-
def filter_set(set, worker, &block)
|
126
|
-
worker = worker.constantize if worker.kind_of?(String)
|
127
|
-
|
128
|
-
jobs = set.select do |job|
|
129
|
-
klass = job.klass.constantize
|
130
|
-
ret = klass.include?(Schedulable)
|
131
|
-
ret = ret && klass == worker if worker
|
132
|
-
ret
|
133
|
-
end
|
44
|
+
# Public: Reader for the Sidetiq logger.
|
45
|
+
#
|
46
|
+
# Defaults to `Sidekiq.logger`.
|
47
|
+
def logger
|
48
|
+
@logger ||= Sidekiq.logger
|
49
|
+
end
|
134
50
|
|
135
|
-
|
51
|
+
# Public: Returns the Sidetiq::Clock actor.
|
52
|
+
def clock
|
53
|
+
Sidetiq::Supervisor.clock
|
54
|
+
end
|
136
55
|
|
137
|
-
|
138
|
-
|
56
|
+
# Public: Returns a Sidetiq::Handler worker.
|
57
|
+
def handler
|
58
|
+
Sidetiq::Supervisor.handler
|
139
59
|
end
|
140
60
|
end
|
data/sidetiq.gemspec
CHANGED
@@ -19,13 +19,16 @@ Gem::Specification.new do |gem|
|
|
19
19
|
gem.require_paths = ["lib"]
|
20
20
|
gem.extensions = []
|
21
21
|
|
22
|
-
gem.add_dependency 'sidekiq',
|
23
|
-
gem.add_dependency '
|
22
|
+
gem.add_dependency 'sidekiq', '~> 2.14.0'
|
23
|
+
gem.add_dependency 'celluloid', '>= 0.14.1'
|
24
|
+
gem.add_dependency 'ice_cube', '~> 0.11.0'
|
25
|
+
gem.add_dependency 'json'
|
24
26
|
|
25
27
|
gem.add_development_dependency 'rake'
|
26
28
|
gem.add_development_dependency 'sinatra'
|
27
29
|
gem.add_development_dependency 'mocha'
|
28
30
|
gem.add_development_dependency 'rack-test'
|
31
|
+
gem.add_development_dependency 'minitest', '~> 5.0.7'
|
29
32
|
|
30
33
|
if RUBY_PLATFORM != "java"
|
31
34
|
gem.add_development_dependency 'coveralls'
|
data/tasks/bundler.task
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
data/tasks/minitest.task
ADDED
data/test/helper.rb
CHANGED
@@ -3,15 +3,26 @@ if RUBY_PLATFORM != "java"
|
|
3
3
|
Coveralls.wear!
|
4
4
|
end
|
5
5
|
|
6
|
-
require 'minitest/autorun'
|
7
|
-
require 'mocha/setup'
|
8
|
-
require 'rack/test'
|
9
|
-
|
10
6
|
require 'sidekiq'
|
11
7
|
require 'sidekiq/testing'
|
12
8
|
|
9
|
+
require 'minitest'
|
10
|
+
require 'mocha/setup'
|
11
|
+
require 'rack/test'
|
12
|
+
|
13
13
|
require 'sidetiq'
|
14
14
|
require 'sidetiq/web'
|
15
|
+
require 'sidetiq/lock/watcher'
|
16
|
+
|
17
|
+
class Sidetiq::Supervisor
|
18
|
+
def self.clock
|
19
|
+
@clock ||= Sidetiq::Clock.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.handler
|
23
|
+
Sidetiq::Handler.new
|
24
|
+
end
|
25
|
+
end
|
15
26
|
|
16
27
|
# Keep the test output clean.
|
17
28
|
Sidetiq.logger = Logger.new(nil)
|
@@ -34,13 +45,13 @@ class Sidekiq::Client
|
|
34
45
|
end
|
35
46
|
end
|
36
47
|
|
37
|
-
class Sidetiq::TestCase < MiniTest::
|
48
|
+
class Sidetiq::TestCase < MiniTest::Test
|
38
49
|
def setup
|
39
50
|
Sidekiq.redis { |r| r.flushall }
|
40
51
|
end
|
41
52
|
|
42
53
|
def clock
|
43
|
-
|
54
|
+
Sidetiq.clock
|
44
55
|
end
|
45
56
|
|
46
57
|
# Blatantly stolen from Sidekiq's test suite.
|
@@ -55,3 +66,7 @@ class Sidetiq::TestCase < MiniTest::Unit::TestCase
|
|
55
66
|
end
|
56
67
|
end
|
57
68
|
|
69
|
+
# Override Celluloid's at_exit hook manually.
|
70
|
+
at_exit {
|
71
|
+
exit Minitest.run(ARGV) || false
|
72
|
+
}
|
data/test/test_clock.rb
CHANGED
@@ -1,30 +1,6 @@
|
|
1
1
|
require_relative 'helper'
|
2
2
|
|
3
3
|
class TestClock < Sidetiq::TestCase
|
4
|
-
def test_delegates_to_instance
|
5
|
-
Sidetiq::Clock.instance.expects(:foo).once
|
6
|
-
Sidetiq::Clock.foo
|
7
|
-
end
|
8
|
-
|
9
|
-
def test_start_stop
|
10
|
-
refute clock.ticking?
|
11
|
-
assert_nil clock.thread
|
12
|
-
|
13
|
-
clock.start!
|
14
|
-
Thread.pass
|
15
|
-
sleep 0.01
|
16
|
-
|
17
|
-
assert clock.ticking?
|
18
|
-
assert_kind_of Thread, clock.thread
|
19
|
-
|
20
|
-
clock.stop!
|
21
|
-
Thread.pass
|
22
|
-
sleep 0.01
|
23
|
-
|
24
|
-
refute clock.ticking?
|
25
|
-
refute clock.thread.alive?
|
26
|
-
end
|
27
|
-
|
28
4
|
def test_gettime_seconds
|
29
5
|
assert_equal clock.gettime.tv_sec, Time.now.tv_sec
|
30
6
|
end
|
@@ -118,6 +94,22 @@ class TestClock < Sidetiq::TestCase
|
|
118
94
|
clock.tick
|
119
95
|
end
|
120
96
|
|
97
|
+
def test_enqueues_jobs_with_last_run_timestamp_if_optional_argument
|
98
|
+
schedule = Sidetiq::Schedule.new
|
99
|
+
schedule.hourly
|
100
|
+
|
101
|
+
time = Time.local(2011, 1, 1, 1, 30)
|
102
|
+
|
103
|
+
clock.stubs(:gettime).returns(time, time + 3600)
|
104
|
+
clock.stubs(:schedules).returns(OptionalArgumentWorker => schedule)
|
105
|
+
|
106
|
+
expected_first_tick = time + 1800
|
107
|
+
|
108
|
+
OptionalArgumentWorker.expects(:perform_at)
|
109
|
+
.with(expected_first_tick, -1).once
|
110
|
+
clock.tick
|
111
|
+
end
|
112
|
+
|
121
113
|
def test_enqueues_jobs_correctly_for_splat_args_perform_methods
|
122
114
|
schedule = Sidetiq::Schedule.new
|
123
115
|
schedule.hourly
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require_relative 'helper'
|
2
|
+
|
3
|
+
class TestHistory < Sidetiq::TestCase
|
4
|
+
class HistoryWorker
|
5
|
+
include Sidekiq::Worker
|
6
|
+
include Sidetiq::Schedulable
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_success
|
10
|
+
middlewared do; end
|
11
|
+
|
12
|
+
entry = Sidekiq.redis do |redis|
|
13
|
+
redis.lrange('sidetiq:TestHistory::HistoryWorker:history', 0, -1)
|
14
|
+
end
|
15
|
+
|
16
|
+
actual = JSON.parse(entry[0], symbolize_names: true)
|
17
|
+
|
18
|
+
assert_equal 'success', actual[:status]
|
19
|
+
|
20
|
+
assert_empty actual[:error]
|
21
|
+
assert_empty actual[:backtrace]
|
22
|
+
assert_empty actual[:exception]
|
23
|
+
|
24
|
+
refute_empty actual[:node]
|
25
|
+
refute_empty actual[:timestamp]
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_failure
|
29
|
+
begin
|
30
|
+
middlewared do
|
31
|
+
raise StandardError.new("failed")
|
32
|
+
end
|
33
|
+
rescue
|
34
|
+
end
|
35
|
+
|
36
|
+
entry = Sidekiq.redis do |redis|
|
37
|
+
redis.lrange('sidetiq:TestHistory::HistoryWorker:history', 0, -1)
|
38
|
+
end
|
39
|
+
|
40
|
+
actual = JSON.parse(entry[0], symbolize_names: true)
|
41
|
+
|
42
|
+
assert_equal 'failure', actual[:status]
|
43
|
+
|
44
|
+
assert_equal "failed", actual[:error]
|
45
|
+
assert_equal "StandardError", actual[:exception]
|
46
|
+
refute_empty actual[:backtrace]
|
47
|
+
|
48
|
+
refute_empty actual[:node]
|
49
|
+
refute_empty actual[:timestamp]
|
50
|
+
end
|
51
|
+
|
52
|
+
def middlewared
|
53
|
+
middleware = Sidetiq::Middleware::History.new
|
54
|
+
|
55
|
+
middleware.call(HistoryWorker.new, {}, 'default') do
|
56
|
+
yield
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require_relative 'helper'
|
2
|
+
|
3
|
+
class TestLockMetaData < Sidetiq::TestCase
|
4
|
+
def new_without_params
|
5
|
+
md = Sidetiq::Lock::MetaData.new
|
6
|
+
|
7
|
+
assert_nil md.owner
|
8
|
+
assert_nil md.timestamp
|
9
|
+
assert_nil md.key
|
10
|
+
end
|
11
|
+
|
12
|
+
def new_with_empty_hash
|
13
|
+
md = Sidetiq::Lock::MetaData.new({})
|
14
|
+
|
15
|
+
assert_nil md.owner
|
16
|
+
assert_nil md.timestamp
|
17
|
+
assert_nil md.key
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_from_json
|
21
|
+
json = { timestamp: 42, owner: "me", key: "foobar" }.to_json
|
22
|
+
md = Sidetiq::Lock::MetaData.from_json(json)
|
23
|
+
|
24
|
+
assert_equal 42, md.timestamp
|
25
|
+
assert_equal "me", md.owner
|
26
|
+
assert_equal "foobar", md.key
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_from_json_with_empty_string_json
|
30
|
+
md = Sidetiq::Lock::MetaData.from_json(nil)
|
31
|
+
|
32
|
+
assert_nil md.owner
|
33
|
+
assert_nil md.timestamp
|
34
|
+
assert_nil md.key
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_from_json_with_nil_json
|
38
|
+
md = Sidetiq::Lock::MetaData.from_json("")
|
39
|
+
|
40
|
+
assert_nil md.owner
|
41
|
+
assert_nil md.timestamp
|
42
|
+
assert_nil md.key
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_pttl
|
46
|
+
lock = Sidetiq::Lock::Redis.new("foobar", 1000000)
|
47
|
+
md = Sidekiq.redis do |r|
|
48
|
+
lock.lock
|
49
|
+
Sidetiq::Lock::MetaData.from_json(r.get(lock.key))
|
50
|
+
end
|
51
|
+
|
52
|
+
# Allow 10 ms.
|
53
|
+
assert md.pttl <= 1000000
|
54
|
+
assert md.pttl > 999990
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_from_json_with_malformed_json
|
58
|
+
Sidetiq::Lock::MetaData.expects(:handle_exception).once
|
59
|
+
|
60
|
+
md = Sidetiq::Lock::MetaData.from_json('invalid')
|
61
|
+
|
62
|
+
assert_nil md.owner
|
63
|
+
assert_nil md.timestamp
|
64
|
+
assert_nil md.key
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_for_new_lock
|
68
|
+
md = Sidetiq::Lock::MetaData.for_new_lock("baz")
|
69
|
+
|
70
|
+
assert_equal Sidetiq::Lock::MetaData::OWNER, md.owner
|
71
|
+
assert_equal "baz", md.key
|
72
|
+
|
73
|
+
assert md.timestamp > 0
|
74
|
+
assert md.timestamp <= Time.now.to_f
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_to_json
|
78
|
+
hash = { timestamp: 42, owner: "me", key: "foobar" }
|
79
|
+
md = Sidetiq::Lock::MetaData.new(hash)
|
80
|
+
|
81
|
+
assert_equal hash, JSON.parse(md.to_json, symbolize_names: true)
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_to_s
|
85
|
+
md = Sidetiq::Lock::MetaData.new(timestamp: 42, owner: "me", key: "foobar")
|
86
|
+
|
87
|
+
assert_equal "Sidetiq::Lock on foobar set at 42 by me", md.to_s
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require_relative 'helper'
|
2
|
+
|
3
|
+
class TestLockRedis < Sidetiq::TestCase
|
4
|
+
def test_locking
|
5
|
+
lock_name = SecureRandom.hex(8)
|
6
|
+
key = SecureRandom.hex(8)
|
7
|
+
|
8
|
+
Sidekiq.redis do |redis|
|
9
|
+
redis.set(key, 0)
|
10
|
+
|
11
|
+
5.times.map do
|
12
|
+
Thread.start do
|
13
|
+
locked(lock_name) do |r|
|
14
|
+
sleep 0.1
|
15
|
+
r.incr(key)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end.each(&:join)
|
19
|
+
|
20
|
+
assert_equal "1", redis.get(key)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_all
|
25
|
+
Sidekiq.redis do |redis|
|
26
|
+
redis.set("sidetiq:Foobar:lock", 1)
|
27
|
+
end
|
28
|
+
|
29
|
+
locks = Sidetiq::Lock::Redis.all
|
30
|
+
|
31
|
+
assert_equal "sidetiq:Foobar:lock", locks.first.key
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_unlock!
|
35
|
+
Sidekiq.redis do |redis|
|
36
|
+
redis.set("sidetiq:Foobar:lock", 1)
|
37
|
+
|
38
|
+
Sidetiq::Lock::Redis.new("Foobar").unlock!
|
39
|
+
|
40
|
+
assert_nil redis.get("sidetiq:Foobar:lock")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_lock_sets_correct_meta_data
|
45
|
+
key = SecureRandom.hex(8)
|
46
|
+
internal_key = "sidetiq:#{key}:lock"
|
47
|
+
|
48
|
+
locked(key) do |redis|
|
49
|
+
json = redis.get(internal_key)
|
50
|
+
md = Sidetiq::Lock::MetaData.from_json(json)
|
51
|
+
|
52
|
+
assert_equal Sidetiq::Lock::MetaData::OWNER, md.owner
|
53
|
+
assert_equal internal_key, md.key
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def locked(lock_name)
|
58
|
+
Sidetiq::Lock::Redis.new(lock_name).synchronize do |redis|
|
59
|
+
yield redis
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
data/test/test_version.rb
CHANGED
@@ -15,7 +15,8 @@ class TestVersion < Sidetiq::TestCase
|
|
15
15
|
|
16
16
|
def test_string
|
17
17
|
assert_equal Sidetiq::VERSION::STRING, [Sidetiq::VERSION::MAJOR,
|
18
|
-
|
18
|
+
Sidetiq::VERSION::MINOR, Sidetiq::VERSION::PATCH,
|
19
|
+
Sidetiq::VERSION::SUFFIX].compact.join('.')
|
19
20
|
end
|
20
21
|
end
|
21
22
|
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require_relative 'helper'
|
2
|
+
|
3
|
+
class TestWatcher < Sidetiq::TestCase
|
4
|
+
def setup
|
5
|
+
Sidetiq.config.lock.watcher.remove_lock = true
|
6
|
+
Sidetiq.config.lock.watcher.notify = true
|
7
|
+
|
8
|
+
@worker = Sidetiq::Lock::Watcher.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_perform
|
12
|
+
Sidetiq::Lock::Redis.new("foobar", 1000000).lock
|
13
|
+
|
14
|
+
assert_equal 1, Sidetiq::Lock::Redis.all.length
|
15
|
+
|
16
|
+
@worker.expects(:handle_exception).once
|
17
|
+
|
18
|
+
@worker.perform
|
19
|
+
|
20
|
+
assert_equal 0, Sidetiq::Lock::Redis.all.length
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
data/test/test_web.rb
CHANGED
@@ -33,8 +33,18 @@ class TestWeb < Sidetiq::TestCase
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
-
def
|
37
|
-
get "/sidetiq/
|
36
|
+
def test_locks_page
|
37
|
+
get "/sidetiq/locks"
|
38
|
+
assert_equal 200, last_response.status
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_history_page
|
42
|
+
get "/sidetiq/ScheduledWorker/history"
|
43
|
+
assert_equal 200, last_response.status
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_schedule_page
|
47
|
+
get "/sidetiq/ScheduledWorker/schedule"
|
38
48
|
assert_equal 200, last_response.status
|
39
49
|
schedule = clock.schedules[ScheduledWorker]
|
40
50
|
|
@@ -57,5 +67,19 @@ class TestWeb < Sidetiq::TestCase
|
|
57
67
|
assert_equal "http://#{host}/sidetiq", last_response.location
|
58
68
|
assert_equal 1, ScheduledWorker.jobs.size
|
59
69
|
end
|
70
|
+
|
71
|
+
def test_unlock
|
72
|
+
Sidekiq.redis do |redis|
|
73
|
+
redis.set("sidetiq:Foo:lock", 1)
|
74
|
+
end
|
75
|
+
|
76
|
+
post "/sidetiq/Foo/unlock"
|
77
|
+
assert_equal 302, last_response.status
|
78
|
+
assert_equal "http://#{host}/sidetiq/locks", last_response.location
|
79
|
+
|
80
|
+
Sidekiq.redis do |redis|
|
81
|
+
assert_nil redis.get("sidetiq:Foo:lock")
|
82
|
+
end
|
83
|
+
end
|
60
84
|
end
|
61
85
|
|