journaled 2.1.1 → 2.5.0

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: 3b7a10c3a016b77101958c098880bfcfab640b8277e93d80962a90fd6255c6c8
4
- data.tar.gz: 54d9bfb3d13c97c2a40c6be9a9854ce3120671ae06fd9c9c251f766abd822215
3
+ metadata.gz: 895598e96b01aad6c51bd55355c5d7d0fab963b97326c2943bcb76450dd7cdb7
4
+ data.tar.gz: 61073882361fbb34ca243d8cc4dbedb494f798bcaaf2bde124f820eb8e175439
5
5
  SHA512:
6
- metadata.gz: d3bed9db0a770ee95a10309d673ec7b7e3f3d8f7da59303d27bb17ce6e3920e9913e4a34e553fe9e4a99a395f16810c4784844e0161e78292c8383b00b55a9a5
7
- data.tar.gz: 930ed61334d18351879b66ac8d36768e0cc0a9d982e1482c40fb313431f9c38ab624f1ad3f6c2797ca76e0c35b69f66a8051fc9e322a36661cacecb6e1d46a76
6
+ metadata.gz: 4564bc7e637fc2d032ee00b1f2b9e21282d65a531ae758ac374f863b1964100c3ea755db1e558c43d3503a74b995ffc310bb6343f255591357bf4d7ffe556e54
7
+ data.tar.gz: b456385727f88392465553ff9c63f313902536a9a13cae00fae011e40c7afb2490f3f5ff5fb1012346c18cedfb5cfabcbd20ed2dcaf1cd039dc27551d756647c
data/README.md CHANGED
@@ -88,6 +88,29 @@ Journaling provides a number of different configuation options that can be set i
88
88
  This can be used to configure what `priority` the Delayed Jobs are enqueued with. This will be applied to all the Journaled::Devivery jobs that are created by this application.
89
89
  Ex: `Journaled.job_priority = 14`
90
90
 
91
+ #### `Journaled.http_idle_timeout` (default: 1 second)
92
+
93
+ The number of seconds a persistent connection is allowed to sit idle before it should no longer be used.
94
+
95
+ #### `Journaled.http_open_timeout` (default: 2 seconds)
96
+
97
+ The number of seconds before the :http_handler should timeout while trying to open a new HTTP session.
98
+
99
+ #### `Journaled.http_read_timeout` (default: 60 seconds)
100
+
101
+ The number of seconds before the :http_handler should timeout while waiting for a HTTP response.
102
+
103
+ #### DJ `enqueue` options
104
+
105
+ Both model-level directives accept additional options to be passed into DelayedJob's `enqueue` method:
106
+
107
+ ```ruby
108
+ # For change journaling:
109
+ journal_changes_to :email, as: :identity_change, enqueue_with: { priority: 10 }
110
+
111
+ # Or for custom journaling:
112
+ journal_attributes :email, enqueue_with: { priority: 20, queue: 'journaled' }
113
+ ```
91
114
 
92
115
  ### Change Journaling
93
116
 
@@ -12,6 +12,7 @@ module Journaled::Actor
12
12
  class_methods do
13
13
  def journaled_actor=(method_name)
14
14
  raise "Must provide a symbol method name" unless method_name.is_a?(Symbol)
15
+
15
16
  self._journaled_actor_method_name = method_name
16
17
  end
17
18
  end
@@ -2,10 +2,9 @@ module Journaled::Changes
2
2
  extend ActiveSupport::Concern
3
3
 
4
4
  included do
5
- cattr_accessor :_journaled_change_definitions
6
- cattr_accessor :journaled_attribute_names
7
- self._journaled_change_definitions = []
8
- self.journaled_attribute_names = []
5
+ cattr_accessor(:_journaled_change_definitions) { [] }
6
+ cattr_accessor(:journaled_attribute_names) { [] }
7
+ cattr_accessor(:journaled_enqueue_opts, instance_writer: false) { {} }
9
8
 
10
9
  after_create do
11
10
  self.class._journaled_change_definitions.each do |definition|
@@ -57,7 +56,7 @@ module Journaled::Changes
57
56
  end
