Skip to content

Commit 436d355

Browse files
authored
Use positional event job args (#274)
1 parent dd29feb commit 436d355

File tree

4 files changed

+91
-63
lines changed

4 files changed

+91
-63
lines changed

app/jobs/event_created_job.rb

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
class EventCreatedJob
22
include Sidekiq::Job
33

4-
def self.perform_async(*args)
5-
can_handle?(type: args[0]["type"]) ? super : nil
4+
def self.perform_async(event_id, event_type)
5+
can_handle?(event_type: event_type) ? super : nil
66
end
77

8-
def perform(args)
9-
job_class_name = to_job_class_name(type: args["type"])
8+
def perform(event_id, event_type)
9+
job_class_name = to_job_class_name(event_type: event_type)
1010

1111
if job_class_name.nil?
12-
Sidekiq.logger.debug("Could not get job class name from event type: #{args["type"]}")
12+
Sidekiq.logger.debug("Could not get job class name from event type: #{event_type}")
1313

1414
return
1515
end
@@ -22,16 +22,16 @@ def perform(args)
2222
return
2323
end
2424

25-
job_class.perform_async(args["id"])
25+
job_class.perform_async(event_id, event_type)
2626
end
2727

2828
TYPE_REGEX = /\A(::)?([A-Z][\w]*::)*[A-Z][\w]*Event\z/
2929

30-
def to_job_class_name(type:)
31-
self.class.can_handle?(type: type) ? type.sub(/Event\z/, "Job") : nil
30+
def to_job_class_name(event_type:)
31+
self.class.can_handle?(event_type: event_type) ? event_type.sub(/Event\z/, "Job") : nil
3232
end
3333

34-
def self.can_handle?(type:)
34+
def self.can_handle?(event_type:)
3535
# \A => start of string
3636
# (::)? => optional leading ::
3737
# ([A-Z]\w*::)* => zero or more namespace segments like Foo:: or FooBar::
@@ -52,6 +52,6 @@ def self.can_handle?(type:)
5252
# ✘ 123::InvalidEvent # starts with digit
5353
# ✘ Foo:: # incomplete constant
5454

55-
/\A(::)?([A-Z][\w]*::)*[A-Z][\w]*Event\z/.match?(type)
55+
/\A(::)?([A-Z][\w]*::)*[A-Z][\w]*Event\z/.match?(event_type)
5656
end
5757
end

app/jobs/outboxer_integration/test_started_job.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ module OutboxerIntegration
22
class TestStartedJob
33
include Sidekiq::Job
44

5-
def perform(event_id)
6-
test_started_event = TestStartedEvent.find(event_id)
5+
def perform(event_id, event_type)
6+
test_started_event = event_type.safe_constantize.find(event_id)
77

88
TestCompletedEvent.create!(body: { "test_id" => test_started_event.body["test_id"] })
99
end

bin/outboxer_publisher

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,7 @@ begin
3434
heartbeat: options[:heartbeat],
3535
logger: logger
3636
) do |message|
37-
if EventCreatedJob.can_handle?(type: message[:messageable_type])
38-
EventCreatedJob.perform_async({
39-
"id" => message[:messageable_id],
40-
"type" => message[:messageable_type]
41-
})
42-
end
37+
EventCreatedJob.perform_async(message[:messageable_id], message[:messageable_type])
4338
end
4439
ensure
4540
Outboxer::Database.disconnect(logger: logger)

spec/jobs/event_created_job_spec.rb

Lines changed: 78 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -12,32 +12,38 @@
1212
it "enqueues ContactCreatedJob" do
1313
stub_const("ContactCreatedJob", Class.new { include Sidekiq::Job })
1414

15-
EventCreatedJob.new.perform({ "id" => 1, "type" => "ContactCreatedEvent" })
15+
EventCreatedJob.new.perform(1, "ContactCreatedEvent")
1616

