outboxable 1.0.0 → 1.0.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: 6289db937af7c6072908dce5da1a44a5145c9a4065bcd3705f847ea39e6c7c57
4
- data.tar.gz: 89a5d2581f353528fd78e0c19443163d625d2981fa443b5db99a31554001e93d
3
+ metadata.gz: 7ff24c145223dcc558818028a2866583266372e1a52cbb0dc63661fdad5f94ea
4
+ data.tar.gz: 64e19fa685b3f77a85c10bc60f9754a32bbe8534b9aaa5cb153253aefb5bbcb1
5
5
  SHA512:
6
- metadata.gz: dcefad48f356f8d18e44ac7431464f3b1687505fa6241e4d472ad67f215a00e0b5d0da5f690b028aae34c97564d60c5db1c331a37151b02c69d5b60823c029e9
7
- data.tar.gz: 810dd5e03320ddc4812e5f15db86521fe3e29f4dc69bb92d64dbff822cceddccb71c25e99573edf8cf6d191aa8992d58e7a8fd144a28598def81b63e6614c567
6
+ metadata.gz: 9dca7a575abbc63e9b033e3726229ce8abe6254ea049f220f66c9b675c4395efbfdac1a12da0dc5c31f50a65bfdab939ee23809c24d9e2182864fdd0b703754f
7
+ data.tar.gz: 6673eabf79e2daa9b36bd93c84589dc68f796a22c8b82cf93d035cd9eaaa1b3ba523ee16c9c121c719befe9b1527b3bf32a6c2467ee023b9bfd527b209575ef3
data/Gemfile.lock CHANGED
@@ -1,10 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- outboxable (1.0.0)
4
+ outboxable (1.0.2)
5
5
  bunny (>= 2.19.0)
6
6
  connection_pool (~> 2.3.0)
7
- simple_enum (>= 2.3)
8
7
 
9
8
  GEM
10
9
  remote: https://rubygems.org/
@@ -85,8 +84,6 @@ GEM
85
84
  fugit (~> 1.8)
86
85
  globalid (>= 1.0.1)
87
86
  sidekiq (>= 6)
88
- simple_enum (2.3.2)
89
- activesupport (>= 4.0.0)
90
87
  sorted_set (1.0.3)
91
88
  rbtree
92
89
  set (~> 1.0)
@@ -5,8 +5,8 @@ module Outboxable
5
5
  source_root File.expand_path('../../templates', __dir__)
6
6
  class_option :orm, type: :string, default: 'activerecord'
7
7
 
8
- def initialize
9
- super
8
+ def initialize(*)
9
+ super(*)
10
10
 
11
11
  @orm = options[:orm] || 'activerecord'
12
12
  %w[activerecord mongoid].include?(@orm) || raise(ArgumentError, 'Invalid ORM. Only ActiveRecord and Mongoid are supported.')
@@ -6,6 +6,12 @@ module Outboxable
6
6
  def self.configure
7
7
  self.configuration ||= Configuration.new
8
8
  yield(configuration)
9
+
10
+ # In accordance to sidekiq-cron README: https://github.com/sidekiq-cron/sidekiq-cron#under-the-hood
11
+ Sidekiq::Options[:cron_poll_interval] = 5
12
+
13
+ # Create the cron job for the polling publisher
14
+ Sidekiq::Cron::Job.create(name: 'OutboxablePollingPublisher', cron: '*/5 * * * * *', class: 'Outboxable::PollingPublisherWorker', args: [{ orm: configuration.orm }])
9
15
  end
10
16
 
11
17
  class Configuration
@@ -26,12 +32,6 @@ module Outboxable
26
32
  raise Error, 'Outboxable Gem only supports Rails but you application does not seem to be a Rails app' unless Object.const_defined?('Rails')
27
33
  raise Error, 'Outboxable Gem only support Rails version 7 and newer' if Rails::VERSION::MAJOR < 7
28
34
  raise Error, 'Outboxable Gem uses the sidekiq-cron Gem. Make sure you add it to your project' unless Object.const_defined?('Sidekiq::Cron')
29
-
30
- # In accordance to sidekiq-cron README: https://github.com/sidekiq-cron/sidekiq-cron#under-the-hood
31
- Sidekiq::Options[:cron_poll_interval] = 5
32
-
33
- # Create the cron job for the polling publisher
34
- Sidekiq::Cron::Job.create(name: 'OutboxablePollingPublisher', cron: '*/5 * * * * *', class: 'Outboxable::PollingPublisherWorker')
35
35
  end
36
36
 
37
37
  def message_broker=(message_broker)
@@ -3,24 +3,25 @@ module Outboxable
3
3
  include Sidekiq::Job
4
4
  sidekiq_options queue: 'critical'
5
5
 
6
- def perform
7
- Outboxable.configuration.orm == :mongoid ? perform_mongoid : perform_activerecord
6
+ def perform(args)
7
+ orm = args['orm']
8
+ orm == 'mongoid' ? perform_mongoid(orm) : perform_activerecord(orm)
8
9
  end
9
10
 
10
- def perform_activerecord
11
+ def perform_activerecord(orm)
11
12
  Outbox.pending.where(last_attempted_at: [..Time.zone.now, nil]).find_in_batches(batch_size: 100).each do |batch|
12
13
  batch.each do |outbox|
13
14
  # This is to prevent a job from being retried too many times. Worst-case scenario is 1 minute delay in jobs.
14
- Outboxable::Worker.perform_async(outbox.id)
15
+ Outboxable::Worker.perform_async(outbox.id, orm)
15
16
  outbox.update(last_attempted_at: 1.minute.from_now, status: :processing, allow_publish: false)
16
17
  end
17
18
  end
18
19
  end