58
57
 
59
58
  class_methods do
60
- def journal_changes_to(*attribute_names, as:) # rubocop:disable Naming/UncommunicativeMethodParamName
59
+ def journal_changes_to(*attribute_names, as:, enqueue_with: {}) # rubocop:disable Naming/UncommunicativeMethodParamName
61
60
  if attribute_names.empty? || attribute_names.any? { |n| !n.is_a?(Symbol) }
62
61
  raise "one or more symbol attribute_name arguments is required"
63
62
  end
@@ -66,6 +65,7 @@ module Journaled::Changes
66
65
 
67
66
  _journaled_change_definitions << Journaled::ChangeDefinition.new(attribute_names: attribute_names, logical_operation: as)
68
67
  journaled_attribute_names.concat(attribute_names)
68
+ journaled_enqueue_opts.merge!(enqueue_with)
69
69
  end
70
70
 
71
71
  if Rails::VERSION::MAJOR > 5 || (Rails::VERSION::MAJOR == 5 && Rails::VERSION::MINOR >= 2)
@@ -7,6 +7,7 @@ class Journaled::Change
7
7
  :logical_operation,
8
8
  :changes,
9
9
  :journaled_app_name,
10
+ :journaled_enqueue_opts,
10
11
  :actor
11
12
 
12
13
  journal_attributes :table_name,
@@ -16,12 +17,13 @@ class Journaled::Change
16
17
  :changes,
17
18
  :actor
18
19
 
19
- def initialize(table_name:, # rubocop:disable Metrics/ParameterLists
20
+ def initialize(table_name:,
20
21
  record_id:,
21
22
  database_operation:,
22
23
  logical_operation:,
23
24
  changes:,
24
25
  journaled_app_name:,
26
+ journaled_enqueue_opts:,
25
27
  actor:)
26
28
  @table_name = table_name
27
29
  @record_id = record_id
@@ -29,6 +31,7 @@ class Journaled::Change
29
31
  @logical_operation = logical_operation
30
32
  @changes = changes
31
33
  @journaled_app_name = journaled_app_name
34
+ @journaled_enqueue_opts = journaled_enqueue_opts
32
35
  @actor = actor
33
36
  end
34
37
  end
@@ -19,6 +19,7 @@ class Journaled::ChangeDefinition
19
19
 
20
20
  #{nonexistent_attribute_names.join(', ')}
21
21
  ERROR
22
+
22
23
  @validated = true
23
24
  end
24
25
  end
@@ -28,7 +28,8 @@ class Journaled::ChangeWriter
28
28
  logical_operation: logical_operation,
29
29
  changes: JSON.dump(changes),
30
30
  journaled_app_name: journaled_app_name,
31
- actor: actor_uri
31
+ journaled_enqueue_opts: model.journaled_enqueue_opts,
32
+ actor: actor_uri,
32
33
  )
33
34
  end
34
35
 
@@ -1,4 +1,4 @@
1
- class Journaled::Delivery
1
+ class Journaled::Delivery # rubocop:disable Betterment/ActiveJobPerformable
2
2
  DEFAULT_REGION = 'us-east-1'.freeze
3
3
 
4
4
  def initialize(serialized_event:, partition_key:, app_name:)
@@ -25,7 +25,10 @@ class Journaled::Delivery
25
25
  def kinesis_client_config
26
26
  {
27
27
  region: ENV.fetch('AWS_DEFAULT_REGION', DEFAULT_REGION),
28
- retry_limit: 0
28
+ retry_limit: 0,
29
+ http_idle_timeout: Journaled.http_idle_timeout,
30
+ http_open_timeout: Journaled.http_open_timeout,
31
+ http_read_timeout: Journaled.http_read_timeout,
29
32
  }.merge(credentials)
30
33
  end
31
34
 
@@ -37,7 +40,7 @@ class Journaled::Delivery
37
40
  {
38
41
  stream_name: stream_name,
39
42
  data: serialized_event,
40
- partition_key: partition_key
43
+ partition_key: partition_key,
41
44
  }
