job_contracts 0.1.1 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +26 -14
- data/lib/job_contracts/concerns/contractable.rb +0 -6
- data/lib/job_contracts/concerns/sidekiq_contractable.rb +7 -29
- data/lib/job_contracts/contracts/contract.rb +9 -9
- data/lib/job_contracts/railtie.rb +6 -0
- data/lib/job_contracts/sidekiq_job_hash_middleware.rb +10 -0
- data/lib/job_contracts/version.rb +1 -1
- metadata +11 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5bcafda35a29dbc6cb71004f638807b9634658e3eb50cd13f9ebd4274709f03c
|
4
|
+
data.tar.gz: 6a6a0e43df2db48f77525ac3ceae7bb26b36cd300becee484b65b14caec3c703
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 799d3d7aa098fe1775a7ec0e36d210ae25713ccb96c2ab5bd8962298097b7754fb5805f4c99267111aabe19f20caf47e64671806410ffd2af5c11a757121e9a1
|
7
|
+
data.tar.gz: ecef09781a6b2833d30c6e8c1ee2dcf3d32c3a500df0f1b1cab60e4cf8490eeda1b294a77263ffdc9039adec10740b68396e7d292542e75e245a405f3ec59ea0
|
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
-
[![Lines of Code](http://img.shields.io/badge/lines_of_code-
|
1
|
+
[![Lines of Code](http://img.shields.io/badge/lines_of_code-232-brightgreen.svg?style=flat)](http://blog.codinghorror.com/the-best-code-is-no-code-at-all/)
|
2
2
|
[![Code Quality](https://app.codacy.com/project/badge/Grade/f604d4bc6db0474c802ef51182732488)](https://www.codacy.com/gh/hopsoft/job_contracts/dashboard?utm_source=github.com&utm_medium=referral&utm_content=hopsoft/job_contracts&utm_campaign=Badge_Grade)
|
3
|
-
![
|
3
|
+
![Tests](https://github.com/hopsoft/job_contracts/actions/workflows/test.yml/badge.svg)
|
4
|
+
[![Gem Version](https://badge.fury.io/rb/job_contracts.svg)](https://badge.fury.io/rb/job_contracts)
|
5
|
+
[![Follow Hopsoft](https://img.shields.io/twitter/follow/hopsoft?style=social)](https://twitter.com/hopsoft)
|
4
6
|
|
5
7
|
# Job Contracts
|
6
8
|
|
@@ -47,7 +49,6 @@ class ImportantJob < ApplicationJob
|
|
47
49
|
include JobContracts::Contractable
|
48
50
|
|
49
51
|
queue_as :default
|
50
|
-
|
51
52
|
add_contract JobContracts::DurationContract.new(max: 5.seconds)
|
52
53
|
|
53
54
|
def perform
|
@@ -97,7 +98,7 @@ Contracts support the following constructor arguments.
|
|
97
98
|
|
98
99
|
### Defining a Contract
|
99
100
|
|
100
|
-
Here's a contrived but simple example that ensures the first argument to perform fits within a specific range of values.
|
101
|
+
Here's a contrived, but simple, example that ensures the first argument passed to perform fits within a specific range of values.
|
101
102
|
|
102
103
|
```ruby
|
103
104
|
# app/contracts/argument_contract.rb
|
@@ -203,7 +204,6 @@ class ImportantJob < ApplicationJob
|
|
203
204
|
include JobContracts::Contractable
|
204
205
|
|
205
206
|
queue_as :default
|
206
|
-
|
207
207
|
on_contract_breach :take_action
|
208
208
|
add_contract JobContracts::DurationContract.new(max: 5.seconds)
|
209
209
|
|
@@ -222,10 +222,7 @@ class ImportantJob < ApplicationJob
|
|
222
222
|
include JobContracts::Contractable
|
223
223
|
|
224
224
|
queue_as :default
|
225
|
-
|
226
|
-
on_contract_breach -> (contract) {
|
227
|
-
# take action...
|
228
|
-
}
|
225
|
+
on_contract_breach -> (contract) { # take action... }
|
229
226
|
|
230
227
|
add_contract JobContracts::DurationContract.new(max: 5.seconds)
|
231
228
|
|
@@ -237,11 +234,26 @@ end
|
|
237
234
|
|
238
235
|
## Sidekiq
|
239
236
|
|
240
|
-
Sidekiq
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
237
|
+
`Sidekiq::Job`s are also supported.
|
238
|
+
|
239
|
+
```ruby
|
240
|
+
class ImportantJob
|
241
|
+
include Sidekiq::Job
|
242
|
+
include JobContracts::SidekiqContractable
|
243
|
+
|
244
|
+
sidekiq_options queue: :default
|
245
|
+
add_contract JobContracts::DurationContract.new(max: 1.second)
|
246
|
+
|
247
|
+
def perform
|
248
|
+
# logic...
|
249
|
+
end
|
250
|
+
|
251
|
+
# default callback that's invoked if the contract is breached
|
252
|
+
def contract_breached!(contract)
|
253
|
+
# handle breach...
|
254
|
+
end
|
255
|
+
end
|
256
|
+
```
|
245
257
|
|
246
258
|
## Todo
|
247
259
|
|
@@ -75,11 +75,5 @@ module JobContracts
|
|
75
75
|
def contract_breached!
|
76
76
|
# noop / override in job subclasses
|
77
77
|
end
|
78
|
-
|
79
|
-
def on_contract_breach(contract)
|
80
|
-
breached_contracts << contract
|
81
|
-
method = self.class.on_contract_breach_callback
|
82
|
-
method.is_a?(Proc) ? method.call(contract) : send(method.to_s, contract)
|
83
|
-
end
|
84
78
|
end
|
85
79
|
end
|
@@ -8,54 +8,32 @@ module JobContracts
|
|
8
8
|
extend ActiveSupport::Concern
|
9
9
|
include Contractable
|
10
10
|
|
11
|
-
class SidekiqJobMetadataNotFoundError < StandardError; end
|
12
|
-
|
13
11
|
module ClassMethods
|
12
|
+
# Matches the ActiveJob API
|
14
13
|
def queue_name
|
15
14
|
sidekiq_options_hash["queue"]
|
16
15
|
end
|
17
16
|
end
|
18
17
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
begin
|
23
|
-
attempts ||= 1
|
24
|
-
hit = Sidekiq::Workers.new.find do |_process_id, _thread_id, work|
|
25
|
-
work.dig("payload", "jid") == jid
|
26
|
-
end
|
27
|
-
raise SidekiqJobMetadataNotFoundError if hit.blank?
|
28
|
-
rescue SidekiqJobMetadataNotFoundError
|
29
|
-
# The WorkSet only updates every 5 seconds
|
30
|
-
# SEE: https://github.com/mperham/sidekiq/wiki/API#workers
|
31
|
-
# Re-attempt up to 10 times with a simple backoff strategy (up to 5.5 seconds)
|
32
|
-
# TODO: Is there a faster and more reliable way to fetch the job's metadata after perform has begun?
|
33
|
-
# May need to query Redis directly if the data is still in there at this point
|
34
|
-
attempts += 1
|
35
|
-
if attempts <= 10
|
36
|
-
sleep 0.1 * attempts
|
37
|
-
retry
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
hit&.last || {}
|
42
|
-
end
|
18
|
+
# Metadata used to enqueue the job
|
19
|
+
def sidekiq_job_hash
|
20
|
+
@sidekiq_job_hash ||= {}
|
43
21
|
end
|
44
22
|
|
45
23
|
# Matches the ActiveJob API
|
46
24
|
def queue_name
|
47
|
-
|
25
|
+
sidekiq_job_hash["queue"]
|
48
26
|
end
|
49
27
|
|
50
28
|
# Matches the ActiveJob API
|
51
29
|
def enqueued_at
|
52
|
-
seconds =
|
30
|
+
seconds = sidekiq_job_hash["enqueued_at"]
|
53
31
|
(seconds ? Time.at(seconds) : nil)&.iso8601.to_s
|
54
32
|
end
|
55
33
|
|
56
34
|
# Matches the ActiveJob API
|
57
35
|
def arguments
|
58
|
-
|
36
|
+
sidekiq_job_hash["args"] || []
|
59
37
|
end
|
60
38
|
end
|
61
39
|
end
|
@@ -1,11 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "observer"
|
4
|
-
|
5
3
|
module JobContracts
|
6
4
|
class Contract
|
7
|
-
include Observable
|
8
|
-
|
9
5
|
attr_reader :trigger, :queues
|
10
6
|
|
11
7
|
def initialize(trigger: :after, halt: false, queues: [], expected: {})
|
@@ -32,11 +28,9 @@ module JobContracts
|
|
32
28
|
# NOTE: subclasses should update `actual`, set `satisfied`, and call `super`
|
33
29
|
def enforce!(contractable)
|
34
30
|
return unless should_enforce?(contractable)
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
ensure
|
39
|
-
delete_observer contractable
|
31
|
+
return if satisfied?
|
32
|
+
contractable.breached_contracts << self
|
33
|
+
invoke_contract_breach_callback contractable
|
40
34
|
end
|
41
35
|
|
42
36
|
def satisfied?
|
@@ -73,5 +67,11 @@ module JobContracts
|
|
73
67
|
protected
|
74
68
|
|
75
69
|
attr_accessor :satisfied
|
70
|
+
|
71
|
+
def invoke_contract_breach_callback(contractable)
|
72
|
+
callback = contractable.class.on_contract_breach_callback
|
73
|
+
callback = contractable.method(callback.to_sym) unless callback.is_a?(Proc)
|
74
|
+
callback.call self
|
75
|
+
end
|
76
76
|
end
|
77
77
|
end
|
@@ -1,6 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "sidekiq"
|
4
|
+
require_relative "sidekiq_job_hash_middleware"
|
5
|
+
|
3
6
|
module JobContracts
|
4
7
|
class Railtie < ::Rails::Railtie
|
8
|
+
initializer "job_contracts.register_sidekiq_middleware" do
|
9
|
+
Sidekiq.server_middleware.add SidekiqJobHashMiddleware
|
10
|
+
end
|
5
11
|
end
|
6
12
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: job_contracts
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nathan Hopkins
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-05-
|
11
|
+
date: 2022-05-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -16,42 +16,42 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 6.1.5
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 6.1.5
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: sidekiq
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 6.4.
|
33
|
+
version: 6.4.2
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 6.4.
|
40
|
+
version: 6.4.2
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: standard
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
47
|
+
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
54
|
+
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: magic_frozen_string_literal
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -126,6 +126,7 @@ files:
|
|
126
126
|
- lib/job_contracts/contracts/queue_name_contract.rb
|
127
127
|
- lib/job_contracts/contracts/read_only_contract.rb
|
128
128
|
- lib/job_contracts/railtie.rb
|
129
|
+
- lib/job_contracts/sidekiq_job_hash_middleware.rb
|
129
130
|
- lib/job_contracts/version.rb
|
130
131
|
homepage: https://github.com/hopsoft/job_contracts
|
131
132
|
licenses:
|