1717
expect(ContactCreatedJob.jobs).to match([
18-
hash_including("class" => "ContactCreatedJob", "args" => [1])
18+
hash_including(
19+
"class" => "ContactCreatedJob",
20+
"args" => [1, "ContactCreatedEvent"])
1921
])
2022
end
2123

2224
it "enqueues Accountify::ContactCreatedJob" do
2325
stub_const("Accountify", Module.new)
2426
stub_const("Accountify::ContactCreatedJob", Class.new { include Sidekiq::Job })
2527

26-
EventCreatedJob.new.perform({ "id" => 2, "type" => "Accountify::ContactCreatedEvent" })
28+
EventCreatedJob.new.perform(2, "Accountify::ContactCreatedEvent")
2729

2830
expect(Accountify::ContactCreatedJob.jobs).to match([
29-
hash_including("class" => "Accountify::ContactCreatedJob", "args" => [2])
31+
hash_including(
32+
"class" => "Accountify::ContactCreatedJob",
33+
"args" => [2, "Accountify::ContactCreatedEvent"])
3034
])
3135
end
3236

3337
it "enqueues Accountify::InvoiceUpdatedJob" do
3438
stub_const("Accountify", Module.new) unless defined?(Accountify)
3539
stub_const("Accountify::InvoiceUpdatedJob", Class.new { include Sidekiq::Job })
3640

37-
EventCreatedJob.new.perform({ "id" => 3, "type" => "Accountify::InvoiceUpdatedEvent" })
41+
EventCreatedJob.new.perform(3, "Accountify::InvoiceUpdatedEvent")
3842

3943
expect(Accountify::InvoiceUpdatedJob.jobs).to match([
40-
hash_including("class" => "Accountify::InvoiceUpdatedJob", "args" => [3])
44+
hash_including(
45+
"class" => "Accountify::InvoiceUpdatedJob",
46+
"args" => [3, "Accountify::InvoiceUpdatedEvent"])
4147
])
4248
end
4349

@@ -46,79 +52,87 @@
4652
stub_const("Accountify::Invoice", Module.new)
4753
stub_const("Accountify::Invoice::CreatedJob", Class.new { include Sidekiq::Job })
4854

49-
EventCreatedJob.new.perform({ "id" => 4, "type" => "Accountify::Invoice::CreatedEvent" })
55+
EventCreatedJob.new.perform(4, "Accountify::Invoice::CreatedEvent")
5056

5157
expect(Accountify::Invoice::CreatedJob.jobs).to match([
52-
hash_including("class" => "Accountify::Invoice::CreatedJob", "args" => [4])
58+
hash_including(
59+
"class" => "Accountify::Invoice::CreatedJob",
60+
"args" => [4, "Accountify::Invoice::CreatedEvent"])
5361
])
5462
end
5563

5664
it "enqueues MyApp::Domain::Event::UserSignedUpJob" do
5765
stub_const("MyApp", Module.new)
5866
stub_const("MyApp::Domain", Module.new)
5967
stub_const("MyApp::Domain::Event", Module.new)
60-
stub_const("MyApp::Domain::Event::UserSignedUpJob", Class.new { include Sidekiq::Job })
68+
stub_const("MyApp::Domain::Event::UserSignedUpJob",
69+
Class.new { include Sidekiq::Job })
6170

6271
EventCreatedJob.new.perform(
63-
{ "id" => 5, "type" => "MyApp::Domain::Event::UserSignedUpEvent" })
72+
5,
73+
"MyApp::Domain::Event::UserSignedUpEvent")
6474

6575
expect(MyApp::Domain::Event::UserSignedUpJob.jobs).to match([
66-
hash_including("class" => "MyApp::Domain::Event::UserSignedUpJob", "args" => [5])
76+
hash_including(
77+
"class" => "MyApp::Domain::Event::UserSignedUpJob",
78+
"args" => [5, "MyApp::Domain::Event::UserSignedUpEvent"])
6779
])
6880
end
6981

