queue-bus 0.11.0 → 0.13.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 139511a2de01b9ffb7e58b63ecf62cbc01ae94fe38896282de2ae0dbb13178de
4
- data.tar.gz: 0e481639105b4dceff9991ee448f378923fdb3ae5820294f954602e96a177243
3
+ metadata.gz: 48a236d7a44dafb099dc3d36e5f34e4a1f065d47fa76b3be1a7465ae8533773b
4
+ data.tar.gz: c2e6cffeba50ae36e13c8c417f43c7b9f18ff09772c4fd3ffd48e2784a80d5d9
5
5
  SHA512:
6
- metadata.gz: 3ce3ebbeee0e6be7513af1ed093f5612877a6293a78bad68da502817c10f205ddf69bbc3071ef497f48baef2e66f2823311ef80e579805dbeedccec9b0794bef
7
- data.tar.gz: 8b93e84ff4b5d6801d6b490560af46532c729eb7ff2b32b0d88e565bd620388d029f1a010027b9032e56731aef936945922bf7afc642453aeb9db9cbeacd0bcd
6
+ metadata.gz: 7c3ba54737925161ec4c658864a7badd08f58400e246f31ee31a2aef7a6347005f073f62c2a3874aaf4e64f11a3da7f0a2fff322997e0a99da9b7901079e320a
7
+ data.tar.gz: 26b7011be9db57d5f2c93f397fda77374f8aa34fa097efc93d3831ce1832a3c1e12913433e507cf2c8e5c1057178e71b08a3fdbcee68fe382597b8bd3828f603
data/CHANGELOG.md CHANGED
@@ -6,6 +6,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.13.2]
10
+
11
+ ### Fixes
12
+
13
+ - Properly passes the attributes down to the subscription when using `on_heartbeat`
14
+
15
+ ## [0.13.1]
16
+
17
+ ### Fixes
18
+
19
+ - Allows matching on 0 via the `on_heartbeat` subscription
20
+
21
+ ### Added
22
+
23
+ - Allows matching on `wday` via the `on_heartbeat` subscription
24
+
25
+ ## [0.13.0]
26
+
27
+ ### Added
28
+
29
+ - Adds `Dispatch#on_heartbeat` which is a helper function for specifying heartbeat subscriptions.
30
+
31
+ ## [0.12.0]
32
+
33
+ ### Changed
34
+ - Pipelines fetching all queue subscriptions when using `QueueBus::Application.all`
35
+
9
36
  ## [0.11.0]
10
37
 
11
38
  ### Added
data/README.mdown CHANGED
@@ -63,6 +63,16 @@ QueueBus.dispatch("app_b") do
63
63
  subscribe "my_key", { "user_id" => :present, "page" => "homepage"} do
64
64
  Mixpanel.homepage_action!(attributes["action"])
65
65
  end
66
+
67
+ # You may also declare a subscription to heartbeat events. This is a helper function
68
+ # that works along with subscribe to make scheduling regular events easier.
69
+ #
70
+ # minute_interval: Executes every n minutes
71
+ # hour_interval: Executes every n hours
72
+ # minute: Executes on this minute
73
+ # hour: Executes on this hour
74
+ on_heartbeat "my_heartbeat_event", minute_interval: 5 do |attributes|
75
+ end
66
76
  end