42
45
  end
43
46
 
@@ -48,7 +51,7 @@ class Journaled::Delivery
48
51
  def credentials
49
52
  if ENV.key?('JOURNALED_IAM_ROLE_ARN')
50
53
  {
51
- credentials: iam_assume_role_credentials
54
+ credentials: iam_assume_role_credentials,
52
55
  }
53
56
  else
54
57
  legacy_credentials_hash_if_present
@@ -59,7 +62,7 @@ class Journaled::Delivery
59
62
  if ENV.key?('RUBY_AWS_ACCESS_KEY_ID')
60
63
  {
61
64
  access_key_id: ENV.fetch('RUBY_AWS_ACCESS_KEY_ID'),
62
- secret_access_key: ENV.fetch('RUBY_AWS_SECRET_ACCESS_KEY')
65
+ secret_access_key: ENV.fetch('RUBY_AWS_SECRET_ACCESS_KEY'),
63
66
  }
64
67
  else
65
68
  {}
@@ -68,7 +71,7 @@ class Journaled::Delivery
68
71
 
69
72
  def sts_client
70
73
  Aws::STS::Client.new({
71
- region: ENV.fetch('AWS_DEFAULT_REGION', DEFAULT_REGION)
74
+ region: ENV.fetch('AWS_DEFAULT_REGION', DEFAULT_REGION),
72
75
  }.merge(legacy_credentials_hash_if_present))
73
76
  end
74
77
 
@@ -76,7 +79,7 @@ class Journaled::Delivery
76
79
  @iam_assume_role_credentials ||= Aws::AssumeRoleCredentials.new(
77
80
  client: sts_client,
78
81
  role_arn: ENV.fetch('JOURNALED_IAM_ROLE_ARN'),
79
- role_session_name: "JournaledAssumeRoleAccess"
82
+ role_session_name: "JournaledAssumeRoleAccess",
80
83
  )
81
84
  end
82
85
 
@@ -2,7 +2,7 @@ module Journaled::Event
2
2
  extend ActiveSupport::Concern
3
3
 
4
4
  def journal!
5
- Journaled::Writer.new(journaled_event: self, priority: Journaled.job_priority).journal!
5
+ Journaled::Writer.new(journaled_event: self).journal!
6
6
  end
7
7
 
8
8
  # Base attributes
@@ -42,8 +42,9 @@ module Journaled::Event
42
42
  private
43
43
 
44
44
  class_methods do
45
- def journal_attributes(*args)
45
+ def journal_attributes(*args, enqueue_with: {})
46
46
  journaled_attributes.concat(args)
47
+ journaled_enqueue_opts.merge!(enqueue_with)
47
48
  end
48
49
 
49
50
  def journaled_attributes
@@ -56,6 +57,8 @@ module Journaled::Event
56
57
  end
57
58
 
58
59
  included do
60
+ cattr_accessor(:journaled_enqueue_opts, instance_writer: false) { {} }
61
+
59
62
  journal_attributes :id, :event_type, :created_at
60
63
  end
61
64
  end
@@ -4,9 +4,10 @@ class Journaled::Writer
4
4
  journaled_partition_key
5
5
  journaled_attributes
6
6
  journaled_app_name
7
+ journaled_enqueue_opts
7
8
  ).freeze
8
9
 
9
- def initialize(journaled_event:, priority:)
10
+ def initialize(journaled_event:)
10
11
  raise "An enqueued event must respond to: #{EVENT_METHOD_NAMES.to_sentence}" unless respond_to_all?(journaled_event, EVENT_METHOD_NAMES)
11
12
 
12
13
  unless journaled_event.journaled_schema_name.present? &&
@@ -21,25 +22,24 @@ class Journaled::Writer
21
22
  end
22
23
 
23
24
  @journaled_event = journaled_event
24
- @priority = priority
25
25
  end
26
26
 
27
27
  def journal!
28
28
  base_event_json_schema_validator.validate! serialized_event
29
29
  json_schema_validator.validate! serialized_event
