acidic_job 1.0.0.pre26 → 1.0.0.pre29

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: 12ef46783f7518f53f6f92384087761abecfa81576e72c6c9f8facdec94182a3
4
- data.tar.gz: c39ab11338a29020c6700d7cb9707b0ac9a28a7971f9125247cfbb35eee06b21
3
+ metadata.gz: 41d83dcc9ad4d8b835881a8268e43c8d74f7ae87e8e6dd0ad07e79f8f0df1319
4
+ data.tar.gz: 651b7eb29e6f2c3ec006b18151ae80ca5efeaf17093495656dde87420774c8ac
5
5
  SHA512:
6
- metadata.gz: 4560e80dbfcac6f59efee5cae6236e430cae66ef54928e0f8258180752fdbc78161b421e39d9df46cdc67a528b170589d08db78a609ad52d263cae3b63387c8d
7
- data.tar.gz: 8c23139c2f27dda273bb504a13d45afcf60e5ffec1ad9351cbf984da0ffb2de399cc693f0f98d1edbb053f1b62e2d0a46ba9bac6baa3c43a9d8dd2458cb79eb5
6
+ metadata.gz: 66289b30eae68ad0742f4f744ee509ddaeba4a9cb769101ca836482e8820c64755b63dd1030da3ea152bae73151121af821cfdb0d6f9f26ed80453ca1e2f1f0f
7
+ data.tar.gz: c1c2522cf165f8a3f693aa9ac5839b3e2f1df9f057fe2f7776f1e42c9eb718847f4b3f81e86ca5230b4532dc909505920671f9539f0ca1f20a5c65f196a86c75
data/.gitignore CHANGED
@@ -12,3 +12,5 @@ slides.md
12
12
  /test/dummy
13
13
  /test/log
14
14
  /database.sqlite
15
+ /test/combustion/log/test.log
16
+ /test/combustion/database.sqlite
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- acidic_job (1.0.0.pre26)
4
+ acidic_job (1.0.0.pre29)
5
5
  activerecord
6
6
  activesupport
7
7
  database_cleaner
@@ -144,6 +144,8 @@ GEM
144
144
  nokogiri (1.13.7)
145
145
  mini_portile2 (~> 2.8.0)
146
146
  racc (~> 1.4)
147
+ nokogiri (1.13.7-x86_64-darwin)
148
+ racc (~> 1.4)
147
149
  noticed (1.5.9)
148
150
  http (>= 4.0.0)
149
151
  rails (>= 5.2.0)
data/README.md CHANGED
@@ -246,7 +246,7 @@ class RideCreateJob < ActiveJob::Base
246
246
  end
