chaotic_job 0.5.0 → 0.6.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 +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +19 -15
- data/lib/chaotic_job/glitch.rb +27 -12
- data/lib/chaotic_job/scenario.rb +5 -19
- data/lib/chaotic_job/simulation.rb +2 -1
- data/lib/chaotic_job/version.rb +1 -1
- data/lib/chaotic_job.rb +7 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 10db3cce1a0eedffe044477a348122d781e19cfbb6f561c9e389926d7de21153
|
4
|
+
data.tar.gz: a48f0d63526613593a25cc92d1c3eca794adb99466ef697a3c932e581a08434a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a1ea02d93adf652616f25478c8d7f628f30d56137485b10988bd2f08b9a62153327cd60c787555d7ba4286a7c26f94616ee45c92a58778e0689011461a39bb3b
|
7
|
+
data.tar.gz: 6d94662caef5559bca3de08c69674ad10dd4fa349fbd8434a42dc65c8baa8ba6da13f6cc8d13b9af815f4610148a874ba3f9fa0b9e5c8aa97e7b131afc5c3689
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -107,7 +107,7 @@ test "scenario of a simple job" do
|
|
107
107
|
def step_3; ChaoticJob::Journal.log; end
|
108
108
|
end
|
109
109
|
|
110
|
-
run_scenario(Job.new, glitch:
|
110
|
+
run_scenario(Job.new, glitch: ChaoticJob::Glitch.before_call("Job#step_3"))
|
111
111
|
|
112
112
|
assert_equal 5, ChaoticJob::Journal.total
|
113
113
|
end
|
@@ -124,14 +124,16 @@ end
|
|
124
124
|
> | `Journal.entries` | get all of the logged values under the default scope |
|
125
125
|
> | `Journal.entries(scope: :special)` | get all of the logged values under a particular scope |
|
126
126
|
|
127
|
-
In this example, the job being tested is defined within the test case. You can, of course, also test jobs defined in your application. The key detail is the `glitch` keyword argument.
|
127
|
+
In this example, the job being tested is defined within the test case. You can, of course, also test jobs defined in your application. The key detail is the `glitch` keyword argument.
|
128
|
+
|
129
|
+
A "glitch" is describes precisely where you would like the failure to occur. The description is composed first of the _kind_ of glitch, which can be either `before_line`, `before_call`, or `before_return`. These refer to the three kinds of `TracePoint` events that the gem hooks into. The second element is the _key_ for the code that will be affected by the glitch. This _key_ is a specially formatted string that defines the specific bit of code that the glitch should be inserted before. The different kinds of glitches are identified by different kinds of keys:
|
128
130
|
|kind|key format|key example|
|
129
131
|
|---|---|---|
|
130
|
-
|
131
|
-
|
132
|
-
|
132
|
+
|`before_line`|`"#{file_path}:#{line_number}"`|`"/Users/you/path/to/file.rb:123"`|
|
133
|
+
|`before_call`|`"#{YourClass.name}(.|#)#{method_name}"`|`"YourClass.some_class_method"`|
|
134
|
+
|`before_return`|`"#{YourClass.name}(.|#)#{method_name}"`|`"YourClass#some_instance_method"`|
|
133
135
|
|
134
|
-
As you can see, the
|
136
|
+
As you can see, the `before_call` and `before_return` keys are formatted the same, and can identify any instance (`#`) or class (`.`) method.
|
135
137
|
|
136
138
|
What the example scenario above does is inject a glitch before the `step_3` method is called, here:
|
137
139
|
|
@@ -144,10 +146,10 @@ def perform
|
|
144
146
|
end
|
145
147
|
```
|
146
148
|
|
147
|
-
If we wanted to inject a glitch right before the `step_3` method finishes, we could define the glitch as a
|
149
|
+
If we wanted to inject a glitch right before the `step_3` method finishes, we could define the glitch as a `before_return`, like this:
|
148
150
|
|
149
151
|
```ruby
|
150
|
-
run_scenario(Job.new, glitch:
|
152
|
+
run_scenario(Job.new, glitch: ChaoticJob::Glitch.before_return("Job#step_3"))
|
151
153
|
```
|
152
154
|
|
153
155
|
and it would inject the transient error right here:
|
@@ -159,19 +161,21 @@ def step_3
|
|
159
161
|
end
|
160
162
|
```
|
161
163
|
|
162
|
-
Finally, if you need to inject a glitch right before a particular line of code is executed that is neither a method call nor a method return, you can use the
|
164
|
+
Finally, if you need to inject a glitch right before a particular line of code is executed that is neither a method call nor a method return, you can use the `before_line` key, like this:
|
163
165
|
|
164
166
|
```ruby
|
165
|
-
run_scenario(Job.new, glitch:
|
167
|
+
run_scenario(Job.new, glitch: ChaoticJob::Glitch.before_line("#{__FILE__}:6"))
|
166
168
|
```
|
167
169
|
|
168
|
-
If you want to simulate multiple glitches affecting a job run, you
|
170
|
+
If you want to simulate multiple glitches affecting a job run, you simply define additional failure points using the fluid interface of the `ChaoticJob::Glitch` class:
|
169
171
|
|
170
172
|
```ruby
|
171
|
-
run_scenario(
|
172
|
-
|
173
|
-
|
174
|
-
|
173
|
+
run_scenario(
|
174
|
+
Job.new,
|
175
|
+
glitch: ChaoticJob::Glitch
|
176
|
+
.before_call("Job#step_1")
|
177
|
+
.before_return("Job#step_3")
|
178
|
+
)
|
175
179
|
```
|
176
180
|
|
177
181
|
Scenario testing is useful to test the behavior of a job under a specific set of conditions. But, if you want to test the behavior of a job under a variety of conditions, you can use the `run_simulation` method. Instead of running a single scenario, a simulation will run the full set of possible error scenarios for your job.
|
data/lib/chaotic_job/glitch.rb
CHANGED
@@ -1,12 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Glitch.
|
4
|
-
# Glitch.
|
5
|
-
# Glitch.
|
6
|
-
# Glitch.
|
3
|
+
# Glitch.before_line("job_crucible.rb:10") { do_anything }
|
4
|
+
# Glitch.before_call("Model#method", String, name: "Joel") { do_anything }
|
5
|
+
# Glitch.before_return("Model#method", String, name: "Joel") { do_anything }
|
6
|
+
# Glitch.inject! { execute code to glitch }
|
7
7
|
|
8
8
|
module ChaoticJob
|
9
9
|
class Glitch
|
10
|
+
def self.before_line(key, &block)
|
11
|
+
new.before_line(key, &block)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.before_call(key, ...)
|
15
|
+
new.before_call(key, ...)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.before_return(key, return_type = nil, &block)
|
19
|
+
new.before_return(key, return_type, &block)
|
20
|
+
end
|
21
|
+
|
10
22
|
def initialize
|
11
23
|
@breakpoints = {}
|
12
24
|
end
|
@@ -26,6 +38,15 @@ module ChaoticJob
|
|
26
38
|
self
|
27
39
|
end
|
28
40
|
|
41
|
+
def set_action(force: false, &block)
|
42
|
+
@breakpoints.each do |_key, handlers|
|
43
|
+
handlers.each do |_event, handler|
|
44
|
+
handler[:block] = block if handler[:block].nil? || force
|
45
|
+
end
|
46
|
+
end
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
29
50
|
def inject!(&block)
|
30
51
|
breakpoints = @breakpoints
|
31
52
|
|
@@ -45,17 +66,11 @@ module ChaoticJob
|
|
45
66
|
end
|
46
67
|
|
47
68
|
def all_executed?
|
48
|
-
@breakpoints.all? do |
|
49
|
-
handlers.all? { |
|
69
|
+
@breakpoints.all? do |_key, handlers|
|
70
|
+
handlers.all? { |_event, handler| handler[:executed] }
|
50
71
|
end
|
51
72
|
end
|
52
73
|
|
53
|
-
# def inspect
|
54
|
-
# @breakpoints.flat_map do |location, configs|
|
55
|
-
# configs.keys.map { |position| "#{position}-#{location}" }
|
56
|
-
# end.join("|>")
|
57
|
-
# end
|
58
|
-
|
59
74
|
private
|
60
75
|
|
61
76
|
def set_breakpoint(key, event, *args, retval: nil, **kwargs, &block)
|
data/lib/chaotic_job/scenario.rb
CHANGED
@@ -7,20 +7,20 @@ module ChaoticJob
|
|
7
7
|
class Scenario
|
8
8
|
attr_reader :events
|
9
9
|
|
10
|
-
def initialize(job,
|
10
|
+
def initialize(job, glitch:, raise: RetryableError, capture: /active_job/)
|
11
11
|
@job = job
|
12
|
-
@
|
12
|
+
@glitch = (Glitch === glitch) ? glitch : (raise Error.new("glitch: must be a Glitch instance, but got #{glitch.inspect}"))
|
13
13
|
@raise = binding.local_variable_get(:raise)
|
14
14
|
@capture = capture
|
15
|
-
@glitch = nil
|
16
15
|
@events = []
|
17
16
|
end
|
18
17
|
|
19
18
|
def run(&block)
|
20
19
|
@job.class.retry_on RetryableError, attempts: 10, wait: 1, jitter: 0
|
20
|
+
@glitch.set_action { raise @raise }
|
21
21
|
|
22
22
|
ActiveSupport::Notifications.subscribed(->(event) { @events << event.dup }, @capture) do
|
23
|
-
glitch.inject! do
|
23
|
+
@glitch.inject! do
|
24
24
|
@job.enqueue
|
25
25
|
if block
|
26
26
|
block.call
|
@@ -30,25 +30,11 @@ module ChaoticJob
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
# TODO: assert that all
|
34
|
-
end
|
35
|
-
|
36
|
-
def to_s
|
37
|
-
@glitches.map { |position, location| "#{position}-#{location}" }.join("|>")
|
33
|
+
# TODO: assert that all glitch ran
|
38
34
|
end
|
39
35
|
|
40
36
|
def all_glitched?
|
41
37
|
@glitch.all_executed?
|
42
38
|
end
|
43
|
-
|
44
|
-
private
|
45
|
-
|
46
|
-
def glitch
|
47
|
-
@glitch ||= Glitch.new.tap do |glitch|
|
48
|
-
@glitches.each do |kind, location, _description|
|
49
|
-
glitch.public_send(kind, location) { raise @raise }
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
39
|
end
|
54
40
|
end
|
@@ -45,7 +45,8 @@ module ChaoticJob
|
|
45
45
|
def scenarios
|
46
46
|
variants.map do |glitches|
|
47
47
|
job = clone_job_template
|
48
|
-
|
48
|
+
glitch = Glitch.new.tap { |g| glitches.each { |event, key| g.public_send(event, key) } }
|
49
|
+
scenario = Scenario.new(job, glitch: glitch)
|
49
50
|
job.job_id = scenario.to_s
|
50
51
|
scenario
|
51
52
|
end
|
data/lib/chaotic_job/version.rb
CHANGED
data/lib/chaotic_job.rb
CHANGED
@@ -76,10 +76,13 @@ module ChaoticJob
|
|
76
76
|
Simulation.new(job, **kwargs).run(&block)
|
77
77
|
end
|
78
78
|
|
79
|
-
def run_scenario(job, glitch
|
80
|
-
kwargs = {
|
79
|
+
def run_scenario(job, glitch:, raise: nil, capture: nil, &block)
|
80
|
+
kwargs = {}
|
81
|
+
|
82
|
+
kwargs[:glitch] = glitch
|
81
83
|
kwargs[:raise] = binding.local_variable_get(:raise) if binding.local_variable_get(:raise)
|
82
84
|
kwargs[:capture] = capture if capture
|
85
|
+
|
83
86
|
if block
|
84
87
|
Scenario.new(job, **kwargs).run(&block)
|
85
88
|
else
|
@@ -87,6 +90,8 @@ module ChaoticJob
|
|
87
90
|
end
|
88
91
|
end
|
89
92
|
|
93
|
+
private
|
94
|
+
|
90
95
|
def assert(test, msg = nil)
|
91
96
|
return super unless @simulation_scenario
|
92
97
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chaotic_job
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen Margheim
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-06-
|
10
|
+
date: 2025-06-08 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: activejob
|