67
77
  ```
68
78
 
@@ -7,7 +7,22 @@ module QueueBus
7
7
  class << self
8
8
  def all
9
9
  # note the names arent the same as we started with
10
- ::QueueBus.redis { |redis| redis.smembers(app_list_key).collect { |val| new(val) } }
10
+ ::QueueBus.redis do |redis|
11
+ app_keys = redis.smembers(app_list_key)
12
+ apps = app_keys.collect { |val| new(val) }
13
+
14
+ hashes = redis.pipelined do
15
+ apps.each do |app|
16
+ redis.hgetall(app.redis_key)
17
+ end
18
+ end
19
+
20
+ apps.zip(hashes).each do |app, hash|
21
+ app._hydrate_redis_hash(hash)
22
+ end
23
+
24
+ apps
25
+ end
11
26
  end
12
27
  end
13
28
 
@@ -90,6 +105,10 @@ module QueueBus
90
105
  out
91
106
  end
92
107
 
108
+ def _hydrate_redis_hash(hash)
109
+ @raw_redis_hash = hash
110
+ end
111
+
93
112
  protected
94
113
 
95
114
  def self.normalize(val)
@@ -114,16 +133,24 @@ module QueueBus
114
133
 
115
134
  def read_redis_hash
116
135
  out = {}
117
- ::QueueBus.redis do |redis|
118
- redis.hgetall(redis_key).each do |key, val|
119
- begin
120
- out[key] = ::QueueBus::Util.decode(val)
121
- rescue ::QueueBus::Util::DecodeException
122
- out[key] = val
123
- end
136
+ raw_redis_hash.each do |key, val|
137
+ begin
138
+ out[key] = ::QueueBus::Util.decode(val)
139
+ rescue ::QueueBus::Util::DecodeException
140
+ out[key] = val
124
141
  end
125
142
  end
126
143
  out
127
144
  end
145
+
146
+ private
147
+
148
+ def raw_redis_hash
149
+ return @raw_redis_hash if @raw_redis_hash
150
+
151
+ ::QueueBus.redis do |redis|
152
+ redis.hgetall(redis_key)
153
+ end
154
+ end
128
155
  end
129
156
  end
@@ -16,6 +16,45 @@ module QueueBus
16
16
  @subscriptions.size
17
17
  end
18
18
 
19
+ def on_heartbeat(key, minute: nil, hour: nil, wday: nil, minute_interval: nil, hour_interval: nil, &block) # rubocop:disable Metrics/PerceivedComplexity, Metrics/MethodLength, Metrics/ParameterLists, Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/LineLength
20
+ if minute_interval && !minute_interval.positive?
21
+ raise ArgumentError, 'minute_interval must be a positive integer'
22
+ end
23
+
24
+ if hour_interval && !hour_interval.positive?
25
+ raise ArgumentError, 'hour_interval must be a positive integer'
26
+ end
27
+
28
+ matcher = { bus_event_type: :heartbeat_minutes }
29
+
30
+ if minute
31
+ raise ArgumentError, 'minute must not be negative' if minute.negative?
32
+
33
+ matcher['minute'] = minute
34
+ end
35
+
36
+ if hour
37
+ raise ArgumentError, 'hour must not be negative' if hour.negative?
38
+
39
+ matcher['hour'] = hour
40
+ end
41
+
42
+ if wday
43
+ raise ArgumentError, 'wday must not be negative' if wday.negative?
44
+
45
+ matcher['wday'] = wday
46
+ end
47
+
48
+ subscribe(key, matcher) do |event|
49
+ if (minute_interval.nil? || (event['minute'] % minute_interval).zero?) &&
50
+ (hour_interval.nil? || (event['hour'] % hour_interval).zero?)
51
+
52
+ # Yield the block passed in.
53
+ block.call(event)
54
+ end
55
+ end
56
+ end
57
+
19
58
  def subscribe(key, matcher_hash = nil, &block)
20
59
  dispatch_event('default', key, matcher_hash, block)
21
60
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module QueueBus
4
- VERSION = '0.11.0'
4
+ VERSION = '0.13.2'
5
5
  end
@@ -28,6 +28,160 @@ module QueueBus
28
28
  end.not_to raise_error
29
29
  end
30
30
 
31
+ describe '#on_heartbeat' do
32
+ let(:dispatch) { Dispatch.new('heartbeat') }
33
+ let(:event) { { bus_event_type: :heartbeat_minutes } }
34
+ let(:event_name) { 'my-event' }
35
+
36
+ it 'passes on the event' do
37
+ dispatch.on_heartbeat event_name do |event|
38
+ expect(event).to match hash_including('hour' => 1, 'minute' => 0)
39
+ end
40
+
41
+ dispatch.execute(event_name, 'hour' => 1, 'minute' => 0)
42
+ end
43
+
44
+ context 'when not declaring anything' do
45
+ before do
46
+ dispatch.on_heartbeat event_name do |_event|
47
+ Runner2.run({})
48
+ end
49
+ end
50
+
51
+ it 'runs on every heart beat' do
52
+ (0..24).each do |hour|
53
+ (0..60).each do |minute|
54
+ expect do
55
+ dispatch.execute(
56
+ event_name, event.merge('hour' => hour, 'minute' => minute)
57
+ )
58
+ end.to change(Runner2, :value).by(1)
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ context 'when running on hour 8' do
65
+ before do
66
+ dispatch.on_heartbeat event_name, hour: 8 do |_event|
67
+ Runner2.run({})
68
+ end
69
+ end
70
+
71
+ it 'subscribes to hour 8' do
72
+ expect(dispatch.subscriptions.all.first.matcher.filters)
73
+ .to eq('bus_event_type' => 'heartbeat_minutes', 'hour' => '8')
74
+ end
75
+ end
76
+
77
+ context 'when running on minute 4' do
78
+ before do
79
+ dispatch.on_heartbeat event_name, minute: 4 do |_event|
80
+ Runner2.run({})
81
+ end
82
+ end
83
+
84
+ it 'subscribes to minute 4' do
85
+ expect(dispatch.subscriptions.all.first.matcher.filters)
86
+ .to eq('bus_event_type' => 'heartbeat_minutes', 'minute' => '4')
87
+ end
88
+ end
89
+
90
+ context 'when running on minute 4 and hour 8' do
91
+ before do
92
+ dispatch.on_heartbeat event_name, hour: 8, minute: 4 do |_event|
93
+ Runner2.run({})
94
+ end
95
+ end
96
+
97
+ it 'subscribes to minute 4 and hour 8' do
98
+ expect(dispatch.subscriptions.all.first.matcher.filters)
99
+ .to eq('bus_event_type' => 'heartbeat_minutes', 'minute' => '4', 'hour' => '8')
100
+ end
101
+ end
102
+
103
+ context 'when running on wday 2' do
104
+ before do
105
+ dispatch.on_heartbeat event_name, wday: 2 do |_event|
106
+ Runner2.run({})
107
+ end
108
+ end
109
+
110
+ it 'subscribes to wday 2' do
111
+ expect(dispatch.subscriptions.all.first.matcher.filters)
112
+ .to eq('bus_event_type' => 'heartbeat_minutes', 'wday' => '2')
113
+ end
114
+ end
115
+
116
+ context 'when declaring minute intervals' do
117
+ before do
118
+ dispatch.on_heartbeat event_name, minute_interval: 5 do |_event|
119
+ Runner2.run({})
120
+ end
121
+ end
122
+
123
+ it 'runs the runner when the minute buzzes (modulos to 5)' do
124
+ (0..60).each do |minute|
125
+ if minute % 5 == 0
126
+ expect { dispatch.execute(event_name, event.merge('minute' => minute)) }
127
+ .to change(Runner2, :value).by(1)
128
+ else
129
+ expect { dispatch.execute(event_name, event.merge('minute' => minute)) }
130
+ .not_to change(Runner2, :value)
131
+ end
132
+ end
133
+ end
134
+ end
135
+
136
+ context 'when declaring hour intervals' do
137
+ before do
138
+ dispatch.on_heartbeat event_name, hour_interval: 3 do |_event|
139
+ Runner2.run({})
140
+ end
141
+ end
142
+
143
+ it 'runs the runner when the hour fizzes (modulos to 3)' do
144
+ (0..60).each do |hour|
145
+ if hour % 3 == 0
146
+ expect { dispatch.execute(event_name, event.merge('hour' => hour)) }
147
+ .to change(Runner2, :value).by(1)
148
+ else
149
+ expect { dispatch.execute(event_name, event.merge('hour' => hour)) }
150
+ .not_to change(Runner2, :value)
151
+ end
152
+ end
153
+ end
154
+ end
155
+
156
+ context 'when declaring hour and minute intervals' do
157
+ before do
158
+ dispatch.on_heartbeat event_name, minute_interval: 5, hour_interval: 3 do |_event|
159
+ Runner2.run({})
160
+ end
161
+ end
162
+
163
+ it 'runs the runner when the time fizzbuzzes (modulos to 3 and 5)' do
164
+ (0..24).each do |hour|
165
+ (0..60).each do |minute|
166
+ if hour % 3 == 0 && minute % 5 == 0
167
+ expect do
168
+ dispatch.execute(
169
+ event_name, event.merge('hour' => hour, 'minute' => minute)
170
+ )
171
+ end.to change(Runner2, :value).by(1)
172
+ else
173
+ expect do
174
+ dispatch.execute(
175
+ event_name, event.merge('hour' => hour, 'minute' => minute)
176
+ )
177
+ end.not_to change(Runner2, :value)
178
+ end
179
+ end
180
+ end
181
+ end
182
+ end
183
+ end
184
+
31
185
  describe 'Top Level' do
32
186
  before(:each) do
33
187
  QueueBus.dispatch('testit') do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: queue-bus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.0
4
+ version: 0.13.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Leonard
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-06-16 00:00:00.000000000 Z
11
+ date: 2021-11-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: multi_json
@@ -159,7 +159,7 @@ files:
159
159
  homepage: ''
160
160
  licenses: []
161
161
  metadata: {}
162
- post_install_message:
162
+ post_install_message:
163
163
  rdoc_options: []
164
164
  require_paths:
165
165
  - lib
@@ -174,9 +174,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
174
174
  - !ruby/object:Gem::Version
175
175
  version: '0'
176
176
  requirements: []
177
- rubyforge_project: queue-bus
178
- rubygems_version: 2.7.6.2
179
- signing_key:
177
+ rubygems_version: 3.0.3
178
+ signing_key:
180
179
  specification_version: 4
181
180
  summary: A simple event bus on top of background queues
182
181
  test_files: