railbox 0.1.0 → 0.1.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 +4 -4
- data/lib/generators/railbox/install/templates/migration.rb.tt +21 -0
- data/lib/railbox/handler/handler.rb +8 -0
- data/lib/railbox/models/transactional_outbox.rb +6 -0
- data/lib/railbox/mutators/transactional_outbox_mutator.rb +1 -1
- data/lib/railbox/processors/handler_processor.rb +23 -6
- data/lib/railbox/processors/http_processor.rb +4 -1
- data/lib/railbox/workers/process_queue_worker.rb +20 -13
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9bee1e734460ab0bc5d07c19cf133c1a46bde8e0e943b7a5e50a480d5fdce24f
|
|
4
|
+
data.tar.gz: 40b7b8f3e1c3ac79447dc56d0eb682ea58a2c82205481f6f13656319a6955803
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2c2b6dbde97ef2814a83b5b75149c9e7e0e0f43d1180aff131bf6b37cce3f6be6ded8f4d9257a5792ab93ad528602ec2525802180c75f302710e36fa2ef960c7
|
|
7
|
+
data.tar.gz: e5f8c61ec2fbd84a48301dd84bc608621a10a4ce493cd453c0a90b396dfb37914e81c709543d093ea4792f885f2bc809752869f08ddd2c186800990060e5c0f8
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
class CreateTransactionalOutbox < ActiveRecord::Migration[7.0]
|
|
2
|
+
def change
|
|
3
|
+
create_table :transactional_outboxes do |t|
|
|
4
|
+
t.string :action_type, null: false
|
|
5
|
+
t.jsonb :action_data, null: false, default: {}
|
|
6
|
+
t.string :status, null: false
|
|
7
|
+
t.string :entity_type
|
|
8
|
+
t.integer :entity_id
|
|
9
|
+
t.jsonb :query, default: {}
|
|
10
|
+
t.jsonb :body, default: {}
|
|
11
|
+
t.jsonb :headers, default: {}
|
|
12
|
+
t.jsonb :meta, default: {}
|
|
13
|
+
t.integer :attempts, default: 0
|
|
14
|
+
t.datetime :retry_at
|
|
15
|
+
t.jsonb :failure_reasons, array: true, default: []
|
|
16
|
+
t.timestamps
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
add_index :transactional_outboxes, [:entity_type, :entity_id]
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -28,6 +28,14 @@ module Railbox
|
|
|
28
28
|
def enqueue(method: 'create', body: {}, **opts)
|
|
29
29
|
HandlingQueue.enqueue(service: name, method: method, body: body, **opts)
|
|
30
30
|
end
|
|
31
|
+
|
|
32
|
+
# Base failure hook:
|
|
33
|
+
# - can be safely called even if not overridden in the service;
|
|
34
|
+
# - does nothing by default;
|
|
35
|
+
# - when overridden, has access to `outbox_entity`.
|
|
36
|
+
def on_failure
|
|
37
|
+
# no-op by default
|
|
38
|
+
end
|
|
31
39
|
end
|
|
32
40
|
end
|
|
33
41
|
end
|
|
@@ -32,6 +32,12 @@ module Railbox
|
|
|
32
32
|
class TransactionalOutbox < ::ActiveRecord::Base
|
|
33
33
|
belongs_to :relative_entity, polymorphic: true, foreign_key: :entity_id, foreign_type: :entity_type
|
|
34
34
|
|
|
35
|
+
enum :status, {in_progress: 'in_progress', failed: 'failed', completed: 'completed'}
|
|
36
|
+
|
|
37
|
+
def action_data
|
|
38
|
+
super&.deep_symbolize_keys || {}
|
|
39
|
+
end
|
|
40
|
+
|
|
35
41
|
def in_group?
|
|
36
42
|
group.present? || entity_group.present?
|
|
37
43
|
end
|
|
@@ -1,17 +1,34 @@
|
|
|
1
1
|
module Railbox
|
|
2
2
|
module Processors
|
|
3
3
|
class HandlerProcessor
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
4
6
|
class << self
|
|
5
7
|
|
|
6
8
|
def process(record)
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
with_handler(record) do |handler, action_data|
|
|
10
|
+
handler.public_send(action_data[:method_name])
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def on_failure(record)
|
|
15
|
+
with_handler(record) do |handler, _action_data|
|
|
16
|
+
handler.on_failure
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
11
21
|
|
|
12
|
-
|
|
22
|
+
def with_handler(record)
|
|
23
|
+
interface = Railbox::TransactionalOutboxInterface.new(record)
|
|
24
|
+
action_data = record.action_data
|
|
25
|
+
handler = Object.const_get(action_data[:class_name])
|
|
26
|
+
|
|
27
|
+
handler.outbox_entity = interface
|
|
13
28
|
|
|
14
|
-
handler
|
|
29
|
+
yield(handler, action_data)
|
|
30
|
+
ensure
|
|
31
|
+
handler.outbox_entity = nil if handler
|
|
15
32
|
end
|
|
16
33
|
end
|
|
17
34
|
end
|
|
@@ -4,7 +4,7 @@ module Railbox
|
|
|
4
4
|
class << self
|
|
5
5
|
|
|
6
6
|
def process(record)
|
|
7
|
-
action_data = record.action_data
|
|
7
|
+
action_data = record.action_data
|
|
8
8
|
|
|
9
9
|
Railbox::HttpClient::Faraday.request(action_data[:method_name],
|
|
10
10
|
action_data[:url],
|
|
@@ -12,6 +12,9 @@ module Railbox
|
|
|
12
12
|
record.body,
|
|
13
13
|
record.headers)
|
|
14
14
|
end
|
|
15
|
+
|
|
16
|
+
def on_failure(record)
|
|
17
|
+
end
|
|
15
18
|
end
|
|
16
19
|
end
|
|
17
20
|
end
|
|
@@ -12,11 +12,7 @@ module Railbox
|
|
|
12
12
|
group.each do |record|
|
|
13
13
|
process_record(record)
|
|
14
14
|
rescue => e
|
|
15
|
-
|
|
16
|
-
raise e if record.in_group? || record.action_type == 'handler'
|
|
17
|
-
|
|
18
|
-
Rails.logger.error("RailboxWorker error: #{e.message}\n #{e.backtrace&.take(3)&.join("\n")}")
|
|
19
|
-
|
|
15
|
+
on_failure(e, record)
|
|
20
16
|
next
|
|
21
17
|
end
|
|
22
18
|
rescue => e
|
|
@@ -71,23 +67,34 @@ module Railbox
|
|
|
71
67
|
all_group_records = scope.order(:created_at).to_a
|
|
72
68
|
|
|
73
69
|
group_records if all_group_records.first&.id.in?(group_records.map(&:id))
|
|
74
|
-
end.
|
|
70
|
+
end.compact_blank
|
|
75
71
|
end
|
|
76
72
|
|
|
77
73
|
def process_record(record)
|
|
78
74
|
Rails.logger.info("Start process with transactional outbox ID #{record.id}")
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
if processor
|
|
82
|
-
processor.process(record)
|
|
83
|
-
else
|
|
84
|
-
raise Railbox::QueueError, "Unknown action_type=#{record.action_type} for outbox #{record.id}"
|
|
85
|
-
end
|
|
75
|
+
take_processor(record).process(record)
|
|
86
76
|
|
|
87
77
|
TransactionalOutboxMutator.update(record, {status: 'completed'})
|
|
88
78
|
|
|
89
79
|
Rails.logger.info("Finish process with transactional outbox ID #{record.id}")
|
|
90
80
|
end
|
|
81
|
+
|
|
82
|
+
def on_failure(error, record)
|
|
83
|
+
record = TransactionalOutboxMutator.update(record, {failure_reasons: record.failure_reasons << {message: error.message, backtrace: error.backtrace&.take(3), at: DateTime.current}})
|
|
84
|
+
take_processor(record).on_failure(record) if record.failed?
|
|
85
|
+
|
|
86
|
+
raise error if record.in_group? || record.action_type == 'handler'
|
|
87
|
+
|
|
88
|
+
Rails.logger.error("RailboxWorker error: #{error.message}\n #{error.backtrace&.take(3)&.join("\n")}")
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def take_processor(record)
|
|
92
|
+
processor = PROCESSORS[record.action_type]
|
|
93
|
+
|
|
94
|
+
raise Railbox::QueueError, "Unknown action_type=#{record.action_type} for outbox #{record.id}" unless processor
|
|
95
|
+
|
|
96
|
+
processor
|
|
97
|
+
end
|
|
91
98
|
end
|
|
92
99
|
end
|
|
93
100
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: railbox
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Egor Beresnev
|
|
@@ -158,6 +158,7 @@ extensions: []
|
|
|
158
158
|
extra_rdoc_files: []
|
|
159
159
|
files:
|
|
160
160
|
- lib/generators/railbox/install/install_generator.rb
|
|
161
|
+
- lib/generators/railbox/install/templates/migration.rb.tt
|
|
161
162
|
- lib/railbox.rb
|
|
162
163
|
- lib/railbox/exceptions/queue_error.rb
|
|
163
164
|
- lib/railbox/exceptions/validation_error.rb
|