7082
it "handles leading :: in type" do
7183
stub_const("ContactCreatedJob", Class.new { include Sidekiq::Job })
7284

73-
EventCreatedJob.new.perform({ "id" => 6, "type" => "::ContactCreatedEvent" })
85+
EventCreatedJob.new.perform(6, "::ContactCreatedEvent")
7486

7587
expect(ContactCreatedJob.jobs).to match([
76-
hash_including("class" => "ContactCreatedJob", "args" => [6])
88+
hash_including(
89+
"class" => "ContactCreatedJob",
90+
"args" => [6, "::ContactCreatedEvent"])
7791
])
7892
end
7993

8094
it "does not enqueue for invalid type format" do
81-
EventCreatedJob.new.perform({ "id" => 7, "type" => "contact_created_event" })
95+
EventCreatedJob.new.perform(7, "contact_created_event")
8296
expect(Sidekiq::Worker.jobs.size).to eq(0)
8397
end
8498

8599
it "does not enqueue for empty string" do
86-
EventCreatedJob.new.perform({ "id" => 8, "type" => "" })
100+
EventCreatedJob.new.perform(8, "")
87101
expect(Sidekiq::Worker.jobs.size).to eq(0)
88102
end
89103

90104
it "does not enqueue if type does not end in Event" do
91-
EventCreatedJob.new.perform({ "id" => 9, "type" => "SomethingCreated" })
105+
EventCreatedJob.new.perform(9, "SomethingCreated")
92106
expect(Sidekiq::Worker.jobs.size).to eq(0)
93107
end
94108

95109
it "does not enqueue for missing job class" do
96-
EventCreatedJob.new.perform({ "id" => 10, "type" => "ImaginaryThingEvent" })
110+
EventCreatedJob.new.perform(10, "ImaginaryThingEvent")
97111
expect(Sidekiq::Worker.jobs.size).to eq(0)
98112
end
99113

100114
it "does not enqueue for invalid type constant path" do
101-
EventCreatedJob.new.perform({ "id" => 11, "type" => "123::@@@Invalid" })
115+
EventCreatedJob.new.perform(11, "123::@@@Invalid")
102116
expect(Sidekiq::Worker.jobs.size).to eq(0)
103117
end
104118

105119
it "does not enqueue if type is exactly 'Event'" do
106-
EventCreatedJob.new.perform({ "id" => 12, "type" => "Event" })
120+
EventCreatedJob.new.perform(12, "Event")
107121
expect(Sidekiq::Worker.jobs.size).to eq(0)
108122
end
109123

110124
it "logs debug message when type is invalid" do
111125
expect(Sidekiq.logger).to receive(:debug).with(
112126
"Could not get job class name from event type: bad_type")
113127

114-
EventCreatedJob.new.perform({ "id" => 13, "type" => "bad_type" })
128+
EventCreatedJob.new.perform(13, "bad_type")
115129
end
116130

117131
it "logs debug message when job class name is not constantizable" do
118132
expect(Sidekiq.logger).to receive(:debug).with(
119133
"Could not constantize job class name: ImaginaryThingJob")
120134

121-
EventCreatedJob.new.perform({ "id" => 14, "type" => "ImaginaryThingEvent" })
135+
EventCreatedJob.new.perform(14, "ImaginaryThingEvent")
122136
end
123137
end
124138

@@ -128,35 +142,41 @@
128142
it "enqueues ContactCreatedJob through perform_async" do
129143
stub_const("ContactCreatedJob", Class.new { include Sidekiq::Job })
130144

131-
EventCreatedJob.perform_async({ "id" => 1, "type" => "ContactCreatedEvent" })
145+
EventCreatedJob.perform_async(1, "ContactCreatedEvent")
132146
EventCreatedJob.drain
133147