19
20
 
20
- def perform_mongoid
21
+ def perform_mongoid(orm)
21
22
  Outbox.pending.where(last_attempted_at: [..Time.zone.now, nil]).each do |outbox|
22
23
  # This is to prevent a job from being retried too many times. Worst-case scenario is 1 minute delay in jobs.
23
- Outboxable::Worker.perform_async(outbox.id)
24
+ Outboxable::Worker.perform_async(outbox.idempotency_key, orm)
24
25
  outbox.update(last_attempted_at: 1.minute.from_now, status: :processing, allow_publish: false)
25
26
  end
26
27
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Outboxable
4
- VERSION = '1.0.0'
4
+ VERSION = '1.0.2'
5
5
  end
@@ -4,8 +4,9 @@ module Outboxable
4
4
  class Worker
5
5
  include ::Sidekiq::Job
6
6
 
7
- def perform(outbox_id)
8
- Outboxable::PublishingManager.publish(resource: Outbox.find(outbox_id))
7
+ def perform(outbox_id, orm)
8
+ Outboxable::PublishingManager.publish(resource: Outbox.find(outbox_id)) if orm == 'activerecord'
9
+ Outboxable::PublishingManager.publish(resource: Outbox.find_by!(idempotency_key: outbox_id)) if orm == 'mongoid'
9
10
  end
10
11
  end
11
12
  end
@@ -4,7 +4,7 @@ class Outbox < ApplicationRecord
4
4
  before_save :check_publishing
5
5
  # Callbacks
6
6
  before_create :set_last_attempted_at
7
- after_commit :publish, if: :allow_publish?
7
+ after_save :publish, if: :allow_publish
8
8
  # Enums
9
9
  enum status: { pending: 0, processing: 1, published: 2, failed: 3 }
10
10
  enum size: { single: 0, batch: 1 }
@@ -1,5 +1,3 @@
1
- require 'simple_enum/mongoid'
2
-
3
1
  # This monkey patch allows you to customize the message format that you publish to your broker.
4
2
  # By default, Outboxable publishes a CloudEvent message to your broker.
5
3
  module Outboxable
@@ -1,13 +1,12 @@
1
1
  class Outbox
2
2
  include Mongoid::Document
3
3
  include Mongoid::Timestamps
4
- include SimpleEnum::Mongoid
5
4
 
6
- attr_accessor :allow_publish
5
+ attr_writer :allow_publish
7
6
 
8
7
  # Fields
9
8
  field :status, type: String, default: 'pending'
10
- field :size, type: String, default: 'single'
9
+ field :size, type: String, default: 'single'
11
10
 
12
11
  field :exchange, type: String, default: ''
13
12
  field :routing_key, type: String, default: ''
@@ -18,18 +17,19 @@ class Outbox
18
17
 
19
18
  field :retry_at, type: DateTime, default: nil
20
19
 
20
+ field :idempotency_key, type: String
21
+
21
22
  field :payload, type: Hash, default: {}
22
23
  field :headers, type: Hash, default: {}
23
24
 
25
+ index({ idempotency_key: 1 }, { unique: true, name: 'idempotency_key_unique_index' })
26
+
24
27
  before_save :check_publishing
28
+ before_create :set_idempotency_key
25
29
 
26
30
  # Callbacks
27
31
  before_create :set_last_attempted_at
28
- after_commit :publish, if: :allow_publish?
29
-
30
- # Enums
31
- as_enum :status, { pending: 0, processing: 1, published: 2, failed: 3 }, pluralize_scopes: false, map: :string
32
- as_enum :size, { single: 0, batch: 1 }, pluralize_scopes: false, map: :string
32
+ after_save :publish, if: :allow_publish
33
33
 
34
34
  # Validations
35
35
  validates :payload, :exchange, :routing_key, presence: true
@@ -42,15 +42,30 @@ class Outbox
42
42
  end
43
43
 
44
44
  def publish
45
- Outboxable::Worker.perform_async(id)
45
+ Outboxable::Worker.perform_async(idempotency_key)
46
46
  update(status: :processing, last_attempted_at: 1.minute.from_now, allow_publish: false)
47
47
  end
48
48
 
49
+ def set_idempotency_key
50
+ self.idempotency_key = SecureRandom.uuid if idempotency_key.blank?
51
+ end
52
+
49
53
  def check_publishing
50
54
  self.allow_publish = false if published?
51
55
  end
52
56
 
53
57
  def allow_publish
54
- @allow_publish || true
58
+ return true if @allow_publish.nil?
59
+
60
+ @allow_publish
61
+ end
62
+
63
+ %w[pending processing published failed].each do |status|
64
+ define_method "#{status}?" do
65
+ self.status == status
66
+ end
67
+
68
+ # define scope
69
+ scope status, -> { where(status:) }
55
70
  end
56
71
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: outboxable
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brusk Awat
@@ -38,20 +38,6 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: 2.3.0
41
- - !ruby/object:Gem::Dependency
42
- name: simple_enum
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '2.3'
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '2.3'
55
41
  description: The Outboxable Gem is tailored for Rails applications to implement the
56
42
  transactional outbox pattern. It currently only supports ActiveRecord.
57
43
  email:
@@ -81,7 +67,7 @@ files:
81
67
  - lib/templates/activerecord_initializer.rb
82
68
  - lib/templates/activerecrod_outbox.rb
83
69
  - lib/templates/create_outboxable_outboxes.rb
84
- - lib/templates/mongoid_initializer..rb
70
+ - lib/templates/mongoid_initializer.rb
85
71
  - lib/templates/mongoid_outbox.rb
86
72
  - sig/outboxable.rbs
87
73
  homepage: https://github.com/broosk1993/outboxable