journaled 3.1.0 → 4.2.0

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: d758f3a24c9170a8b7585c330c59a80483ac763640ad847e229f16123d6f9f1b
4
- data.tar.gz: adb70f763fd7daffcdc89a02898846a55132461f6329a67d787ce7fd10f73257
3
+ metadata.gz: bfdabb8b24bdfdf23c4f77ec819f03e89a4a0239ed997368eb1f07ac0bc2cd5b
4
+ data.tar.gz: 97eeec1dfa22f7b683f23e322eb663e6fae4b47e0c2786690c4f44166b8cca51
5
5
  SHA512:
6
- metadata.gz: 346e26235e8de20fc34e0a888b2d3bf98189d73aaa9968db4af9addcf04b8c8577bb0f8e31d5443d85549f0da6c6defae8f554d328fc328732ae029a90704e2f
7
- data.tar.gz: 1be21eed56a1ac95e27e13712831bd45fe0c4e8cf3b896b19e7ad9037b924a9d6543828ddb6d2112cbd25aa77aa464e7e99fd4fd8a4288a89c7d11ad2836915b
6
+ metadata.gz: 78c8b888f9c00a084e8d60c2f271d56a9a188f60287cb30edfbadc7a4f9fc1c3fc3210c763e757658a0040fb57f6f94f1a713fc1f95942db801e2e114dd50ec3
7
+ data.tar.gz: f0e56609680ecfc3e1f3f3a9d2ba801515762311307f0a208757a70a82ff7c37ba6af040f8ee5a64ebbf7a08a910579c27d65e940680b2406383b8eca022f323
data/README.md CHANGED
@@ -18,22 +18,24 @@ add scoped ordering capability at a future date (and would gladly
18
18
  entertain pull requests), but it is presently only designed to provide a
19
19
  durable, eventually consistent record that discrete events happened.
20
20
 
21
+ **See [upgrades](#upgrades) below if you're upgrading from an older `journaled` version!**
22
+
21
23
  ## Installation
22
24
 
23
25
  1. If you haven't already,
24
26
  [configure ActiveJob](https://guides.rubyonrails.org/active_job_basics.html)
25
27
  to use one of the following queue adapters:
26
28
 
27
- - `:delayed_job` (via `delayed_job_active_record`)
28
- - `:que`
29
- - `:good_job`
30
- - `:delayed`
29
+ - `:delayed_job` (via `delayed_job_active_record`)
30
+ - `:que`
31
+ - `:good_job`
32
+ - `:delayed`
31
33
 
32
- Ensure that your queue adapter is not configured to delete jobs on failure.
34
+ Ensure that your queue adapter is not configured to delete jobs on failure.
33
35
 
34
- **If you launch your application in production mode and the gem detects that
35
- `ActiveJob::Base.queue_adapter` is not in the above list, it will raise an exception
36
- and prevent your application from performing unsafe journaling.**
36
+ **If you launch your application in production mode and the gem detects that
37
+ `ActiveJob::Base.queue_adapter` is not in the above list, it will raise an exception
38
+ and prevent your application from performing unsafe journaling.**
37
39
 
38
40
  2. To integrate Journaled into your application, simply include the gem in your
39
41
  app's Gemfile.
@@ -51,20 +53,21 @@ app's Gemfile.
51
53
  require 'journaled/rspec'
52
54
  ```
53
55
 
54
- 3. You will also need to define the following environment variables to allow Journaled to publish events to your AWS Kinesis event stream:
56
+ 3. You will need to set the following config in an initializer to allow Journaled to publish events to your AWS Kinesis event stream:
55
57
 
56
- * `JOURNALED_STREAM_NAME`
58
+ ```ruby
59
+ Journaled.default_stream_name = "my_app_#{Rails.env}_events"
60
+ ```
57
61
 
58
- Special case: if your `Journaled::Event` objects override the
59
- `#journaled_app_name` method to a non-nil value e.g. `my_app`, you will
60
- instead need to provide a corresponding
61
- `[upcased_app_name]_JOURNALED_STREAM_NAME` variable for each distinct
62
- value, e.g. `MY_APP_JOURNALED_STREAM_NAME`. You can provide a default value
63
- for all `Journaled::Event`s in an initializer like this:
62
+ You may also define a `#journaled_stream_name` method on `Journaled::Event` instances:
64
63
 
65
64
  ```ruby
66
- Journaled.default_app_name = 'my_app'
67
- ```
65
+ def journaled_stream_name
66
+ "my_app_#{Rails.env}_alternate_events"
67
+ end
68
+ ````
69
+
70
+ 3. You may also need to define environment variables to allow Journaled to publish events to your AWS Kinesis event stream:
68
71
 
69
72
  You may optionally define the following ENV vars to specify AWS
70
73
  credentials outside of the locations that the AWS SDK normally looks:
@@ -88,11 +91,9 @@ app's Gemfile.
88
91
 
89
92
  Journaling provides a number of different configuation options that can be set in Ruby using an initializer. Those values are:
90
93
 
91
- #### `Journaled.default_app_name`
94
+ #### `Journaled.default_stream_name `
92
95
 
93
- This is described in the proceeding paragraph and is used to specify which app name to use, which corresponds to which Journaled Stream to send events too.
94
- This is the default value for events that do NOT specify their own `#journaled_app_name`. For events that define their own `#journaled_app_name` method, that will take precedence over this default.
95
- Ex: `Journaled.default_app_name = 'my_app'`
96
+ This is described in the "Installation" section above, and is used to specify which stream name to use.
96
97
 
97
98
  #### `Journaled.job_priority` (default: 20)
98
99
 
@@ -149,8 +150,8 @@ class ApplicationController < ActionController::Base
149
150
  end
150
151
  ```
151
152
 
152
- Your authenticated entity must respond to `#to_global_id`, which
153
- ActiveRecords do by default.
153
+ Your authenticated entity must respond to `#to_global_id`, which ActiveRecords do by default.
154
+ This feature relies on `ActiveSupport::CurrentAttributes` under the hood.
154
155
 
155
156
  Every time any of the specified attributes is modified, or a `User`
156
157
  record is created or destroyed, an event will be sent to Kinesis with the following attributes:
@@ -178,6 +179,40 @@ journaling. Note that the less-frequently-used methods `toggle`,
178
179
  `increment*`, `decrement*`, and `update_counters` are not intercepted at
179
180
  this time.
180
181
 
182
+ ### Tagged Events
183
+
184
+ Events may be optionally marked as "tagged." This will add a `tags` field, intended for tracing and
185
+ auditing purposes.
186
+
187
+ ```ruby
188
+ class MyEvent
189
+ include Journaled::Event
190
+
191
+ journal_attributes :attr_1, :attr_2, tagged: true
192
+ end
193
+ ```
194
+
195
+ You may then use `Journaled.tag!` and `Journaled.tagged` inside of your
196
+ `ApplicationController` and `ApplicationJob` classes (or anywhere else!) to tag
197
+ all events with request and job metadata:
198
+
199
+ ```ruby
200
+ class ApplicationController < ActionController::Base
201
+ before_action do
202
+ Journaled.tag!(request_id: request.request_id, current_user_id: current_user&.id)
203
+ end
204
+ end
205
+
206
+ class ApplicationJob < ActiveJob::Base
207
+ around_perform do |job, perform|
208
+ Journaled.tagged(job_id: job.id) { perform.call }
209
+ end
210
+ end
211
+ ```
212
+
213
+ This feature relies on `ActiveSupport::CurrentAttributes` under the hood, so these tags are local to
214
+ the current thread, and will be cleared at the end of each request request/job.
215
+
181
216
  #### Testing
182
217
 
183
218
  If you use RSpec (and have required `journaled/rspec` in your
@@ -317,6 +352,49 @@ Returns one of the following in order of preference:
317
352
  In order for this to be most useful, you must configure your controller
318
353
  as described in [Change Journaling](#change-journaling) above.
319
354
 
355
+ ## Upgrades
356
+
357
+ Since this gem relies on background jobs (which can remain in the queue across
358
+ code releases), this gem generally aims to support jobs enqueued by the prior
359
+ gem version.
360
+
361
+ As such, **we always recommend upgrading only one major version at a time.**
362
+
363
+ ### Upgrading from 3.1.0
364
+
365
+ Versions of Journaled prior to 4.0 relied directly on environment variables for stream names, but now stream names are configured directly.
366
+ When upgrading, you can use the following configuration to maintain the previous behavior:
367
+
368
+ ```ruby
369
+ Journaled.default_stream_name = ENV['JOURNALED_STREAM_NAME']
370
+ ```
371
+
372
+ If you previously specified a `Journaled.default_app_name`, you would have required a more precise environment variable name (substitute `{{upcase_app_name}}`):
373
+
374
+ ```ruby
375
+ Journaled.default_stream_name = ENV["{{upcase_app_name}}_JOURNALED_STREAM_NAME"]
376
+ ```
377
+
378
+ And if you had defined any `journaled_app_name` methods on `Journaled::Event` instances, you can replace them with the following:
379
+
380
+ ```ruby
381
+ def journaled_stream_name
382
+ ENV['{{upcase_app_name}}_JOURNALED_STREAM_NAME']
383
+ end
384
+ ```
385
+
386
+ When upgrading from 3.1 or below, `Journaled::DeliveryJob` will handle any jobs that remain in the queue by accepting an `app_name` argument. **This behavior will be removed in version 5.0**, so it is recommended to upgrade one major version at a time.
387
+
388
+ ### Upgrading from 2.5.0
389
+
390
+ Versions of Journaled prior to 3.0 relied direclty on `delayed_job` and a "performable" class called `Journaled::Delivery`.
391
+ In 3.0, this was superceded by an ActiveJob class called `Journaled::DeliveryJob`, but the `Journaled::Delivery` class was not removed until 4.0.
392
+
393
+ Therefore, when upgrading from 2.5.0 or below, it is recommended to first upgrade to 3.1.0 (to allow any `Journaled::Delivery` jobs to finish working off) before upgrading to 4.0+.
394
+
395
+ The upgrade to 3.1.0 will require a working ActiveJob config. ActiveJob can be configured globally by setting `ActiveJob::Base.queue_adapter`, or just for Journaled jobs by setting `Journaled::DeliveryJob.queue_adapter`.
396
+ The `:delayed_job` queue adapter will allow you to continue relying on `delayed_job`. You may also consider switching your app(s) to [`delayed`](https://github.com/Betterment/delayed) and using the `:delayed` queue adapter.
397
+
320
398
  ## Future improvements & issue tracking
321
399
  Suggestions for enhancements to this engine are currently being tracked via Github Issues. Please feel free to open an
322
400
  issue for a desired feature, as well as for any observed bugs.
data/Rakefile CHANGED
@@ -4,37 +4,23 @@ rescue LoadError
4
4
  puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
5
  end
6
6
 
7
- require 'rdoc/task'
8
-
9
- RDoc::Task.new(:rdoc) do |rdoc|
10
- rdoc.rdoc_dir = 'rdoc'
11
- rdoc.title = 'Journaled'
12
- rdoc.options << '--line-numbers'
13
- rdoc.rdoc_files.include('README.rdoc')
14
- rdoc.rdoc_files.include('lib/**/*.rb')
15
- end
16
-
17
- APP_RAKEFILE = File.expand_path('spec/dummy/Rakefile', __dir__)
18
- load 'rails/tasks/engine.rake'
19
-
20
7
  Bundler::GemHelper.install_tasks
21
8
 
22
- if %w(development test).include? Rails.env
23
- require 'rspec/core'
24
- require 'rspec/core/rake_task'
25
- RSpec::Core::RakeTask.new
9
+ require 'rubocop/rake_task'
10
+ RuboCop::RakeTask.new
26
11
 
27
- require 'rubocop/rake_task'
28
- RuboCop::RakeTask.new
12
+ require 'rspec/core'
13
+ require 'rspec/core/rake_task'
14
+ RSpec::Core::RakeTask.new(:spec)
29
15
 
30
- task(:default).clear
16
+ def default_task
31
17
  if ENV['APPRAISAL_INITIALIZED'] || ENV['CI']
32
- task default: %i(rubocop spec)
18
+ %i(rubocop spec)
33
19
  else
34
20
  require 'appraisal'
35
21
  Appraisal::Task.new
36
- task default: :appraisal
22
+ %i(appraisal)
37
23
  end
38
-
39
- task 'db:test:prepare' => 'db:setup'
40
24
  end
25
+
26
+ task(:default).clear.enhance(default_task)
@@ -2,11 +2,14 @@ module Journaled::Actor
2
2
  extend ActiveSupport::Concern
3
3
 
4
4
  included do
5
- class_attribute :_journaled_actor_method_name, instance_accessor: false, instance_predicate: false
6
- before_action do
7
- RequestStore.store[:journaled_actor_proc] = self.class._journaled_actor_method_name &&
8
- -> { send(self.class._journaled_actor_method_name) }
9
- end
5
+ class_attribute :_journaled_actor_method_name, instance_writer: false
6
+ before_action :_set_journaled_actor_proc, if: :_journaled_actor_method_name?
7
+ end
8
+
9
+ private
10
+
11
+ def _set_journaled_actor_proc
12
+ Journaled::Current.journaled_actor_proc = -> { send(self.class._journaled_actor_method_name) }
10
13
  end
11
14
 
12
15
  class_methods do
@@ -12,15 +12,24 @@ module Journaled
12
12
  raise KinesisTemporaryFailure
13
13
  end
14
14
 
15
- def perform(serialized_event:, partition_key:, app_name:)
15
+ UNSPECIFIED = Object.new
16
+ private_constant :UNSPECIFIED
17
+
18
+ def perform(serialized_event:, partition_key:, stream_name: UNSPECIFIED, app_name: UNSPECIFIED)
16
19
  @serialized_event = serialized_event
17
20
  @partition_key = partition_key
18
- @app_name = app_name
21
+ if app_name != UNSPECIFIED
22
+ @stream_name = self.class.legacy_computed_stream_name(app_name: app_name)
23
+ elsif stream_name != UNSPECIFIED && !stream_name.nil?
24
+ @stream_name = stream_name
25
+ else
26
+ raise(ArgumentError, 'missing keyword: stream_name')
27
+ end
19
28
 
20
29
  journal!
21
30
  end
22
31
 
23
- def self.stream_name(app_name:)
32
+ def self.legacy_computed_stream_name(app_name:)
24
33
  env_var_name = [app_name&.upcase, 'JOURNALED_STREAM_NAME'].compact.join('_')
25
34
  ENV.fetch(env_var_name)
26
35
  end
@@ -37,7 +46,7 @@ module Journaled
37
46
 
38
47
  private
39
48
 
40
- attr_reader :serialized_event, :partition_key, :app_name
49
+ attr_reader :serialized_event, :partition_key, :stream_name
41
50
 
42
51
  def journal!
43
52
  kinesis_client.put_record record if Journaled.enabled?
@@ -45,7 +54,7 @@ module Journaled
45
54
 
46
55
  def record
47
56
  {
48
- stream_name: self.class.stream_name(app_name: app_name),
57
+ stream_name: stream_name,
49
58
  data: serialized_event,
50
59
  partition_key: partition_key,
51
60
  }
@@ -39,8 +39,8 @@ module Journaled::Changes
39
39
  end
40
40
  end
41
41
 
42
- def update_columns(attributes, force: false)
43
- unless force || self.class.journaled_attribute_names.empty?
42
+ def update_columns(attributes, opts = { force: false })
43
+ unless opts[:force] || self.class.journaled_attribute_names.empty?
44
44
  conflicting_journaled_attribute_names = self.class.journaled_attribute_names & attributes.keys.map(&:to_sym)
45
45
  raise(<<~ERROR) if conflicting_journaled_attribute_names.present?
46
46
  #update_columns aborted by Journaled::Changes due to journaled attributes:
@@ -56,7 +56,7 @@ module Journaled::Changes
56
56
  end
57
57
 
58
58
  class_methods do
59
- def journal_changes_to(*attribute_names, as:, enqueue_with: {}) # rubocop:disable Naming/UncommunicativeMethodParamName
59
+ def journal_changes_to(*attribute_names, as:, enqueue_with: {}) # rubocop:disable Naming/MethodParameterName
60
60
  if attribute_names.empty? || attribute_names.any? { |n| !n.is_a?(Symbol) }
61
61
  raise "one or more symbol attribute_name arguments is required"
62
62
  end
@@ -69,8 +69,8 @@ module Journaled::Changes
69
69
  end
70
70
 
71
71
  if Rails::VERSION::MAJOR > 5 || (Rails::VERSION::MAJOR == 5 && Rails::VERSION::MINOR >= 2)
72
- def delete(id_or_array, force: false)
73
- if force || journaled_attribute_names.empty?
72
+ def delete(id_or_array, opts = { force: false })
73
+ if opts[:force] || journaled_attribute_names.empty?
74
74
  where(primary_key => id_or_array).delete_all(force: true)
75
75
  else
76
76
  raise(<<~ERROR)
@@ -8,8 +8,7 @@ class Journaled::ActorUriProvider
8
8
  private
9
9
 
10
10
  def actor_global_id_uri
11
- actor = RequestStore.store[:journaled_actor_proc]&.call
12
- actor.to_global_id.to_s if actor
11
+ Journaled::Current.actor&.to_global_id&.to_s
13
12
  end
14
13
 
15
14
  def fallback_global_id_uri
@@ -2,27 +2,27 @@ class Journaled::Change
2
2
  include Journaled::Event
3
3
 
4
4
  attr_reader :table_name,
5
- :record_id,
6
- :database_operation,
7
- :logical_operation,
8
- :changes,
9
- :journaled_app_name,
10
- :journaled_enqueue_opts,
11
- :actor
5
+ :record_id,
6
+ :database_operation,
7
+ :logical_operation,
8
+ :changes,
9
+ :journaled_stream_name,
10
+ :journaled_enqueue_opts,
11
+ :actor
12
12
 
13
13
  journal_attributes :table_name,
14
- :record_id,
15
- :database_operation,
16
- :logical_operation,
17
- :changes,
18
- :actor
14
+ :record_id,
15
+ :database_operation,
16
+ :logical_operation,
17
+ :changes,
18
+ :actor
19
19
 
20
20
  def initialize(table_name:,
21
21
  record_id:,
22
22
  database_operation:,
23
23
  logical_operation:,
24
24
  changes:,
25
- journaled_app_name:,
25
+ journaled_stream_name:,
26
26
  journaled_enqueue_opts:,
27
27
  actor:)
28
28
  @table_name = table_name
@@ -30,7 +30,7 @@ class Journaled::Change
30
30
  @database_operation = database_operation
31
31
  @logical_operation = logical_operation
32
32
  @changes = changes
33
- @journaled_app_name = journaled_app_name
33
+ @journaled_stream_name = journaled_stream_name
34
34
  @journaled_enqueue_opts = journaled_enqueue_opts
35
35
  @actor = actor
36
36
  end
@@ -1,5 +1,6 @@
1
1
  class Journaled::ChangeWriter
2
2
  attr_reader :model, :change_definition
3
+
3
4
  delegate :attribute_names, :logical_operation, to: :change_definition
4
5
 
5
6
  def initialize(model:, change_definition:)
@@ -27,7 +28,7 @@ class Journaled::ChangeWriter
27
28
  database_operation: database_operation,
28
29
  logical_operation: logical_operation,
29
30
  changes: JSON.dump(changes),
30
- journaled_app_name: journaled_app_name,
31
+ journaled_stream_name: journaled_stream_name,
31
32
  journaled_enqueue_opts: model.journaled_enqueue_opts,
32
33
  actor: actor_uri,
33
34
  )
@@ -52,16 +53,16 @@ class Journaled::ChangeWriter
52
53
  private
53
54
 
54
55
  def pluck_changed_values(change_hash, index:)
55
- change_hash.each_with_object({}) do |(k, v), result|
56
- result[k] = v[index]
56
+ change_hash.transform_values do |v|
57
+ v[index]
57
58
  end
58
59
  end
59
60
 
60
- def journaled_app_name
61
- if model.class.respond_to?(:journaled_app_name)
62
- model.class.journaled_app_name
61
+ def journaled_stream_name
62
+ if model.class.respond_to?(:journaled_stream_name)
63
+ model.class.journaled_stream_name
63
64
  else
64
- Journaled.default_app_name
65
+ Journaled.default_stream_name
65
66
  end
66
67
  end
67
68
  end
@@ -35,16 +35,22 @@ module Journaled::Event
35
35
  event_type
36
36
  end
37
37
 
38
- def journaled_app_name
39
- Journaled.default_app_name
38
+ def journaled_stream_name
39
+ Journaled.default_stream_name
40
+ end
41
+
42
+ def tagged?
43
+ false
40
44
  end
41
45
 
42
46
  private
43
47
 
44
48
  class_methods do
45
- def journal_attributes(*args, enqueue_with: {})
49
+ def journal_attributes(*args, enqueue_with: {}, tagged: false)
46
50
  journaled_attributes.concat(args)
47
51
  journaled_enqueue_opts.merge!(enqueue_with)
52
+
53
+ include Tagged if tagged
48
54
  end
49
55
 
50
56
  def journaled_attributes
@@ -61,4 +67,20 @@ module Journaled::Event
61
67
 
62
68
  journal_attributes :id, :event_type, :created_at
63
69
  end
70
+
71
+ module Tagged
72
+ extend ActiveSupport::Concern
73
+
74
+ included do
75
+ journaled_attributes << :tags
76
+ end
77
+
78
+ def tags
79
+ Journaled::Current.tags
80
+ end
81
+
82
+ def tagged?
83
+ true
84
+ end
85
+ end
64
86
  end
@@ -3,7 +3,7 @@ class Journaled::Writer
3
3
  journaled_schema_name
4
4
  journaled_partition_key
5
5
  journaled_attributes
6
- journaled_app_name
6
+ journaled_stream_name
7
7
  journaled_enqueue_opts
8
8
  ).freeze
9
9
 
@@ -25,23 +25,29 @@ class Journaled::Writer
25
25
  end
26
26
 
27
27
  def journal!
28
- base_event_json_schema_validator.validate! serialized_event
29
- json_schema_validator.validate! serialized_event
28
+ validate!
30
29
  Journaled::DeliveryJob
31
30
  .set(journaled_enqueue_opts.reverse_merge(priority: Journaled.job_priority))
32
- .perform_later(delivery_perform_args)
31
+ .perform_later(**delivery_perform_args)
33
32
  end
34
33
 
35
34
  private
36
35
 
37
36
  attr_reader :journaled_event
37
+
38
38
  delegate(*EVENT_METHOD_NAMES, to: :journaled_event)
39
39
 
40
+ def validate!
41
+ schema_validator('base_event').validate! serialized_event
42
+ schema_validator('tagged_event').validate! serialized_event if journaled_event.tagged?
43
+ schema_validator(journaled_schema_name).validate! serialized_event
44
+ end
45
+
40
46
  def delivery_perform_args
41
47
  {
42
48
  serialized_event: serialized_event,
43
49
  partition_key: journaled_partition_key,
44
- app_name: journaled_app_name,
50
+ stream_name: journaled_stream_name,
45
51
  }
46
52
  end
47
53
 
@@ -49,12 +55,8 @@ class Journaled::Writer
49
55
  @serialized_event ||= journaled_attributes.to_json
50
56
  end
51
57
 
52
- def json_schema_validator
53
- @json_schema_validator ||= Journaled::JsonSchemaModel::Validator.new(journaled_schema_name)
54
- end
55
-
56
- def base_event_json_schema_validator
57
- @base_event_json_schema_validator ||= Journaled::JsonSchemaModel::Validator.new('base_event')
58
+ def schema_validator(schema_name)
59
+ Journaled::JsonSchemaModel::Validator.new(schema_name)
58
60
  end
59
61
 
60
62
  def respond_to_all?(object, method_names)
@@ -0,0 +1,14 @@
1
+ {
2
+ "type": "object",
3
+ "title": "tagged_event",
4
+ "additionalProperties": true,
5
+ "required": [
6
+ "tags"
7
+ ],
8
+ "properties": {
9
+ "tags": {
10
+ "type": "object",
11
+ "additionalProperties": true
12
+ }
13
+ }
14
+ }
@@ -0,0 +1,18 @@
1
+ module Journaled
2
+ class Current < ActiveSupport::CurrentAttributes
3
+ attribute :tags
4
+ attribute :journaled_actor_proc
5
+
6
+ def tags=(value)
7
+ super(value.freeze)
8
+ end
9
+
10
+ def tags
11
+ attributes[:tags] ||= {}.freeze
12
+ end
13
+
14
+ def actor
15
+ journaled_actor_proc&.call
16
+ end
17
+ end
18
+ end
@@ -1,14 +1,15 @@
1
1
  module Journaled::RelationChangeProtection
2
- def update_all(updates, force: false) # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity
3
- unless force || !@klass.respond_to?(:journaled_attribute_names) || @klass.journaled_attribute_names.empty?
4
- conflicting_journaled_attribute_names = if updates.is_a?(Hash)
5
- @klass.journaled_attribute_names & updates.keys.map(&:to_sym)
6
- elsif updates.is_a?(String)
7
- @klass.journaled_attribute_names.select do |a|
8
- updates.match?(/\b(?<!')#{a}(?!')\b/)
9
- end
10
- else
11
- raise "unsupported type '#{updates.class}' for 'updates'"
2
+ def update_all(updates, opts = { force: false }) # rubocop:disable Metrics/AbcSize
3
+ unless opts[:force] || !@klass.respond_to?(:journaled_attribute_names) || @klass.journaled_attribute_names.empty?
4
+ conflicting_journaled_attribute_names = case updates
5
+ when Hash
6
+ @klass.journaled_attribute_names & updates.keys.map(&:to_sym)
7
+ when String
8
+ @klass.journaled_attribute_names.select do |a|
9
+ updates.match?(/\b(?<!')#{a}(?!')\b/)
10
+ end
11
+ else
12
+ raise "unsupported type '#{updates.class}' for 'updates'"
12
13
  end
13
14
  raise(<<~ERROR) if conflicting_journaled_attribute_names.present?
14
15
  .update_all aborted by Journaled::Changes due to journaled attributes:
@@ -1,3 +1,3 @@
1
1
  module Journaled
2
- VERSION = "3.1.0".freeze
2
+ VERSION = "4.2.0".freeze
3
3
  end
data/lib/journaled.rb CHANGED
@@ -1,14 +1,14 @@
1
1
  require "aws-sdk-kinesis"
2
2
  require "active_job"
3
3
  require "json-schema"
4
- require "request_store"
5
4
 
6
5
  require "journaled/engine"
6
+ require "journaled/current"
7
7
 
8
8
  module Journaled
9
9
  SUPPORTED_QUEUE_ADAPTERS = %w(delayed delayed_job good_job que).freeze
10
10
 
11
- mattr_accessor :default_app_name
11
+ mattr_accessor :default_stream_name
12
12
  mattr_accessor(:job_priority) { 20 }
13
13
  mattr_accessor(:http_idle_timeout) { 5 }
14
14
  mattr_accessor(:http_open_timeout) { 2 }
@@ -20,7 +20,7 @@ module Journaled
20
20
  end
21
21
 
22
22
  def enabled?
23
- !['0', 'false', false, 'f', ''].include?(ENV.fetch('JOURNALED_ENABLED', !development_or_test?))
23
+ ['0', 'false', false, 'f', ''].exclude?(ENV.fetch('JOURNALED_ENABLED', !development_or_test?))
24
24
  end
25
25
 
26
26
  def schema_providers
@@ -51,5 +51,17 @@ module Journaled
51
51
  end
52
52
  end
53
53
 
54
+ def self.tagged(**tags)
55
+ existing_tags = Current.tags
56
+ tag!(**tags)
57
+ yield
58
+ ensure
59
+ Current.tags = existing_tags
60
+ end
61
+
62
+ def self.tag!(**tags)
63
+ Current.tags = Current.tags.merge(tags)
64
+ end
65
+
54
66
  module_function :development_or_test?, :enabled?, :schema_providers, :commit_hash, :actor_uri, :detect_queue_adapter!
55
67
  end
data/spec/dummy/config.ru CHANGED
@@ -1,4 +1,4 @@
1
1
  # This file is used by Rack-based servers to start the application.
2
2
 
3
- require ::File.expand_path('../config/environment', __FILE__)
3
+ require ::File.expand_path('config/environment', __dir__)
4
4
  run Rails.application