sidekiq-bus 1.1.0 → 2.0.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/README.mdown +37 -0
- data/docker-compose.yml +18 -0
- data/lib/sidekiq-bus.rb +19 -0
- data/lib/sidekiq_bus/adapter.rb +3 -2
- data/lib/sidekiq_bus/version.rb +1 -1
- data/sidekiq-bus.gemspec +3 -5
- data/spec/adapter/integration_spec.rb +2 -5
- data/spec/adapter_spec.rb +5 -5
- data/spec/spec_helper.rb +41 -35
- metadata +20 -41
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 31218b263cfcfbc7226f2f8d30ddc2ffb24019fc9a1ee55a45cc324a592d8a60
|
4
|
+
data.tar.gz: 4bc6d366f8163ec83b392476d4fb4919b3c16c026c5713e7632c6aacab276097
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 825f2a4bf78bbfef5e4e02cbd10cbd98833eaa3e29445203877adc238db6aaa0f92aae41c27ddaf11d1ae4a81b49bb63ebf7bfdfe91a13e192d1800a529e08a1
|
7
|
+
data.tar.gz: d42466dd3302d78ed7670fdff75b5b80e59d8da9597e581a1f7324b4e9ab0cd40aa0455c397249300cc41dd5bdcb3e4f644d4743fa51fbc2aca6a2efa3239ce5
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
8
|
|
9
|
+
### Changed
|
10
|
+
|
11
|
+
## [2.0.0] - 2025-06-17
|
12
|
+
|
13
|
+
- [BREAKING] Sidekiq major version now targets 7.X
|
14
|
+
- [BREAKING] SidekiqScheduler major version now targets 5.X to support Sidekiq 7
|
15
|
+
- [BREAKING] SidekiqBus must now be configured with a Redis pool. See the README for more details.
|
16
|
+
- [Development] Discontinues use of FakeRedis in favor of real Redis for testing.
|
17
|
+
|
9
18
|
## [1.1.0] - 2025-05-13
|
10
19
|
|
11
20
|
### Changed
|
data/README.mdown
CHANGED
@@ -11,6 +11,27 @@ To install, include the 'sidekiq-bus' gem and add the following to your Rakefile
|
|
11
11
|
require "sidekiq_bus/tasks"
|
12
12
|
```
|
13
13
|
|
14
|
+
### Configure
|
15
|
+
Starting from version 7, Sidekiq no longer provides a standard Redis connection pool, instead providing a limited
|
16
|
+
wrapper around the low-level RedisClient gem. To maintain compatibility with both QueueBus and later versions of
|
17
|
+
Sidekiq, SidekiqBus now requires an explicit Redis handler. To preserve your existing QueueBus data, this handler should
|
18
|
+
connect to the same Redis instance and database as your Sidekiq configuration.
|
19
|
+
|
20
|
+
The handler can be any object that responds to `call` and yields a Redis connection. In an initializer, set it with:
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
# Naive example
|
24
|
+
SidekiqBus.redis_handler = ->(&block) { block.call(Redis.new(my_config) }
|
25
|
+
|
26
|
+
# More typical example using the Redis-recommended ConnectionPool gem
|
27
|
+
pool = ConnectionPool.new(size: pool_size, timeout: pool_timeout) { Redis.new(my_config) }
|
28
|
+
SidekiqBus.redis_handler = pool.method(:with).to_proc
|
29
|
+
# Or, for clarity:
|
30
|
+
SidekiqBus.redis_handler = ->(&block) do
|
31
|
+
pool.with { |redis| block.call(redis) }
|
32
|
+
end
|
33
|
+
```
|
34
|
+
|
14
35
|
### Example
|
15
36
|
|
16
37
|
Application A can publish an event
|
@@ -162,6 +183,22 @@ event to the appropriate code block.
|
|
162
183
|
You can also say `QueueBus.local_mode = :suppress` to turn off publishing altogether.
|
163
184
|
This can be helpful inside some sort of migration, for example.
|
164
185
|
|
186
|
+
### Development
|
187
|
+
|
188
|
+
#### Running Tests
|
189
|
+
|
190
|
+
The test suite requires a Redis instance. For convenience, we provide Docker Compose configuration to run Redis in a container:
|
191
|
+
|
192
|
+
```bash
|
193
|
+
docker-compose up -d
|
194
|
+
|
195
|
+
bundle exec rspec
|
196
|
+
```
|
197
|
+
|
198
|
+
The test suite uses database 15 by default to avoid conflicts with your development Redis data.
|
199
|
+
|
200
|
+
You can override the connection string (including the database number) by setting the `REDIS_URL` environment variable.
|
201
|
+
|
165
202
|
### TODO
|
166
203
|
|
167
204
|
* Replace local modes with adapters
|
data/docker-compose.yml
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
version: '3.8'
|
2
|
+
|
3
|
+
services:
|
4
|
+
redis:
|
5
|
+
image: redis:7-alpine
|
6
|
+
ports:
|
7
|
+
- "6379:6379"
|
8
|
+
command: redis-server --appendonly yes
|
9
|
+
volumes:
|
10
|
+
- redis_data:/data
|
11
|
+
healthcheck:
|
12
|
+
test: ["CMD", "redis-cli", "ping"]
|
13
|
+
interval: 5s
|
14
|
+
timeout: 3s
|
15
|
+
retries: 5
|
16
|
+
|
17
|
+
volumes:
|
18
|
+
redis_data:
|
data/lib/sidekiq-bus.rb
CHANGED
@@ -7,6 +7,10 @@ require 'sidekiq_bus/server'
|
|
7
7
|
require 'sidekiq_bus/middleware/retry'
|
8
8
|
|
9
9
|
module SidekiqBus
|
10
|
+
ConfigurationError = Class.new(StandardError)
|
11
|
+
REDIS_HANDLER_ERROR_MESSAGE = 'Please set SidekiqBus.redis_handler to a Callable that accepts a block and yields a '\
|
12
|
+
'Redis instance. See the SidekiqBus README for more details.'
|
13
|
+
|
10
14
|
# This method will analyze the current queues and generate an array that
|
11
15
|
# can operate as the sidekiq queues configuration. It should be based on how
|
12
16
|
# The sidekiq CLI builds weighted queues.
|
@@ -42,6 +46,21 @@ module SidekiqBus
|
|
42
46
|
# flattened into a single array
|
43
47
|
entries.flat_map { |e| Array.new(e.weight, e.queue) }
|
44
48
|
end
|
49
|
+
|
50
|
+
def self.redis_handler=(handler)
|
51
|
+
unless handler.respond_to?(:call)
|
52
|
+
raise ConfigurationError, REDIS_HANDLER_ERROR_MESSAGE
|
53
|
+
end
|
54
|
+
@redis_handler = handler
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.redis(&block)
|
58
|
+
raise ConfigurationError, REDIS_HANDLER_ERROR_MESSAGE unless @redis_handler
|
59
|
+
@redis_handler.call(&block)
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.validate_redis_handler
|
63
|
+
end
|
45
64
|
end
|
46
65
|
|
47
66
|
if QueueBus.has_adapter?
|
data/lib/sidekiq_bus/adapter.rb
CHANGED
@@ -21,7 +21,7 @@ module QueueBus
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def redis(&block)
|
24
|
-
::
|
24
|
+
::SidekiqBus.redis(&block)
|
25
25
|
end
|
26
26
|
|
27
27
|
def enqueue(queue_name, klass, hash)
|
@@ -66,7 +66,8 @@ module QueueBus
|
|
66
66
|
description: 'Enqueues a heart beat every minute for the queue-bus'
|
67
67
|
)
|
68
68
|
|
69
|
-
|
69
|
+
# If dynamic is enabled, this will propagate through a different mechanism
|
70
|
+
SidekiqScheduler::Scheduler.instance.reload_schedule! unless ::Sidekiq::Scheduler.instance.dynamic
|
70
71
|
end
|
71
72
|
end
|
72
73
|
end
|
data/lib/sidekiq_bus/version.rb
CHANGED
data/sidekiq-bus.gemspec
CHANGED
@@ -17,13 +17,11 @@ Gem::Specification.new do |s|
|
|
17
17
|
s.require_paths = ["lib"]
|
18
18
|
|
19
19
|
s.add_dependency('queue-bus', ['>= 0.7', '< 1'])
|
20
|
-
s.add_dependency('
|
21
|
-
s.add_dependency('
|
22
|
-
s.add_dependency('sidekiq-scheduler', ['>=
|
20
|
+
s.add_dependency('redis', ['>= 4.0', '< 6.0'])
|
21
|
+
s.add_dependency('sidekiq', ['>= 7.0.0', '< 8.0'])
|
22
|
+
s.add_dependency('sidekiq-scheduler', ['>= 5.0', '< 6.0'])
|
23
23
|
|
24
24
|
s.add_development_dependency("rspec")
|
25
|
-
s.add_development_dependency("fakeredis")
|
26
|
-
s.add_development_dependency("redis-namespace")
|
27
25
|
s.add_development_dependency("pry")
|
28
26
|
s.add_development_dependency("timecop")
|
29
27
|
s.add_development_dependency("json_pure")
|
@@ -87,17 +87,14 @@ describe 'Sidekiq Integration' do
|
|
87
87
|
val = QueueBus.redis { |redis| redis.lpop('queue:bus_incoming') }
|
88
88
|
expect(val).to eq(nil) # nothing really added
|
89
89
|
|
90
|
-
|
91
|
-
# since the Poller invokes a Lua script that FakeRedis does not
|
92
|
-
# natively support.
|
93
|
-
Sidekiq::Scheduled::Poller.new(Sidekiq).enqueue
|
90
|
+
Sidekiq::Scheduled::Poller.new(Sidekiq.default_configuration).enqueue
|
94
91
|
|
95
92
|
val = QueueBus.redis { |redis| redis.lpop('queue:bus_incoming') }
|
96
93
|
expect(val).to eq(nil) # nothing added yet
|
97
94
|
|
98
95
|
# process scheduler in future
|
99
96
|
Timecop.freeze(worktime) do
|
100
|
-
Sidekiq::Scheduled::Poller.new(Sidekiq).enqueue
|
97
|
+
Sidekiq::Scheduled::Poller.new(Sidekiq.default_configuration).enqueue
|
101
98
|
|
102
99
|
val = QueueBus.redis { |redis| redis.lpop('queue:bus_incoming') }
|
103
100
|
hash = JSON.parse(val)
|
data/spec/adapter_spec.rb
CHANGED
@@ -19,11 +19,11 @@ describe 'adapter is set' do
|
|
19
19
|
|
20
20
|
around do |example|
|
21
21
|
begin
|
22
|
-
old = Sidekiq.
|
23
|
-
Sidekiq.
|
22
|
+
old = Sidekiq.default_configuration[:lifecycle_events][:startup]
|
23
|
+
Sidekiq.default_configuration[:lifecycle_events][:startup] = []
|
24
24
|
example.run
|
25
25
|
ensure
|
26
|
-
Sidekiq.
|
26
|
+
Sidekiq.default_configuration[:lifecycle_events][:startup] = old
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
@@ -65,7 +65,7 @@ describe 'adapter is set' do
|
|
65
65
|
allow(Sidekiq::Scheduler.instance).to receive(:dynamic).and_return(true)
|
66
66
|
|
67
67
|
# Simulate running startup events
|
68
|
-
Sidekiq.
|
68
|
+
Sidekiq.default_configuration[:lifecycle_events][:startup].each(&:call)
|
69
69
|
end
|
70
70
|
|
71
71
|
it_behaves_like 'a scheduled heartbeat'
|
@@ -76,7 +76,7 @@ describe 'adapter is set' do
|
|
76
76
|
allow(Sidekiq::Scheduler.instance).to receive(:dynamic).and_return(false)
|
77
77
|
|
78
78
|
# Simulate running startup events
|
79
|
-
Sidekiq.
|
79
|
+
Sidekiq.default_configuration[:lifecycle_events][:startup].each(&:call)
|
80
80
|
end
|
81
81
|
|
82
82
|
it_behaves_like 'a scheduled heartbeat'
|
data/spec/spec_helper.rb
CHANGED
@@ -4,11 +4,40 @@ require 'timecop'
|
|
4
4
|
require 'queue-bus'
|
5
5
|
require 'adapter/support'
|
6
6
|
require 'pry'
|
7
|
+
require 'redis'
|
8
|
+
|
9
|
+
# Require some private Sidekiq APIs to simulate internal scheduling behavior
|
10
|
+
require "sidekiq/capsule"
|
7
11
|
|
8
12
|
reset_test_adapter
|
9
13
|
|
10
|
-
|
11
|
-
|
14
|
+
# Use real Redis for testing to ensure compatibility with Sidekiq's Lua scripts
|
15
|
+
redis_url = ENV.fetch('REDIS_URL', 'redis://localhost:6379/15')
|
16
|
+
|
17
|
+
# Check Redis connection before running tests
|
18
|
+
begin
|
19
|
+
test_redis = Redis.new(url: redis_url)
|
20
|
+
test_redis.ping
|
21
|
+
test_redis.disconnect!
|
22
|
+
rescue Redis::CannotConnectError, Errno::ECONNREFUSED => e
|
23
|
+
puts "\n❌ Redis connection failed!"
|
24
|
+
puts " URL: #{redis_url}"
|
25
|
+
puts " Error: #{e.message}"
|
26
|
+
puts "\n💡 To fix this:"
|
27
|
+
puts " • Start Redis with Docker: docker-compose up -d redis"
|
28
|
+
puts " • Or start Redis locally: redis-server"
|
29
|
+
puts " • Or set REDIS_URL environment variable to a running Redis instance"
|
30
|
+
puts "\n"
|
31
|
+
exit 1
|
32
|
+
rescue => e
|
33
|
+
puts "\n❌ Unexpected error connecting to Redis:"
|
34
|
+
puts " #{e.class}: #{e.message}"
|
35
|
+
puts "\n"
|
36
|
+
exit 1
|
37
|
+
end
|
38
|
+
|
39
|
+
redis_pool = ConnectionPool.new { Redis.new(url: redis_url) }
|
40
|
+
SidekiqBus.redis_handler = redis_pool.method(:with).to_proc
|
12
41
|
|
13
42
|
require 'fileutils'
|
14
43
|
|
@@ -19,9 +48,18 @@ FileUtils.touch(log_file)
|
|
19
48
|
|
20
49
|
logger = Logger.new(File.open(log_file, 'a'))
|
21
50
|
|
22
|
-
Sidekiq.logger = logger
|
23
51
|
QueueBus.logger = logger
|
24
52
|
|
53
|
+
Sidekiq.configure_server do |config|
|
54
|
+
config.redis = { url: redis_url }
|
55
|
+
config.logger = logger
|
56
|
+
end
|
57
|
+
|
58
|
+
Sidekiq.configure_client do |config|
|
59
|
+
config.redis = { url: redis_url }
|
60
|
+
config.logger = logger
|
61
|
+
end
|
62
|
+
|
25
63
|
require 'sidekiq/testing'
|
26
64
|
|
27
65
|
module QueueBus
|
@@ -53,38 +91,6 @@ module QueueBus
|
|
53
91
|
end
|
54
92
|
end
|
55
93
|
|
56
|
-
class Redis
|
57
|
-
module Connection
|
58
|
-
class Memory
|
59
|
-
def script(*args)
|
60
|
-
case args[1]
|
61
|
-
when Sidekiq::Scheduled::Enq::LUA_ZPOPBYSCORE
|
62
|
-
QueueBus.redis do |redis|
|
63
|
-
now = Time.now.to_f
|
64
|
-
|
65
|
-
# Process both 'schedule' and 'retry' sets
|
66
|
-
%w[schedule retry].each do |set_name|
|
67
|
-
# Get jobs that are ready to be processed (score <= now)
|
68
|
-
jobs = redis.zrangebyscore(set_name, '-inf', now)
|
69
|
-
|
70
|
-
jobs.each do |job_json|
|
71
|
-
# Remove from scheduled set
|
72
|
-
redis.zrem(set_name, job_json)
|
73
|
-
|
74
|
-
# Parse and re-enqueue the job
|
75
|
-
job_data = JSON.parse(job_json)
|
76
|
-
queue_name = job_data['queue'] || 'default'
|
77
|
-
redis.lpush("queue:#{queue_name}", job_json)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
else
|
82
|
-
raise "NOSCRIPT - FakeRedis gem does not include Lua support. Please see spec/spec_helper.rb for more information."
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
94
|
|
89
95
|
def test_sub(event_name, queue = 'default')
|
90
96
|
matcher = { 'bus_event_type' => event_name }
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sidekiq-bus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian Leonard
|
@@ -30,59 +30,65 @@ dependencies:
|
|
30
30
|
- !ruby/object:Gem::Version
|
31
31
|
version: '1'
|
32
32
|
- !ruby/object:Gem::Dependency
|
33
|
-
name:
|
33
|
+
name: redis
|
34
34
|
requirement: !ruby/object:Gem::Requirement
|
35
35
|
requirements:
|
36
36
|
- - ">="
|
37
37
|
- !ruby/object:Gem::Version
|
38
|
-
version:
|
38
|
+
version: '4.0'
|
39
39
|
- - "<"
|
40
40
|
- !ruby/object:Gem::Version
|
41
|
-
version: '
|
41
|
+
version: '6.0'
|
42
42
|
type: :runtime
|
43
43
|
prerelease: false
|
44
44
|
version_requirements: !ruby/object:Gem::Requirement
|
45
45
|
requirements:
|
46
46
|
- - ">="
|
47
47
|
- !ruby/object:Gem::Version
|
48
|
-
version:
|
48
|
+
version: '4.0'
|
49
49
|
- - "<"
|
50
50
|
- !ruby/object:Gem::Version
|
51
|
-
version: '
|
51
|
+
version: '6.0'
|
52
52
|
- !ruby/object:Gem::Dependency
|
53
|
-
name:
|
53
|
+
name: sidekiq
|
54
54
|
requirement: !ruby/object:Gem::Requirement
|
55
55
|
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: 7.0.0
|
56
59
|
- - "<"
|
57
60
|
- !ruby/object:Gem::Version
|
58
|
-
version: '
|
61
|
+
version: '8.0'
|
59
62
|
type: :runtime
|
60
63
|
prerelease: false
|
61
64
|
version_requirements: !ruby/object:Gem::Requirement
|
62
65
|
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 7.0.0
|
63
69
|
- - "<"
|
64
70
|
- !ruby/object:Gem::Version
|
65
|
-
version: '
|
71
|
+
version: '8.0'
|
66
72
|
- !ruby/object:Gem::Dependency
|
67
73
|
name: sidekiq-scheduler
|
68
74
|
requirement: !ruby/object:Gem::Requirement
|
69
75
|
requirements:
|
70
76
|
- - ">="
|
71
77
|
- !ruby/object:Gem::Version
|
72
|
-
version: '
|
78
|
+
version: '5.0'
|
73
79
|
- - "<"
|
74
80
|
- !ruby/object:Gem::Version
|
75
|
-
version: '
|
81
|
+
version: '6.0'
|
76
82
|
type: :runtime
|
77
83
|
prerelease: false
|
78
84
|
version_requirements: !ruby/object:Gem::Requirement
|
79
85
|
requirements:
|
80
86
|
- - ">="
|
81
87
|
- !ruby/object:Gem::Version
|
82
|
-
version: '
|
88
|
+
version: '5.0'
|
83
89
|
- - "<"
|
84
90
|
- !ruby/object:Gem::Version
|
85
|
-
version: '
|
91
|
+
version: '6.0'
|
86
92
|
- !ruby/object:Gem::Dependency
|
87
93
|
name: rspec
|
88
94
|
requirement: !ruby/object:Gem::Requirement
|
@@ -97,34 +103,6 @@ dependencies:
|
|
97
103
|
- - ">="
|
98
104
|
- !ruby/object:Gem::Version
|
99
105
|
version: '0'
|
100
|
-
- !ruby/object:Gem::Dependency
|
101
|
-
name: fakeredis
|
102
|
-
requirement: !ruby/object:Gem::Requirement
|
103
|
-
requirements:
|
104
|
-
- - ">="
|
105
|
-
- !ruby/object:Gem::Version
|
106
|
-
version: '0'
|
107
|
-
type: :development
|
108
|
-
prerelease: false
|
109
|
-
version_requirements: !ruby/object:Gem::Requirement
|
110
|
-
requirements:
|
111
|
-
- - ">="
|
112
|
-
- !ruby/object:Gem::Version
|
113
|
-
version: '0'
|
114
|
-
- !ruby/object:Gem::Dependency
|
115
|
-
name: redis-namespace
|
116
|
-
requirement: !ruby/object:Gem::Requirement
|
117
|
-
requirements:
|
118
|
-
- - ">="
|
119
|
-
- !ruby/object:Gem::Version
|
120
|
-
version: '0'
|
121
|
-
type: :development
|
122
|
-
prerelease: false
|
123
|
-
version_requirements: !ruby/object:Gem::Requirement
|
124
|
-
requirements:
|
125
|
-
- - ">="
|
126
|
-
- !ruby/object:Gem::Version
|
127
|
-
version: '0'
|
128
106
|
- !ruby/object:Gem::Dependency
|
129
107
|
name: pry
|
130
108
|
requirement: !ruby/object:Gem::Requirement
|
@@ -200,6 +178,7 @@ files:
|
|
200
178
|
- MIT-LICENSE
|
201
179
|
- README.mdown
|
202
180
|
- Rakefile
|
181
|
+
- docker-compose.yml
|
203
182
|
- lib/sidekiq-bus.rb
|
204
183
|
- lib/sidekiq_bus/adapter.rb
|
205
184
|
- lib/sidekiq_bus/middleware/retry.rb
|