30
- Delayed::Job.enqueue journaled_delivery, priority: priority
30
+ Journaled.enqueue!(journaled_delivery, journaled_enqueue_opts)
31
31
  end
32
32
 
33
33
  private
34
34
 
35
- attr_reader :journaled_event, :priority
36
- delegate :journaled_schema_name, :journaled_attributes, :journaled_partition_key, :journaled_app_name, to: :journaled_event
35
+ attr_reader :journaled_event
36
+ delegate(*EVENT_METHOD_NAMES, to: :journaled_event)
37
37
 
38
38
  def journaled_delivery
39
39
  @journaled_delivery ||= Journaled::Delivery.new(
40
40
  serialized_event: serialized_event,
41
41
  partition_key: journaled_partition_key,
42
- app_name: journaled_app_name
42
+ app_name: journaled_app_name,
43
43
  )
44
44
  end
45
45
 
data/lib/journaled.rb CHANGED
@@ -1,14 +1,17 @@
1
- require "aws-sdk-resources"
1
+ require "aws-sdk-kinesis"
2
2
  require "delayed_job"
3
3
  require "json-schema"
4
4
  require "request_store"
5
5
 
6
6
  require "journaled/engine"
7
- require "journaled/job_priority"
7
+ require 'journaled/enqueue'
8
8
 
9
9
  module Journaled
10
10
  mattr_accessor :default_app_name
11
- mattr_accessor(:job_priority) { Journaled::JobPriority::EVENTUAL }
11
+ mattr_accessor(:job_priority) { 20 }
12
+ mattr_accessor(:http_idle_timeout) { 5 }
13
+ mattr_accessor(:http_open_timeout) { 2 }
14
+ mattr_accessor(:http_read_timeout) { 60 }
12
15
 
13
16
  def development_or_test?
14
17
  %w(development test).include?(Rails.env)
@@ -0,0 +1,13 @@
1
+ module Journaled
2
+ class << self
3
+ def enqueue!(*args)
4
+ delayed_job_enqueue(*args)
5
+ end
6
+
7
+ private
8
+
9
+ def delayed_job_enqueue(*args, **opts)
10
+ Delayed::Job.enqueue(*args, **opts.reverse_merge(priority: Journaled.job_priority))
11
+ end
12
+ end
13
+ end
@@ -1,5 +1,5 @@
1
1
  module Journaled::RelationChangeProtection
2
- def update_all(updates, force: false) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/PerceivedComplexity
2
+ def update_all(updates, force: false) # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity
3
3
  unless force || !@klass.respond_to?(:journaled_attribute_names) || @klass.journaled_attribute_names.empty?
4
4
  conflicting_journaled_attribute_names = if updates.is_a?(Hash)
5
5
  @klass.journaled_attribute_names & updates.keys.map(&:to_sym)
@@ -1,3 +1,3 @@
1
1
  module Journaled
2
- VERSION = "2.1.1".freeze
2
+ VERSION = "2.5.0".freeze
3
3
  end
@@ -3,49 +3,50 @@ require 'rails_helper'
3
3
  RSpec.describe Journaled do
4
4
  it "is enabled in production" do
5
5
  allow(Rails).to receive(:env).and_return("production")
6
- expect(Journaled).to be_enabled
6
+ expect(described_class).to be_enabled
7
7
  end
8
8
 
9
9
  it "is disabled in development" do
10
10
  allow(Rails).to receive(:env).and_return("development")
11
- expect(Journaled).not_to be_enabled
11
+ expect(described_class).not_to be_enabled
12
12
  end
13
13
 
14
14
  it "is disabled in test" do
15
15
  allow(Rails).to receive(:env).and_return("test")
16
- expect(Journaled).not_to be_enabled
16
+ expect(described_class).not_to be_enabled
17
17
  end
18
18
 
19
19
  it "is enabled in whatevs" do
20
20
  allow(Rails).to receive(:env).and_return("whatevs")
21
- expect(Journaled).to be_enabled
21
+ expect(described_class).to be_enabled
22
22
  end
23
23
 
24
24
  it "is enabled when explicitly enabled in development" do