134148
expect(ContactCreatedJob.jobs).to match([
135-
hash_including("class" => "ContactCreatedJob", "args" => [1])
149+
hash_including(
150+
"class" => "ContactCreatedJob",
151+
"args" => [1, "ContactCreatedEvent"])
136152
])
137153
end
138154

139155
it "enqueues Accountify::ContactCreatedJob through perform_async" do
140156
stub_const("Accountify", Module.new)
141157
stub_const("Accountify::ContactCreatedJob", Class.new { include Sidekiq::Job })
142158

143-
EventCreatedJob.perform_async({ "id" => 2, "type" => "Accountify::ContactCreatedEvent" })
159+
EventCreatedJob.perform_async(2, "Accountify::ContactCreatedEvent")
144160
EventCreatedJob.drain
145161

146162
expect(Accountify::ContactCreatedJob.jobs).to match([
147-
hash_including("class" => "Accountify::ContactCreatedJob", "args" => [2])
163+
hash_including(
164+
"class" => "Accountify::ContactCreatedJob",
165+
"args" => [2, "Accountify::ContactCreatedEvent"])
148166
])
149167
end
150168

151169
it "enqueues Accountify::InvoiceUpdatedJob through perform_async" do
152170
stub_const("Accountify", Module.new) unless defined?(Accountify)
153171
stub_const("Accountify::InvoiceUpdatedJob", Class.new { include Sidekiq::Job })
154172

155-
EventCreatedJob.perform_async({ "id" => 3, "type" => "Accountify::InvoiceUpdatedEvent" })
173+
EventCreatedJob.perform_async(3, "Accountify::InvoiceUpdatedEvent")
156174
EventCreatedJob.drain
157175

158176
expect(Accountify::InvoiceUpdatedJob.jobs).to match([
159-
hash_including("class" => "Accountify::InvoiceUpdatedJob", "args" => [3])
177+
hash_including(
178+
"class" => "Accountify::InvoiceUpdatedJob",
179+
"args" => [3, "Accountify::InvoiceUpdatedEvent"])
160180
])
161181
end
162182

@@ -165,91 +185,104 @@
165185
stub_const("Accountify::Invoice", Module.new)
166186
stub_const("Accountify::Invoice::CreatedJob", Class.new { include Sidekiq::Job })
167187

168-
EventCreatedJob.perform_async({ "id" => 4, "type" => "Accountify::Invoice::CreatedEvent" })
188+
EventCreatedJob.perform_async(4, "Accountify::Invoice::CreatedEvent")
169189
EventCreatedJob.drain
170190

171191
expect(Accountify::Invoice::CreatedJob.jobs).to match([
172-
hash_including("class" => "Accountify::Invoice::CreatedJob", "args" => [4])
192+
hash_including(
193+
"class" => "Accountify::Invoice::CreatedJob",
194+
"args" => [4, "Accountify::Invoice::CreatedEvent"])
173195
])
174196
end
175197

176198
it "enqueues MyApp::Domain::Event::UserSignedUpJob through perform_async" do
177199
stub_const("MyApp", Module.new)
178200
stub_const("MyApp::Domain", Module.new)
179201
stub_const("MyApp::Domain::Event", Module.new)
180-
stub_const("MyApp::Domain::Event::UserSignedUpJob", Class.new { include Sidekiq::Job })
202+
stub_const("MyApp::Domain::Event::UserSignedUpJob",
203+
Class.new { include Sidekiq::Job })
181204

182-
EventCreatedJob.perform_async({
183-
"id" => 5,
184-
"type" => "MyApp::Domain::Event::UserSignedUpEvent"
185-
})
205+
EventCreatedJob.perform_async(
206+
5,
207+
"MyApp::Domain::Event::UserSignedUpEvent")
186208
EventCreatedJob.drain
187209

188210
expect(MyApp::Domain::Event::UserSignedUpJob.jobs).to match([
189-
hash_including("class" => "MyApp::Domain::Event::UserSignedUpJob", "args" => [5])
211+
hash_including(
212+
"class" => "MyApp::Domain::Event::UserSignedUpJob",
213+
"args" => [5, "MyApp::Domain::Event::UserSignedUpEvent"])
190214
])
191215
end
192216

193217
it "handles leading :: in type through perform_async" do
194218
stub_const("ContactCreatedJob", Class.new { include Sidekiq::Job })
195219

196-
EventCreatedJob.perform_async({ "id" => 6, "type" => "::ContactCreatedEvent" })
220+
EventCreatedJob.perform_async(6, "::ContactCreatedEvent")
197221
EventCreatedJob.drain
198222

199223
expect(ContactCreatedJob.jobs).to match([
200-
hash_including("class" => "ContactCreatedJob", "args" => [6])
224+
hash_including(
225+
"class" => "ContactCreatedJob",
226+
"args" => [6, "::ContactCreatedEvent"])
201227
])
202228
end
203229

204230
it "does not enqueue job for invalid type format" do
205231
expect do
206-
EventCreatedJob.perform_async({ "id" => 7, "type" => "contact_created_event" })
232+
EventCreatedJob.perform_async(7, "contact_created_event")
207233
end.not_to change(EventCreatedJob.jobs, :size)
208234
end
209235

210236
it "does not enqueue job for empty string" do
211237
expect do
212-
EventCreatedJob.perform_async({ "id" => 8, "type" => "" })
238+
EventCreatedJob.perform_async(8, "")
213239
end.not_to change(EventCreatedJob.jobs, :size)
214240
end
215241

216242
it "does not enqueue job if type does not end in Event" do
217243
expect do
218-
EventCreatedJob.perform_async({ "id" => 9, "type" => "SomethingCreated" })
244+
EventCreatedJob.perform_async(9, "SomethingCreated")
219245
end.not_to change(EventCreatedJob.jobs, :size)
220246
end
221247

222248
it "skips perform_async for missing job class" do
223-
EventCreatedJob.perform_async({ "id" => 10, "type" => "ImaginaryThingEvent" })
249+
EventCreatedJob.perform_async(10, "ImaginaryThingEvent")
224250
EventCreatedJob.drain
225251

226252
expect(Sidekiq::Worker.jobs.size).to eq(0)
227253
end
228254

229255
it "skips perform_async for invalid constant path" do
230-
EventCreatedJob.perform_async({ "id" => 11, "type" => "123::@@@Invalid" })
256+
EventCreatedJob.perform_async(11, "123::@@@Invalid")
231257
EventCreatedJob.drain
232258

233259
expect(Sidekiq::Worker.jobs.size).to eq(0)
234260
end
235261

236262
it "skips perform_async if type is exactly 'Event'" do
237-
EventCreatedJob.perform_async({ "id" => 12, "type" => "Event" })
263+
EventCreatedJob.perform_async(12, "Event")
238264
EventCreatedJob.drain
239265

240266
expect(Sidekiq::Worker.jobs.size).to eq(0)
241267
end
242268

243269
it "returns nil for invalid type" do
244-
result = EventCreatedJob.perform_async({ "id" => 13, "type" => "bad_type" })
270+
result = EventCreatedJob.perform_async(13, "bad_type")
245271
expect(result).to be_nil
246272
end
247273

248274
it "returns job ID when enqueued" do
249275
stub_const("ContactCreatedJob", Class.new { include Sidekiq::Job })
250276

251-
result = EventCreatedJob.perform_async({ "id" => 14, "type" => "ContactCreatedEvent" })
277+
result = EventCreatedJob.perform_async(14, "ContactCreatedEvent")
278+
EventCreatedJob.drain
279+
252280
expect(result).to be_a(String)
281+
expect(ContactCreatedJob.jobs).to match([
282+
hash_including(
283+
"class" => "ContactCreatedJob",
284+
"args" => [14, "ContactCreatedEvent"])
285+
])
253286
end
254287
end
255288
end

0 commit comments

Comments
 (0)