queue-bus 0.11.0 → 0.13.2

Sign up to get free protection for your applications and to get access to all the features.
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: