acidic_job 0.8.2 → 0.8.5

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: a84bc161e4771a11415d7b9bcc9be10cd703242f43ee69bcc1f139e05e93367c
4
- data.tar.gz: 353e0abc18c50d946817e0263517d8efebd6d842a5186f362355da9d2382ac7a
3
+ metadata.gz: 54586a38aa48a14ef168657659a81b0db14446d011bd76085641dd4fb21f7838
4
+ data.tar.gz: 849af5f8e34684cd22d454f85ac816e749c3a4dd91ba58dba34ce67931916d3c
5
5
  SHA512:
6
- metadata.gz: 6009e9a0b132da090454d1ea6c70f852c53169f5a5842f5cd982cc7b167df0a20f2a3dd534879c058b6ffbf2a305ba88f39020b1c92c099ae0d4e76f48b905ff
7
- data.tar.gz: abee47aaa85eed503f0af7e3c3c27b2f6a3c3ed04fd4456d3a9ff743e097db1215409039cbc4c86dccb07cffb073f2e06dcefbf043cf56dc4ad2a83fc64ff624
6
+ metadata.gz: fe54d708708a8316020979400dda7afd73480d34597f9416b30218b7307d8e4ce3cfbf65e14e05681810de88e21d131f06f4a3f72549a7dedef62be209b3137d
7
+ data.tar.gz: 58ba97af8e30c9bff0df8cf4015a3920ce722a5242048469b2224a4d9ca32c67971f03792862c2548515adc33b8407309c386ab1ff1dd509735f420029c11085
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- acidic_job (0.8.2)
4
+ acidic_job (0.8.5)
5
5
  activejob
6
6
  activerecord
7
7
  activesupport
data/README.md CHANGED
@@ -1,7 +1,10 @@
1
1
  # AcidicJob
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/acidic_job.svg)](https://badge.fury.io/rb/acidic_job)
4
- ![main workflow](https://github.com/fractaledmind/acidic_job/actions/workflows/main.yml/badge.svg)
3
+ [![Gem Version](https://badge.fury.io/rb/acidic_job.svg)](https://rubygems.org/gems/acidic_job)
4
+ [![Gem Downloads](https://img.shields.io/gem/dt/acidic_job)](https://rubygems.org/gems/acidic_job)
5
+ ![Tests](https://github.com/fractaledmind/acidic_job/actions/workflows/main.yml/badge.svg)
6
+ ![Coverage](https://img.shields.io/badge/code%20coverage-98%25-success)
7
+ [![Codacy Badge](https://app.codacy.com/project/badge/Grade/e0df63f7a6f141d4aecc3c477314fdb2)](https://www.codacy.com/gh/fractaledmind/acidic_job/dashboard?utm_source=github.com&utm_medium=referral&utm_content=fractaledmind/acidic_job&utm_campaign=Badge_Grade)
5
8
 
6
9
  ## Idempotent operations for Rails apps (for ActiveJob or Sidekiq)
7
10
 
@@ -306,24 +309,22 @@ class ExampleJob < AcidicJob::Base
306
309
  end
307
310
  ```
308
311
 
309
- These options cover the two common situations, but sometimes our systems need finer-grained control. For example, our job might take some record as the job argument, but we need to use a combination of the record identifier and record status as the foundation for the idempotency key. In these cases you can pass a `Proc` to an `acidic_by` class method:
312
+ These options cover the two common situations, but sometimes our systems need finer-grained control. For example, our job might take some record as the job argument, but we need to use a combination of the record identifier and record status as the foundation for the idempotency key. In these cases you can pass a `Proc` or a `Block` to an `acidic_by` class method. This code will be executed in the context of the newly initialized job instance, so you will have access to whatever data the job is initialized with (like the `arguments`, for example):
310
313
 
311
314
  ```ruby
312
315
  class ExampleJob < AcidicJob::Base
313
- acidic_by -> { [@record.id, @record.status] }
316
+ acidic_by do
317
+ record = arguments.first[:record]
318
+ [record.id, record.status]
319
+ end
314
320
 
315
321
  def perform(record:)
316
- @record = record
317
-
318
- # the idempotency key will be based on whatever the values of `@record.id` and `@record.status` are
319
- with_acidic_workflow do |workflow|
320
- workflow.step :do_something
321
- end
322
+ # ...
322
323
  end
323
324
  end
324
325
  ```
325
326
 
326
- > **Note:** The `acidic_by` proc _will be executed in the context of the job instance_ at the moment the `with_acidic_workflow` method is called. This means it will have access to any instance variables defined in your `perform` method up to that point.
327
+ > **Note:** The `acidic_by` proc/block _will be executed in the context of the job instance_ at the moment the job is initialized. This means it will **not** have access to any instance variables defined in your `perform` method.
327
328
 
328
329
 
329
330
  ### Sidekiq Callbacks
@@ -13,11 +13,29 @@ module AcidicJob
13
13
  define_callbacks :perform
14
14
  include Mixin
15
15
 
16
+ concerning :Configuring do
17
+ # Configures the job with the given options.
18
+ def set(options = {}) # :nodoc:
19
+ self.scheduled_at = options[:wait].seconds.from_now.to_f if options[:wait]
20
+ self.scheduled_at = options[:wait_until].to_f if options[:wait_until]
21
+ self.queue_name = self.class.queue_name_from_part(options[:queue]) if options[:queue]
22
+
23
+ self
24
+ end
25
+ end
26
+
16
27
  concerning :Initializing do
28
+ class_methods do
29
+ def job_or_instantiate(*args)
30
+ args.first.is_a?(self) ? args.first : new(*args)
31
+ end
32
+ end
33
+
17
34
  included do
18
35
  attr_accessor :arguments
19
36
  attr_accessor :job_id
20
37
  attr_accessor :queue_name
38
+ attr_accessor :scheduled_at
21
39
  attr_accessor :sidekiq_options
22
40
  end
23
41
  ##
@@ -25,8 +43,8 @@ module AcidicJob
25
43
  # +args+ are the arguments, if any, that will be passed to the perform method
26
44
  # +opts+ are any options to configure the job
27
45
  def initialize(*arguments)
28
- @arguments = arguments
29
- @job_id = ::SecureRandom.uuid
46
+ @arguments = arguments
47
+ @job_id = ::SecureRandom.uuid
30
48
  @sidekiq_options = sidekiq_options_hash || ::Sidekiq.default_job_options
31
49
  @queue_name = @sidekiq_options["queue"]
32
50
  end
@@ -43,22 +61,33 @@ module AcidicJob
43
61
 
44
62
  concerning :Performing do
45
63
  class_methods do
46
- def perform_now(*args, **kwargs)
47
- new.perform(*args, **kwargs)
64
+ def perform_later(*args)
65
+ perform_async(*args)
66
+ end
67
+
68
+ def perform_now(*args)
69
+ perform_inline(*args)
48
70
  end
49
71
  end
50
72
 
51
- def perform_now(*args, **kwargs)
52
- perform(*args, **kwargs)
73
+ def perform_later(*args)
74
+ Setter.new(self.class, {}).perform_async(*args)
75
+ end
76
+
77
+ def perform_now(*args)
78
+ Setter.new(self.class, {}).perform_inline(*args)
53
79
  end
54
80
 
55
81
  def enqueue
56
- ::Sidekiq::Client.push(
82
+ item = {
57
83
  "class" => self.class,
58
84
  "args" => @arguments,
59
85
  "jid" => @job_id,
60
86
  "queue" => @queue_name
61
- )
87
+ }
88
+ item["at"] = @scheduled_at if @scheduled_at
89
+
90
+ ::Sidekiq::Client.push(item)
62
91
  end
63
92
  end
64
93
 
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_job/configured_job"
4
+
5
+ module AcidicJob
6
+ class ConfiguredJob < ::ActiveJob::ConfiguredJob
7
+ def perform_acidicly(...)
8
+ @job_class.new(...).set(@options).perform_acidicly
9
+ end
10
+ end
11
+ end
@@ -10,6 +10,8 @@ module AcidicJob
10
10
  # Ensure our `perform` method always runs first to gather parameters
11
11
  # and run perform callbacks for Sidekiq workers
12
12
  other.prepend PerformWrapper
13
+ # Ensure both configured and base jobs can be performed acidicly
14
+ other.include PerformAcidicly
13
15
 
14
16
  # By default, we unique job runs by the `job_id`
15
17
  other.instance_variable_set(:@acidic_identifier, :job_id)
@@ -18,7 +20,7 @@ module AcidicJob
18
20
  # You could unique job runs by the arguments passed to the job (e.g. memoization)
19
21
  other.define_singleton_method(:acidic_by_job_arguments) { @acidic_identifier = :job_arguments }
20
22
  # Or, you could unique jobs run by any logic you'd like using a block
21
- other.define_singleton_method(:acidic_by) { |&block| @acidic_identifier = block }
23
+ other.define_singleton_method(:acidic_by) { |proc = nil, &block| @acidic_identifier = proc || block }
22
24
 
23
25
  # We add a callback to ensure that staged, non-workflow jobs are "finished" after they are "performed".
24
26
  # This allows us to ensure that we can always inspect whether a run is finished and get correct data
@@ -40,19 +42,6 @@ module AcidicJob
40
42
  super
41
43
  end
42
44
 
43
- # `perform_now` runs a job synchronously and immediately
44
- # `perform_later` runs a job asynchronously and queues it immediately
45
- # `perform_acidicly` run a job asynchronously and queues it after a successful database commit
46
- def perform_acidicly(*args, **kwargs)
47
- job = if kwargs.empty?
48
- new(*args)
49
- else
50
- new(*args, **kwargs)
51
- end
52
-
53
- Run.stage!(job)
54
- end
55
-
56
45
  # Instantiate an instance of a job ready for serialization
57
46
  def with(...)
58
47
  # New delegation syntax (...) was introduced in Ruby 2.7.
@@ -62,12 +51,26 @@ module AcidicJob
62
51
  job.queue_name
63
52
  job
64
53
  end
54
+
55
+ def set(options = {})
56
+ ::AcidicJob::ConfiguredJob.new(self, options)
57
+ end
65
58
  end
66
59
 
67
60
  def idempotency_key
68
61
  IdempotencyKey.new(self).value(acidic_by: acidic_identifier)
69
62
  end
70
63
 
64
+ # Configures the job with the given options.
65
+ def set(options = {}) # :nodoc:
66
+ self.scheduled_at = options[:wait].seconds.from_now.to_f if options[:wait]
67
+ self.scheduled_at = options[:wait_until].to_f if options[:wait_until]
68
+ self.queue_name = self.class.queue_name_from_part(options[:queue]) if options[:queue]
69
+ self.priority = options[:priority].to_i if options[:priority]
70
+
71
+ self
72
+ end
73
+
71
74
  protected
72
75
 
73
76
  # Short circuits execution by sending execution right to 'finished'.
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+
5
+ module AcidicJob
6
+ module PerformAcidicly
7
+ extend ActiveSupport::Concern
8
+
9
+ # `perform_now` runs a job synchronously and immediately
10
+ # `perform_later` runs a job asynchronously and queues it immediately
11
+ # `perform_acidicly` run a job asynchronously and queues it after a successful database commit
12
+
13
+ class_methods do
14
+ def perform_acidicly(...)
15
+ job_or_instantiate(...).perform_acidicly
16
+ end
17
+ end
18
+
19
+ def perform_acidicly
20
+ Run.stage!(self)
21
+ end
22
+ end
23
+ end
@@ -20,14 +20,17 @@ module AcidicJob
20
20
  Serializers::JobSerializer,
21
21
  Serializers::RangeSerializer,
22
22
  Serializers::RecoveryPointSerializer,
23
- Serializers::WorkerSerializer
23
+ Serializers::WorkerSerializer,
24
+ Serializers::ActiveKiqSerializer
24
25
  )
25
26
  end
26
27
  end
27
28
 
29
+ # :nocov:
28
30
  generators do
29
31
  require "generators/acidic_job/install_generator"
30
32
  end
33
+ # :nocov:
31
34
 
32
35
  # This hook happens after all initializers are run, just before returning
33
36
  config.after_initialize do
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_job/serializers/object_serializer"
4
+
5
+ module AcidicJob
6
+ module Serializers
7
+ class ActiveKiqSerializer < ::ActiveJob::Serializers::ObjectSerializer
8
+ def serialize(worker)
9
+ super(
10
+ "job_class" => worker.class.name,
11
+ "arguments" => Arguments.serialize(worker.arguments),
12
+ )
13
+ end
14
+
15
+ def deserialize(hash)
16
+ worker_class = hash["job_class"].constantize
17
+ worker_class.new(*hash["arguments"])
18
+ end
19
+
20
+ def serialize?(argument)
21
+ defined?(::AcidicJob::ActiveKiq) && argument.class < ::AcidicJob::ActiveKiq
22
+ end
23
+ end
24
+ end
25
+ end
@@ -13,7 +13,7 @@ module AcidicJob
13
13
  "backtrace" => {}
14
14
  }
15
15
 
16
- exception.backtrace.map do |trace|
16
+ exception&.backtrace&.map do |trace|
17
17
  path, _, location = trace.rpartition("/")
18
18
 
19
19
  next if hash["backtrace"].key?(path)
@@ -10,7 +10,7 @@ module AcidicJob
10
10
  # by comparing the deserialized database value with a temporary in-memory generated value.
11
11
  # That temporary in-memory generated value can sometimes have an `enqueued_at` value that is 1 second off
12
12
  # from the original. In this case, ActiveRecord will think the record has unsaved changes and block the lock.
13
- super(job.as_json.merge("job_class" => job.class.name))
13
+ super(job.serialize.except("enqueued_at"))
14
14
  end
15
15
 
16
16
  def deserialize(hash)
@@ -2,26 +2,24 @@
2
2
 
3
3
  require "active_job/serializers/object_serializer"
4
4
 
5
- # :nocov:
6
5
  module AcidicJob
7
6
  module Serializers
8
7
  class WorkerSerializer < ::ActiveJob::Serializers::ObjectSerializer
9
8
  def serialize(worker)
10
9
  super(
11
- "job_class" => worker.class.name,
12
- "arguments" => worker.arguments,
10
+ "job_class" => worker.class.name
13
11
  )
14
12
  end
15
13
 
16
14
  def deserialize(hash)
17
15
  worker_class = hash["job_class"].constantize
18
- worker_class.new(*hash["arguments"])
16
+ worker_class.new
19
17
  end
20
18
 
21
19
  def serialize?(argument)
22
- defined?(::Sidekiq) && argument.class.include?(::Sidekiq::Worker)
20
+ defined?(::Sidekiq) && argument.class.include?(::Sidekiq::Worker) &&
21
+ !(defined?(::AcidicJob::ActiveKiq) && argument.class < ::AcidicJob::ActiveKiq)
23
22
  end
24
23
  end
25
24
  end
26
25
  end
27
- # :nocov:
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AcidicJob
4
- VERSION = "0.8.2"
4
+ VERSION = "0.8.5"
5
5
  end
data/lib/acidic_job.rb CHANGED
@@ -5,6 +5,7 @@ require_relative "acidic_job/errors"
5
5
  require_relative "acidic_job/logger"
6
6
  require_relative "acidic_job/arguments"
7
7
  require_relative "acidic_job/serializer"
8
+ require_relative "acidic_job/configured_job"
8
9
  require_relative "acidic_job/workflow_builder"
9
10
  require_relative "acidic_job/idempotency_key"
10
11
  require_relative "acidic_job/recovery_point"
@@ -14,6 +15,7 @@ require_relative "acidic_job/workflow_step"
14
15
  require_relative "acidic_job/workflow"
15
16
  require_relative "acidic_job/processor"
16
17
  require_relative "acidic_job/perform_wrapper"
18
+ require_relative "acidic_job/perform_acidicly"
17
19
  require_relative "acidic_job/extensions/action_mailer"
18
20
  require_relative "acidic_job/extensions/noticed"
19
21
  require_relative "acidic_job/mixin"
@@ -27,6 +29,7 @@ require_relative "acidic_job/serializers/job_serializer"
27
29
  require_relative "acidic_job/serializers/range_serializer"
28
30
  require_relative "acidic_job/serializers/recovery_point_serializer"
29
31
  require_relative "acidic_job/serializers/worker_serializer"
32
+ require_relative "acidic_job/serializers/active_kiq_serializer"
30
33
 
31
34
  require_relative "acidic_job/rails"
32
35
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acidic_job
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.2
4
+ version: 0.8.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - fractaledmind
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-08-17 00:00:00.000000000 Z
11
+ date: 2022-08-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activejob
@@ -253,6 +253,7 @@ files:
253
253
  - lib/acidic_job/active_kiq.rb
254
254
  - lib/acidic_job/arguments.rb
255
255
  - lib/acidic_job/base.rb
256
+ - lib/acidic_job/configured_job.rb
256
257
  - lib/acidic_job/errors.rb
257
258
  - lib/acidic_job/extensions/action_mailer.rb
258
259
  - lib/acidic_job/extensions/noticed.rb
@@ -260,12 +261,14 @@ files:
260
261
  - lib/acidic_job/idempotency_key.rb
261
262
  - lib/acidic_job/logger.rb
262
263
  - lib/acidic_job/mixin.rb
264
+ - lib/acidic_job/perform_acidicly.rb
263
265
  - lib/acidic_job/perform_wrapper.rb
264
266
  - lib/acidic_job/processor.rb
265
267
  - lib/acidic_job/rails.rb
266
268
  - lib/acidic_job/recovery_point.rb
267
269
  - lib/acidic_job/run.rb
268
270
  - lib/acidic_job/serializer.rb
271
+ - lib/acidic_job/serializers/active_kiq_serializer.rb
269
272
  - lib/acidic_job/serializers/exception_serializer.rb
270
273
  - lib/acidic_job/serializers/finished_point_serializer.rb
271
274
  - lib/acidic_job/serializers/job_serializer.rb