247
247
  ```
248
248
 
249
- **Note:** This does mean that you are restricted to objects that can be serialized by ActiveRecord, thus no Procs, for example.
249
+ **Note:** This does mean that you are restricted to objects that can be serialized by **`ActiveJob`** (for more info, see [here](https://edgeguides.rubyonrails.org/active_job_basics.html#supported-types-for-arguments)). This means you can persist ActiveRecord models, and any simple Ruby data types, but you can't persist things like Procs or custom class instances, for example.
250
250
 
251
251
  **Note:** You will note the use of `self.ride = ...` in the code sample above. In order to call the attribute setter method that will sync with the database record, you _must_ use this style. `@ride = ...` and/or `ride = ...` will both fail to sync the value with the database record.
252
252
 
@@ -27,6 +27,10 @@ module AcidicJob
27
27
  # which is what the `after_finish :reenqueue_awaited_by_job` check needs
28
28
  job.instance_variable_set(:@acidic_job_run, run)
29
29
 
30
+ # can't reproduce yet, but saw a bug in production where
31
+ # nested awaits workflows had an unsaved `workflow` attribute
32
+ run.save! if run.has_changes_to_save?
33
+
30
34
  step = Step.new(current_step, run, job, step_result)
31
35
  # TODO: WRITE REGRESSION TESTS FOR PARALLEL JOB FAILING AND RETRYING THE ORIGINAL STEP
32
36
  step.progress
@@ -47,7 +47,7 @@ module AcidicJob
47
47
  arguments = args || @args
48
48
  arguments += [kwargs] unless kwargs.empty?
49
49
  normalized_args = ::Sidekiq.load_json(::Sidekiq.dump_json(arguments))
50
- item = { "class" => self.class, "args" => normalized_args, "jid" => jid }
50
+ item = { "class" => self.class.name, "args" => normalized_args, "jid" => jid }
51
51
  sidekiq_options = sidekiq_options_hash || {}
52
52
 
53
53
  sidekiq_options.merge(item)
@@ -3,6 +3,7 @@
3
3
  require "active_record"
4
4
  require "global_id"
5
5
  require "active_support/core_ext/object/with_options"
6
+ require_relative "./serializer"
6
7
 
7
8
  module AcidicJob
8
9
  class Run < ActiveRecord::Base
@@ -17,11 +18,11 @@ module AcidicJob
17
18
 
18
19
  after_create_commit :enqueue_staged_job, if: :staged?
19
20
 
20
- serialize :error_object
21
- serialize :serialized_job
22
- serialize :workflow
23
- serialize :returning_to
24
- store :attr_accessors
21
+ serialize :serialized_job, JSON
22
+ serialize :error_object, Serializer
23
+ serialize :workflow, Serializer
24
+ serialize :returning_to, Serializer
25
+ store :attr_accessors, coder: Serializer
25
26
 
26
27
  validates :staged, inclusion: { in: [true, false] } # uses database default
27
28
  validates :serialized_job, presence: true
@@ -0,0 +1,163 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_job/serializers"
4
+ require "active_job/arguments"
5
+ require "json"
6
+
7
+ class WorkerSerializer < ActiveJob::Serializers::ObjectSerializer
8
+ def serialize(worker)
9
+ super(
10
+ "class" => worker.class.name,
11
+ "args" => worker.instance_variable_get(:@__acidic_job_args),
12
+ "kwargs" => worker.instance_variable_get(:@__acidic_job_kwargs)
13
+ )
14
+ end
15
+
16
+ def deserialize(hash)
17
+ worker_class = hash["class"].constantize
18
+ worker_class.new(*hash["args"], **hash["kwargs"])
19
+ end
20
+
21
+ def serialize?(argument)
22
+ defined?(::Sidekiq) && argument.class.include?(::Sidekiq::Worker)
23
+ end
24
+ end
25
+
26
+ class JobSerializer < ActiveJob::Serializers::ObjectSerializer
27
+ def serialize(job)
28
+ super(job.serialize)
29
+ end
30
+
31
+ def deserialize(hash)
32
+ job = ActiveJob::Base.deserialize(hash)
33
+ job.send(:deserialize_arguments_if_needed)
34
+ if job.arguments.last.is_a?(Hash)
35
+ *args, kwargs = job.arguments
36
+ else
37
+ args = job.arguments
38
+ kwargs = {}
39
+ end
40
+ job.instance_variable_set(:@__acidic_job_args, args)
41
+ job.instance_variable_set(:@__acidic_job_kwargs, kwargs)
42
+
43
+ job
44
+ end
45
+
46
+ def serialize?(argument)
47
+ defined?(::ActiveJob::Base) && argument.class < ::ActiveJob::Base
48
+ end
49
+ end
50
+
51
+ class ExceptionSerializer < ActiveJob::Serializers::ObjectSerializer
52
+ def serialize(exception)
53
+ hash = {
54
+ "class" => exception.class.name,
55
+ "message" => exception.message,
56
+ "cause" => exception.cause,
57
+ "backtrace" => {}
58
+ }
59
+
60
+ exception.backtrace.map do |trace|
61
+ path, _, location = trace.rpartition("/")
62
+
63
+ next if hash["backtrace"].key?(path)
64
+
65
+ hash["backtrace"][path] = location
66
+ end
67
+
68
+ super(hash)
69
+ end
70
+
71
+ def deserialize(hash)
72
+ exception_class = hash["class"].constantize
73
+ exception = exception_class.new(hash["message"])
74
+ exception.set_backtrace(hash["backtrace"].map do |path, location|
75
+ [path, location].join("/")
76
+ end)
77
+ exception
78
+ end
79
+
80
+ def serialize?(argument)
81
+ defined?(Exception) && argument.is_a?(Exception)
82
+ end
83
+ end
84
+
85
+ class FinishedPointSerializer < ActiveJob::Serializers::ObjectSerializer
86
+ def serialize(finished_point)
87
+ super(
88
+ "class" => finished_point.class.name
89
+ )
90
+ end
91
+
92
+ def deserialize(hash)
93
+ finished_point_class = hash["class"].constantize
94
+ finished_point_class.new
95
+ end
96
+
97
+ def serialize?(argument)
98
+ defined?(::AcidicJob::FinishedPoint) && argument.is_a?(::AcidicJob::FinishedPoint)
99
+ end
100
+ end
101
+
102
+ class RecoveryPointSerializer < ActiveJob::Serializers::ObjectSerializer
103
+ def serialize(recovery_point)
104
+ super(
105
+ "class" => recovery_point.class.name,
106
+ "name" => recovery_point.name
107
+ )
108
+ end
109
+
110
+ def deserialize(hash)
111
+ recovery_point_class = hash["class"].constantize
112
+ recovery_point_class.new(hash["name"])
113
+ end
114
+
115
+ def serialize?(argument)
116
+ defined?(::AcidicJob::RecoveryPoint) && argument.is_a?(::AcidicJob::RecoveryPoint)
117
+ end
118
+ end
119
+
120
+ ActiveJob::Serializers.add_serializers(
121
+ WorkerSerializer,
122
+ JobSerializer,
123
+ ExceptionSerializer,
124
+ FinishedPointSerializer,
125
+ RecoveryPointSerializer
126
+ )
127
+
128
+ # ...
129
+ module AcidicJob
130
+ module Arguments
131
+ include ActiveJob::Arguments
132
+ extend self # rubocop:disable Style/ModuleFunction
133
+
134
+ # `ActiveJob` will throw an error if it tries to deserialize a GlobalID record.
135
+ # However, this isn't the behavior that we want for our custom `ActiveRecord` serializer.
136
+ # Since `ActiveRecord` does _not_ reset instance record state to its pre-transactional state
137
+ # on a transaction ROLLBACK, we can have GlobalID entries in a serialized column that point to
138
+ # non-persisted records. This is ok. We should simply return `nil` for that portion of the
139
+ # serialized field.
140
+ def deserialize_global_id(hash)
141
+ GlobalID::Locator.locate hash[GLOBALID_KEY]
142
+ rescue ActiveRecord::RecordNotFound
143
+ nil
144
+ end
145
+ end
146
+
147
+ class Serializer
148
+ # Used for `serialize` method in ActiveRecord
149
+ class << self
150
+ def load(json)
151
+ return if json.nil? || json.empty?
152
+
153
+ data = JSON.parse(json)
154
+ Arguments.deserialize(data).first
155
+ end
156
+
157
+ def dump(obj)
158
+ data = Arguments.serialize [obj]
159
+ data.to_json
160
+ end
161
+ end
162
+ end
163
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AcidicJob
4
- VERSION = "1.0.0.pre26"
4
+ VERSION = "1.0.0.pre29"
5
5
  end
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: 1.0.0.pre26
4
+ version: 1.0.0.pre29
5
5
  platform: ruby
6
6
  authors:
7
7
  - fractaledmind
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-07-20 00:00:00.000000000 Z
11
+ date: 2022-08-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -300,6 +300,7 @@ files:
300
300
  - lib/acidic_job/recovery_point.rb
301
301
  - lib/acidic_job/rspec_configuration.rb
302
302
  - lib/acidic_job/run.rb
303
+ - lib/acidic_job/serializer.rb
303
304
  - lib/acidic_job/staging.rb
304
305
  - lib/acidic_job/step.rb
305
306
  - lib/acidic_job/test_case.rb