sidekiq-merger 0.0.1 → 0.0.4
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 +4 -4
- data/.dockerignore +21 -0
- data/.gemrelease +2 -0
- data/.gitignore +19 -9
- data/.travis.yml +5 -1
- data/Dockerfile +10 -0
- data/Gemfile +3 -1
- data/README.md +68 -6
- data/app/Gemfile +8 -0
- data/app/app.rb +43 -0
- data/app/config.ru +3 -0
- data/app/sidekiq.rb +25 -0
- data/app/some_worker.rb +9 -0
- data/app/unique_worker.rb +9 -0
- data/app/views/index.erb +35 -0
- data/docker-compose-common.yml +7 -0
- data/docker-compose.yml +26 -0
- data/lib/sidekiq/merger.rb +14 -18
- data/lib/sidekiq/merger/flusher.rb +4 -4
- data/lib/sidekiq/merger/merge.rb +113 -0
- data/lib/sidekiq/merger/middleware.rb +6 -4
- data/lib/sidekiq/merger/redis.rb +52 -25
- data/lib/sidekiq/merger/version.rb +1 -1
- data/lib/sidekiq/merger/views/index.erb +41 -0
- data/lib/sidekiq/merger/web.rb +22 -0
- data/misc/web_ui.png +0 -0
- data/sidekiq-merger.gemspec +9 -11
- data/spec/sidekiq/merger/flusher_spec.rb +7 -7
- data/spec/sidekiq/merger/{batch_spec.rb → merge_spec.rb} +31 -17
- data/spec/sidekiq/merger/middleware_spec.rb +12 -6
- data/spec/sidekiq/merger/redis_spec.rb +99 -69
- data/spec/spec_helper.rb +7 -2
- metadata +73 -66
- data/bin/console +0 -7
- data/bin/setup +0 -8
- data/lib/sidekiq/merger/batch.rb +0 -100
@@ -0,0 +1,113 @@
|
|
1
|
+
require_relative "redis"
|
2
|
+
require "active_support/core_ext/hash/indifferent_access"
|
3
|
+
|
4
|
+
class Sidekiq::Merger::Merge
|
5
|
+
class << self
|
6
|
+
def all
|
7
|
+
redis = Sidekiq::Merger::Redis.new
|
8
|
+
|
9
|
+
redis.all.map { |full_merge_key| initialize_with_full_merge_key(full_merge_key, redis: redis) }
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize_with_full_merge_key(full_merge_key, options = {})
|
13
|
+
keys = full_merge_key.split(":")
|
14
|
+
raise "Invalid merge key" if keys.size < 3
|
15
|
+
worker_class = keys[0].camelize.constantize
|
16
|
+
queue = keys[1]
|
17
|
+
merge_key = keys[2]
|
18
|
+
new(worker_class, queue, merge_key, options)
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize_with_args(worker_class, queue, args, options = {})
|
22
|
+
new(worker_class, queue, merge_key(worker_class, args), options)
|
23
|
+
end
|
24
|
+
|
25
|
+
def merge_key(worker_class, args)
|
26
|
+
options = get_options(worker_class)
|
27
|
+
merge_key = options["key"]
|
28
|
+
if merge_key.respond_to?(:call)
|
29
|
+
merge_key.call(args)
|
30
|
+
else
|
31
|
+
merge_key
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def get_options(worker_class)
|
36
|
+
(worker_class.get_sidekiq_options["merger"] || {}).with_indifferent_access
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
attr_reader :worker_class, :queue, :merge_key
|
41
|
+
|
42
|
+
def initialize(worker_class, queue, merge_key, redis: Sidekiq::Merger::Redis.new)
|
43
|
+
@worker_class = worker_class
|
44
|
+
@queue = queue
|
45
|
+
@merge_key = merge_key
|
46
|
+
@redis = redis
|
47
|
+
end
|
48
|
+
|
49
|
+
def add(args, execution_time)
|
50
|
+
if !options[:unique] || !@redis.exists?(full_merge_key, args)
|
51
|
+
@redis.push(full_merge_key, args, execution_time)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def delete(args)
|
56
|
+
@redis.delete(full_merge_key, args)
|
57
|
+
end
|
58
|
+
|
59
|
+
def delete_all
|
60
|
+
@redis.delete_all(full_merge_key)
|
61
|
+
end
|
62
|
+
|
63
|
+
def size
|
64
|
+
@redis.merge_size(full_merge_key)
|
65
|
+
end
|
66
|
+
|
67
|
+
def flush
|
68
|
+
msgs = []
|
69
|
+
|
70
|
+
if @redis.lock(full_merge_key, Sidekiq::Merger::Config.lock_ttl)
|
71
|
+
msgs = @redis.pluck(full_merge_key)
|
72
|
+
end
|
73
|
+
|
74
|
+
unless msgs.empty?
|
75
|
+
Sidekiq::Client.push(
|
76
|
+
"class" => worker_class,
|
77
|
+
"queue" => queue,
|
78
|
+
"args" => msgs,
|
79
|
+
"merged" => true
|
80
|
+
)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def can_flush?
|
85
|
+
!execution_time.nil? && execution_time < Time.now
|
86
|
+
end
|
87
|
+
|
88
|
+
def full_merge_key
|
89
|
+
@full_merge_key ||= [worker_class.name.to_s.underscore, queue, merge_key].join(":")
|
90
|
+
end
|
91
|
+
|
92
|
+
def all_args
|
93
|
+
@redis.get(full_merge_key)
|
94
|
+
end
|
95
|
+
|
96
|
+
def execution_time
|
97
|
+
@execution_time ||= @redis.execution_time(full_merge_key)
|
98
|
+
end
|
99
|
+
|
100
|
+
def ==(other)
|
101
|
+
self.worker_class == other.worker_class &&
|
102
|
+
self.queue == other.queue &&
|
103
|
+
self.merge_key == other.merge_key
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
def options
|
109
|
+
@options ||= self.class.get_options(worker_class)
|
110
|
+
rescue NameError
|
111
|
+
{}
|
112
|
+
end
|
113
|
+
end
|
@@ -1,18 +1,20 @@
|
|
1
|
-
require_relative "
|
1
|
+
require_relative "merge"
|
2
2
|
|
3
3
|
class Sidekiq::Merger::Middleware
|
4
|
-
def call(worker_class, msg, queue,
|
4
|
+
def call(worker_class, msg, queue, redis_pool = nil)
|
5
5
|
return yield if defined?(Sidekiq::Testing) && Sidekiq::Testing.inline?
|
6
6
|
|
7
7
|
worker_class = worker_class.camelize.constantize if worker_class.is_a?(String)
|
8
8
|
options = worker_class.get_sidekiq_options
|
9
9
|
|
10
10
|
if !msg["at"].nil? && options.key?("merger")
|
11
|
-
Sidekiq::Merger::
|
11
|
+
Sidekiq::Merger::Merge
|
12
12
|
.initialize_with_args(worker_class, queue, msg["args"])
|
13
13
|
.add(msg["args"], msg["at"])
|
14
|
+
false
|
14
15
|
else
|
15
|
-
|
16
|
+
msg["args"] = [msg["args"]] unless msg.delete("merged")
|
17
|
+
yield(worker_class, msg, queue, redis_pool)
|
16
18
|
end
|
17
19
|
end
|
18
20
|
end
|
data/lib/sidekiq/merger/redis.rb
CHANGED
@@ -13,12 +13,16 @@ class Sidekiq::Merger::Redis
|
|
13
13
|
end
|
14
14
|
return true
|
15
15
|
SCRIPT
|
16
|
-
conn.eval(script, [], [
|
16
|
+
conn.eval(script, [], [merges_key, unique_msg_key("*"), msg_key("*"), lock_key("*")])
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
def
|
21
|
-
"#{KEY_PREFIX}:
|
20
|
+
def merges_key
|
21
|
+
"#{KEY_PREFIX}:merges"
|
22
|
+
end
|
23
|
+
|
24
|
+
def unique_msg_key(key)
|
25
|
+
"#{KEY_PREFIX}:unique_msg:#{key}"
|
22
26
|
end
|
23
27
|
|
24
28
|
def msg_key(key)
|
@@ -39,33 +43,45 @@ class Sidekiq::Merger::Redis
|
|
39
43
|
end
|
40
44
|
|
41
45
|
def push(key, msg, execution_time)
|
46
|
+
msg_json = msg.to_json
|
42
47
|
redis do |conn|
|
43
48
|
conn.multi do
|
44
|
-
conn.sadd(
|
45
|
-
conn.setnx(time_key(key), execution_time.
|
46
|
-
conn.
|
49
|
+
conn.sadd(merges_key, key)
|
50
|
+
conn.setnx(time_key(key), execution_time.to_i)
|
51
|
+
conn.lpush(msg_key(key), msg_json)
|
52
|
+
conn.sadd(unique_msg_key(key), msg_json)
|
47
53
|
end
|
48
54
|
end
|
49
55
|
end
|
50
56
|
|
51
57
|
def delete(key, msg)
|
52
|
-
|
58
|
+
msg_json = msg.to_json
|
59
|
+
redis do |conn|
|
60
|
+
conn.multi do
|
61
|
+
conn.srem(unique_msg_key(key), msg_json)
|
62
|
+
conn.lrem(msg_key(key), msg_json)
|
63
|
+
end
|
64
|
+
end
|
53
65
|
end
|
54
66
|
|
55
67
|
def execution_time(key)
|
56
|
-
redis
|
68
|
+
redis do |conn|
|
69
|
+
t = conn.get(time_key(key))
|
70
|
+
Time.at(t.to_i) unless t.nil?
|
71
|
+
end
|
57
72
|
end
|
58
73
|
|
59
|
-
def
|
60
|
-
redis { |conn| conn.
|
74
|
+
def merge_size(key)
|
75
|
+
redis { |conn| conn.llen(msg_key(key)) }
|
61
76
|
end
|
62
77
|
|
63
78
|
def exists?(key, msg)
|
64
|
-
|
79
|
+
msg_json = msg.to_json
|
80
|
+
redis { |conn| conn.sismember(unique_msg_key(key), msg_json) }
|
65
81
|
end
|
66
82
|
|
67
83
|
def all
|
68
|
-
redis { |conn| conn.smembers(
|
84
|
+
redis { |conn| conn.smembers(merges_key) }
|
69
85
|
end
|
70
86
|
|
71
87
|
def lock(key, ttl)
|
@@ -74,33 +90,44 @@ class Sidekiq::Merger::Redis
|
|
74
90
|
|
75
91
|
def get(key)
|
76
92
|
msgs = []
|
77
|
-
redis
|
78
|
-
msgs = conn.smembers(msg_key(key))
|
79
|
-
end
|
93
|
+
redis { |conn| msgs = conn.lrange(msg_key(key), 0, -1) }
|
80
94
|
msgs.map { |msg| JSON.parse(msg) }
|
81
95
|
end
|
82
96
|
|
83
97
|
def pluck(key)
|
84
98
|
msgs = []
|
85
99
|
redis do |conn|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
100
|
+
conn.multi do
|
101
|
+
msgs = conn.lrange(msg_key(key), 0, -1)
|
102
|
+
conn.del(unique_msg_key(key))
|
103
|
+
conn.del(msg_key(key))
|
104
|
+
conn.del(time_key(key))
|
105
|
+
conn.srem(merges_key, key)
|
106
|
+
end
|
90
107
|
end
|
91
|
-
msgs.map { |msg| JSON.parse(msg) }
|
108
|
+
extract_future_value(msgs).map { |msg| JSON.parse(msg) }
|
92
109
|
end
|
93
110
|
|
94
111
|
def delete_all(key)
|
95
112
|
redis do |conn|
|
96
|
-
conn.
|
97
|
-
|
98
|
-
|
99
|
-
|
113
|
+
conn.multi do
|
114
|
+
conn.del(unique_msg_key(key))
|
115
|
+
conn.del(msg_key(key))
|
116
|
+
conn.del(time_key(key))
|
117
|
+
conn.del(lock_key(key))
|
118
|
+
conn.srem(merges_key, key)
|
119
|
+
end
|
100
120
|
end
|
101
121
|
end
|
102
122
|
|
103
123
|
private
|
104
124
|
|
105
|
-
delegate :
|
125
|
+
delegate :merges_key, :msg_key, :unique_msg_key, :time_key, :lock_key, :redis, to: "self.class"
|
126
|
+
|
127
|
+
def extract_future_value(future)
|
128
|
+
while future.value.is_a?(Redis::FutureNotReady)
|
129
|
+
sleep(0.001)
|
130
|
+
end
|
131
|
+
future.value
|
132
|
+
end
|
106
133
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
<header class="row">
|
2
|
+
<div class="col-sm-5">
|
3
|
+
<h3>Merged jobs</h3>
|
4
|
+
</div>
|
5
|
+
</header>
|
6
|
+
|
7
|
+
<div class="container">
|
8
|
+
<div class="row">
|
9
|
+
<div class="col-sm-12">
|
10
|
+
<% if true %>
|
11
|
+
<table class="table table-striped table-bordered table-white" style="width: 100%; margin: 0; table-layout:fixed;">
|
12
|
+
<thead>
|
13
|
+
<th style="width: 25%">Worker</th>
|
14
|
+
<th style="width: 15%">Queue</th>
|
15
|
+
<th style="width: 10%">Count</th>
|
16
|
+
<th style="width: 20%">All Args</th>
|
17
|
+
<th style="width: 20%">Execution time</th>
|
18
|
+
<th style="width: 10%">Actions</th>
|
19
|
+
</thead>
|
20
|
+
<% @merges.each do |merge| %>
|
21
|
+
<tr>
|
22
|
+
<td><%= merge.worker_class %></td>
|
23
|
+
<td><%= merge.queue %></td>
|
24
|
+
<td><%= merge.size %></td>
|
25
|
+
<td><%= merge.all_args %></td>
|
26
|
+
<td><%= merge.execution_time || "–"%></td>
|
27
|
+
<td>
|
28
|
+
<form action="<%= "#{root_path}merger/#{URI.encode_www_form_component merge.full_merge_key}/delete" %>" method="post">
|
29
|
+
<%= csrf_tag %>
|
30
|
+
<input class="btn btn-danger btn-xs" type="submit" name="delete" value="Delete" data-confirm="Are you sure you want to delete this merge?" />
|
31
|
+
</form>
|
32
|
+
</td>
|
33
|
+
</tr>
|
34
|
+
<% end %>
|
35
|
+
</table>
|
36
|
+
<% else %>
|
37
|
+
<div class="alert alert-success">No recurring jobs found.</div>
|
38
|
+
<% end %>
|
39
|
+
</div>
|
40
|
+
</div>
|
41
|
+
</div>
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "sidekiq/web"
|
2
|
+
|
3
|
+
module Sidekiq::Merger::Web
|
4
|
+
VIEWS = File.expand_path("views", File.dirname(__FILE__))
|
5
|
+
|
6
|
+
def self.registered(app)
|
7
|
+
app.get "/merger" do
|
8
|
+
@merges = Sidekiq::Merger::Merge.all
|
9
|
+
erb File.read(File.join(VIEWS, "index.erb")), locals: { view_path: VIEWS }
|
10
|
+
end
|
11
|
+
|
12
|
+
app.post "/merger/:full_merge_key/delete" do
|
13
|
+
full_merge_key = URI.decode_www_form_component params[:full_merge_key]
|
14
|
+
merge = Sidekiq::Merger::Merge.initialize_with_full_merge_key(full_merge_key)
|
15
|
+
merge.delete_all
|
16
|
+
redirect "#{root_path}/merger"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
Sidekiq::Web.register(Sidekiq::Merger::Web)
|
22
|
+
Sidekiq::Web.tabs["Merger"] = "merger"
|
data/misc/web_ui.png
ADDED
Binary file
|
data/sidekiq-merger.gemspec
CHANGED
@@ -24,16 +24,14 @@ Gem::Specification.new do |spec|
|
|
24
24
|
|
25
25
|
spec.required_ruby_version = [">= 2.2.2", "< 2.5"]
|
26
26
|
|
27
|
-
spec.add_development_dependency "
|
28
|
-
spec.add_development_dependency "
|
29
|
-
spec.add_development_dependency "
|
30
|
-
spec.add_development_dependency "
|
31
|
-
spec.add_development_dependency "
|
32
|
-
spec.add_development_dependency "
|
33
|
-
spec.add_development_dependency "pry"
|
34
|
-
spec.add_development_dependency "coveralls"
|
27
|
+
spec.add_development_dependency "rake", ">= 10.0", "< 13"
|
28
|
+
spec.add_development_dependency "rspec", ">= 3.0", "< 4"
|
29
|
+
spec.add_development_dependency "simplecov", "~> 0.12"
|
30
|
+
spec.add_development_dependency "timecop", "~> 0.8"
|
31
|
+
spec.add_development_dependency "rubocop", "~> 0.47"
|
32
|
+
spec.add_development_dependency "coveralls", "~> 0.8"
|
35
33
|
|
36
|
-
spec.
|
37
|
-
spec.
|
38
|
-
spec.
|
34
|
+
spec.add_runtime_dependency "sidekiq", ">= 3.4", "< 5"
|
35
|
+
spec.add_runtime_dependency "concurrent-ruby", "~> 1.0"
|
36
|
+
spec.add_runtime_dependency "activesupport", ">= 3.2", "< 6"
|
39
37
|
end
|
@@ -4,13 +4,13 @@ describe Sidekiq::Merger::Flusher do
|
|
4
4
|
subject { described_class.new(Sidekiq.logger) }
|
5
5
|
|
6
6
|
describe "#call" do
|
7
|
-
let(:
|
8
|
-
let(:
|
9
|
-
let(:
|
10
|
-
it "adds the args to the
|
11
|
-
allow(Sidekiq::Merger::
|
12
|
-
expect(
|
13
|
-
expect(
|
7
|
+
let(:active_merge) { double(full_merge_key: "active", can_flush?: true, flush: nil) }
|
8
|
+
let(:inactive_merge) { double(full_merge_key: "inactive", can_flush?: false, flush: nil) }
|
9
|
+
let(:merges) { [active_merge, inactive_merge] }
|
10
|
+
it "adds the args to the merge" do
|
11
|
+
allow(Sidekiq::Merger::Merge).to receive(:all).and_return merges
|
12
|
+
expect(active_merge).to receive(:flush)
|
13
|
+
expect(inactive_merge).not_to receive(:flush)
|
14
14
|
|
15
15
|
subject.flush
|
16
16
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
-
describe Sidekiq::Merger::
|
3
|
+
describe Sidekiq::Merger::Merge do
|
4
4
|
subject { described_class.new(worker_class, queue, "foo", redis: redis) }
|
5
5
|
let(:redis) { Sidekiq::Merger::Redis.new }
|
6
6
|
let(:queue) { "queue" }
|
@@ -27,8 +27,8 @@ describe Sidekiq::Merger::Batch do
|
|
27
27
|
describe ".all" do
|
28
28
|
it "returns all the keys" do
|
29
29
|
redis.redis do |conn|
|
30
|
-
conn.sadd("sidekiq-merger:
|
31
|
-
conn.sadd("sidekiq-merger:
|
30
|
+
conn.sadd("sidekiq-merger:merges", "string:foo:xxx")
|
31
|
+
conn.sadd("sidekiq-merger:merges", "numeric:bar:yyy")
|
32
32
|
end
|
33
33
|
|
34
34
|
expect(described_class.all).to contain_exactly(
|
@@ -40,18 +40,18 @@ describe Sidekiq::Merger::Batch do
|
|
40
40
|
context "including invalid key" do
|
41
41
|
it "raises an error" do
|
42
42
|
redis.redis do |conn|
|
43
|
-
conn.sadd("sidekiq-merger:
|
44
|
-
conn.sadd("sidekiq-merger:
|
43
|
+
conn.sadd("sidekiq-merger:merges", "string:foo:xxx")
|
44
|
+
conn.sadd("sidekiq-merger:merges", "invalid")
|
45
45
|
end
|
46
46
|
expect {
|
47
47
|
described_class.all
|
48
|
-
}.to raise_error RuntimeError, "Invalid
|
48
|
+
}.to raise_error RuntimeError, "Invalid merge key"
|
49
49
|
end
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
53
|
describe ".initialize_with_args" do
|
54
|
-
it "provides
|
54
|
+
it "provides merge_key from args" do
|
55
55
|
expect(described_class).to receive(:new).with(worker_class, queue, "[1,2,3]", anything)
|
56
56
|
described_class.initialize_with_args(worker_class, queue, [1, 2, 3])
|
57
57
|
end
|
@@ -62,14 +62,28 @@ describe Sidekiq::Merger::Batch do
|
|
62
62
|
end
|
63
63
|
|
64
64
|
describe "#add" do
|
65
|
-
it "adds the args in lazy
|
65
|
+
it "adds the args in lazy merge" do
|
66
66
|
expect(redis).to receive(:push).with("name:queue:foo", [1, 2, 3], execution_time)
|
67
67
|
subject.add([1, 2, 3], execution_time)
|
68
68
|
end
|
69
|
+
context "with unique option" do
|
70
|
+
let(:options) { { key: -> (args) { args.to_json }, unique: true } }
|
71
|
+
it "adds the args in lazy merge" do
|
72
|
+
expect(redis).to receive(:push).with("name:queue:foo", [1, 2, 3], execution_time)
|
73
|
+
subject.add([1, 2, 3], execution_time)
|
74
|
+
end
|
75
|
+
context "the args has alredy been added" do
|
76
|
+
before { subject.add([1, 2, 3], execution_time) }
|
77
|
+
it "adds the args in lazy merge" do
|
78
|
+
expect(redis).not_to receive(:push)
|
79
|
+
subject.add([1, 2, 3], execution_time)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
69
83
|
end
|
70
84
|
|
71
85
|
describe "#delete" do
|
72
|
-
it "adds the args in lazy
|
86
|
+
it "adds the args in lazy merge" do
|
73
87
|
expect(redis).to receive(:delete).with("name:queue:foo", [1, 2, 3])
|
74
88
|
subject.delete([1, 2, 3])
|
75
89
|
end
|
@@ -87,7 +101,8 @@ describe Sidekiq::Merger::Batch do
|
|
87
101
|
expect(Sidekiq::Client).to receive(:push).with(
|
88
102
|
"class" => worker_class,
|
89
103
|
"queue" => queue,
|
90
|
-
"args" => [
|
104
|
+
"args" => a_collection_containing_exactly([1, 2, 3], [2, 3, 4]),
|
105
|
+
"merged" => true
|
91
106
|
)
|
92
107
|
|
93
108
|
subject.flush
|
@@ -95,19 +110,18 @@ describe Sidekiq::Merger::Batch do
|
|
95
110
|
end
|
96
111
|
|
97
112
|
describe "#can_flush?" do
|
98
|
-
|
99
|
-
context "it has not get anything in batch" do
|
113
|
+
context "it has not get anything in merge" do
|
100
114
|
it "returns false" do
|
101
115
|
expect(subject.can_flush?).to eq false
|
102
116
|
end
|
103
117
|
end
|
104
|
-
context "it has not passed the
|
118
|
+
context "it has not passed the execution time" do
|
105
119
|
it "returns false" do
|
106
120
|
subject.add([], execution_time)
|
107
121
|
expect(subject.can_flush?).to eq false
|
108
122
|
end
|
109
123
|
end
|
110
|
-
context "it has passed the
|
124
|
+
context "it has passed the execution time" do
|
111
125
|
it "returns true" do
|
112
126
|
subject.add([], execution_time)
|
113
127
|
Timecop.travel(10.seconds)
|
@@ -116,9 +130,9 @@ describe Sidekiq::Merger::Batch do
|
|
116
130
|
end
|
117
131
|
end
|
118
132
|
|
119
|
-
describe "#
|
120
|
-
it "returns full
|
121
|
-
expect(subject.
|
133
|
+
describe "#full_merge_key" do
|
134
|
+
it "returns full merge key" do
|
135
|
+
expect(subject.full_merge_key).to eq "name:queue:foo"
|
122
136
|
end
|
123
137
|
end
|
124
138
|
end
|