25
25
  with_env(JOURNALED_ENABLED: true) do
26
26
  allow(Rails).to receive(:env).and_return("development")
27
- expect(Journaled).to be_enabled
27
+ expect(described_class).to be_enabled
28
28
  end
29
29
  end
30
30
 
31
31
  it "is disabled when explicitly disabled in production" do
32
32
  with_env(JOURNALED_ENABLED: false) do
33
33
  allow(Rails).to receive(:env).and_return("production")
34
- expect(Journaled).not_to be_enabled
34
+ expect(described_class).not_to be_enabled
35
35
  end
36
36
  end
37
37
 
38
38
  it "is disabled when explicitly disabled with empty string" do
39
39
  with_env(JOURNALED_ENABLED: '') do
40
40
  allow(Rails).to receive(:env).and_return("production")
41
- expect(Journaled).not_to be_enabled
41
+ expect(described_class).not_to be_enabled
42
42
  end
43
43
  end
44
44
 
45
45
  describe "#actor_uri" do
46
46
  it "delegates to ActorUriProvider" do
47
- allow(Journaled::ActorUriProvider).to receive(:instance).and_return(double(actor_uri: "my actor uri"))
48
- expect(Journaled.actor_uri).to eq "my actor uri"
47
+ allow(Journaled::ActorUriProvider).to receive(:instance)
48
+ .and_return(instance_double(Journaled::ActorUriProvider, actor_uri: "my actor uri"))
49
+ expect(described_class.actor_uri).to eq "my actor uri"
49
50
  end
50
51
  end
51
52
  end
@@ -17,6 +17,7 @@ RSpec.describe Journaled::Changes do
17
17
  def self.after_save(opts, &hook)
18
18
  # This is a back-door assertion to prevent regressions in the module's hook definition behavior
19
19
  raise "expected `unless: :saved_change_to_id?`" unless opts[:unless] == :saved_change_to_id?
20
+
20
21
  after_save_hooks << hook
21
22
  end
22
23
 
@@ -91,4 +92,15 @@ RSpec.describe Journaled::Changes do
91
92
  expect(change_writer).to have_received(:delete)
92
93
  expect(Journaled::ChangeWriter).to have_received(:new)
93
94
  end
95
+
96
+ context 'when DJ opts are provided' do
97
+ before do
98
+ klass.journal_changes_to :thing, as: :other_thing, enqueue_with: { asdf: 1, foo: 'bar' }
99
+ end
100
+
101
+ it 'sets them on the model' do
102
+ expect(klass.journaled_enqueue_opts).to eq(asdf: 1, foo: 'bar')
103
+ expect(klass.new.journaled_enqueue_opts).to eq(asdf: 1, foo: 'bar')
104
+ end
105
+ end
94
106
  end
@@ -11,12 +11,13 @@ RSpec.describe Journaled::ChangeWriter do
11
11
  "name" => "bob",
12
12
  "rank" => "first lieutenant",
13
13
  "serial_number" => "foobar",
14
- "last_sign_in_at" => now
14
+ "last_sign_in_at" => now,
15
15
  },
16
16
  saved_changes: {
17
17
  "name" => %w(bill bob),
18
- "last_sign_in_at" => now
19
- }
18
+ "last_sign_in_at" => now,
19
+ },
20
+ journaled_enqueue_opts: {},
20
21
  )
21
22
  end
22
23
 
@@ -24,21 +25,21 @@ RSpec.describe Journaled::ChangeWriter do
24
25
  double(
25
26
  "SoldierClass",
26
27
  table_name: "soldiers",
27
- attribute_names: %w(id name rank serial_number last_sign_in_at)
28
+ attribute_names: %w(id name rank serial_number last_sign_in_at),
28
29
  )
29
30
  end
30
31
 
31
32
  let(:change_definition) do
32
33
  Journaled::ChangeDefinition.new(
33
34
  attribute_names: %i(name rank serial_number),
34
- logical_operation: "identity_change"
35
+ logical_operation: "identity_change",
35
36
  )
36
37
  end
37
38
 
38
39
  let(:faulty_change_definition) do
39
40
  Journaled::ChangeDefinition.new(
40
41
  attribute_names: %i(name rank serial_number nonexistent_thingie),
41
- logical_operation: "identity_change"
42
+ logical_operation: "identity_change",
42
43
  )
43
44
  end
44
45
 
@@ -58,9 +59,10 @@ RSpec.describe Journaled::ChangeWriter do
58
59
  "name" => "bill",
59
60
  "rank" => "first lieutenant",
60
61
  "serial_number" => "foobar",
61
- "last_sign_in_at" => Time.zone.now
62
+ "last_sign_in_at" => Time.zone.now,
62
63
  },
63
- saved_changes: {}
64
+ saved_changes: {},
65
+ journaled_enqueue_opts: {},
64
66
  )
65
67
  end
66
68
 
@@ -68,7 +70,7 @@ RSpec.describe Journaled::ChangeWriter do
68
70
  expect(subject.relevant_attributes).to eq(
69
71
  "name" => "bill",
70
72
  "rank" => "first lieutenant",
71
- "serial_number" => "foobar"
73
+ "serial_number" => "foobar",
72
74
  )
73
75
  end
74
76
  end
@@ -83,11 +85,12 @@ RSpec.describe Journaled::ChangeWriter do
83
85
  "name" => "bill",
84
86
  "rank" => "first lieutenant",
85
87
  "serial_number" => "foobar",
86
- "last_sign_in_at" => Time.zone.now
88
+ "last_sign_in_at" => Time.zone.now,
87
89
  },
88
90
  changes: {
89
- "name" => %w(bob bill)
90
- }
91
+ "name" => %w(bob bill),
92
+ },
93
+ journaled_enqueue_opts: {},
91
94
  )
92
95
  end
93
96
 
@@ -95,7 +98,7 @@ RSpec.describe Journaled::ChangeWriter do
95
98
  expect(subject.relevant_unperturbed_attributes).to eq(
96
99
  "name" => "bob",
97
100
  "rank" => "first lieutenant",
98
- "serial_number" => "foobar"
101
+ "serial_number" => "foobar",
99
102
  )
100
103
  end
101
104
  end
@@ -180,9 +183,10 @@ RSpec.describe Journaled::ChangeWriter do
180
183
  "name" => "bill",
181
184
  "rank" => "first lieutenant",
182
185
  "serial_number" => "foobar",
183
- "last_sign_in_at" => Time.zone.now
186
+ "last_sign_in_at" => Time.zone.now,
184
187
  },
185
- saved_changes: {}
188
+ saved_changes: {},
189
+ journaled_enqueue_opts: {},
186
190
  )
187
191
  end
188
192
 
@@ -222,9 +226,9 @@ RSpec.describe Journaled::ChangeWriter do
222
226
  "name" => "bill",
223
227
  "rank" => "first lieutenant",
224
228
  "serial_number" => "foobar",
225
- "last_sign_in_at" => Time.zone.now
229
+ "last_sign_in_at" => Time.zone.now,
226
230
  },
227
- saved_changes: {}
231
+ saved_changes: {},
228
232
  )
229
233
  end
230
234
 
@@ -248,11 +252,12 @@ RSpec.describe Journaled::ChangeWriter do
248
252
  "name" => "bob",
249
253
  "rank" => "first lieutenant",
250
254
  "serial_number" => "foobar",
251
- "last_sign_in_at" => now
255
+ "last_sign_in_at" => now,
252
256
  },
253
257
  changes: {
254
- "name" => %w(bill bob)
255
- }
258
+ "name" => %w(bill bob),
259
+ },
260
+ journaled_enqueue_opts: {},
256
261
  )
257
262
  end
258
263
 
@@ -261,7 +266,7 @@ RSpec.describe Journaled::ChangeWriter do
261
266
  expect(JSON.parse(opts[:changes])).to eq(
262
267
  "name" => "bill",
263
268
  "rank" => "first lieutenant",
264
- "serial_number" => "foobar"
269
+ "serial_number" => "foobar",
265
270
  )
266
271
  journaled_change
267
272
  end