outboxable 1.0.0 → 1.0.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: 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