services 2.1.0 → 2.2.3
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/lib/services/base.rb +0 -3
- data/lib/services/modules/call_logger.rb +6 -4
- data/lib/services/modules/uniqueness_checker.rb +38 -26
- data/lib/services/version.rb +1 -1
- data/spec/services/modules/uniqueness_checker_spec.rb +39 -18
- data/spec/support/test_services.rb +8 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1e3f42f5b3d4869497acf2e3405f0f278b25582d
|
4
|
+
data.tar.gz: 8c4d047373b919125c3117da284fd345f7a81816
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3c776d68b4a336b6a7a04a0003137a176447d1a13a0061c25d3e78806b2243ee81c1cec2a46951be2713acabef16d734681a911cb81eb2ca4a2667b5ea1ae4df
|
7
|
+
data.tar.gz: 933e0c58c79076b20ab1448b7c6105154703b5aea272ef590d17002d4b092fea4cc5149fd385d1b8d1d6c1af7114fa6446501ef104ac141ec09ed58a4e95a4db
|
data/CHANGELOG.md
CHANGED
data/lib/services/base.rb
CHANGED
@@ -73,9 +73,6 @@ module Services
|
|
73
73
|
|
74
74
|
def controller
|
75
75
|
@controller ||= begin
|
76
|
-
# raise "You must use Rails to use the `controller` helper." unless defined?(Rails)
|
77
|
-
# host = Rails.application.routes.default_url_options[:host] || ActionMailer::Base.default_url_options[:host]
|
78
|
-
# Rails.application.routes.default_url_options[:host]
|
79
76
|
raise 'Please configure host.' if Services.configuration.host.nil?
|
80
77
|
request = ActionDispatch::TestRequest.new
|
81
78
|
request.host = Services.configuration.host
|
@@ -12,16 +12,18 @@ module Services
|
|
12
12
|
end
|
13
13
|
|
14
14
|
module ClassMethods
|
15
|
-
@
|
15
|
+
@_call_logging_disabled = false
|
16
16
|
|
17
|
-
|
17
|
+
def call_logging_disabled
|
18
|
+
@_call_logging_disabled
|
19
|
+
end
|
18
20
|
|
19
21
|
def disable_call_logging
|
20
|
-
@
|
22
|
+
@_call_logging_disabled = true
|
21
23
|
end
|
22
24
|
|
23
25
|
def enable_call_logging
|
24
|
-
@
|
26
|
+
@_call_logging_disabled = false
|
25
27
|
end
|
26
28
|
end
|
27
29
|
|
@@ -10,6 +10,7 @@ module Services
|
|
10
10
|
fail
|
11
11
|
ignore
|
12
12
|
reschedule
|
13
|
+
return
|
13
14
|
)
|
14
15
|
|
15
16
|
MAX_RETRIES = 10
|
@@ -21,45 +22,56 @@ module Services
|
|
21
22
|
|
22
23
|
def check_uniqueness(*args, on_error: :fail)
|
23
24
|
raise "on_error must be one of #{ON_ERROR.join(', ')}, but was #{on_error}" unless ON_ERROR.include?(on_error.to_sym)
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
if @
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
else
|
36
|
-
increase_error_count
|
37
|
-
reschedule
|
38
|
-
end
|
25
|
+
@_on_error = on_error
|
26
|
+
raise 'Service args not found.' if @_service_args.nil?
|
27
|
+
@_uniqueness_args = args.empty? ? @_service_args : args
|
28
|
+
new_uniqueness_key = uniqueness_key(@_uniqueness_args)
|
29
|
+
raise "A uniqueness key with args #{@_uniqueness_args.inspect} already exists." if @_uniqueness_keys && @_uniqueness_keys.include?(new_uniqueness_key)
|
30
|
+
if @_similar_service_id = Services.configuration.redis.get(new_uniqueness_key)
|
31
|
+
if on_error.to_sym == :ignore
|
32
|
+
return false
|
33
|
+
else
|
34
|
+
@_retries_exhausted = on_error.to_sym == :reschedule && error_count >= MAX_RETRIES
|
35
|
+
raise_not_unique_error
|
39
36
|
end
|
40
|
-
false
|
41
37
|
else
|
42
|
-
@
|
43
|
-
@
|
38
|
+
@_uniqueness_keys ||= []
|
39
|
+
@_uniqueness_keys << new_uniqueness_key
|
44
40
|
Services.configuration.redis.setex new_uniqueness_key, ONE_HOUR, @id
|
45
41
|
true
|
46
42
|
end
|
47
43
|
end
|
48
44
|
|
49
45
|
def call(*args)
|
50
|
-
@
|
46
|
+
@_service_args = args
|
51
47
|
super
|
48
|
+
rescue self.class::NotUniqueError => e
|
49
|
+
case @_on_error.to_sym
|
50
|
+
when :fail
|
51
|
+
raise e
|
52
|
+
when :reschedule
|
53
|
+
if @_retries_exhausted
|
54
|
+
raise e
|
55
|
+
else
|
56
|
+
increase_error_count
|
57
|
+
reschedule
|
58
|
+
end
|
59
|
+
when :return
|
60
|
+
return e
|
61
|
+
else
|
62
|
+
raise "Unexpected on_error: #{@_on_error}"
|
63
|
+
end
|
52
64
|
ensure
|
53
|
-
Services.configuration.redis.del @
|
65
|
+
Services.configuration.redis.del @_uniqueness_keys unless @_uniqueness_keys.nil? || @_uniqueness_keys.empty?
|
54
66
|
Services.configuration.redis.del error_count_key
|
55
67
|
end
|
56
68
|
|
57
69
|
private
|
58
70
|
|
59
|
-
def
|
60
|
-
message = "Service #{self.class} #{@id} with uniqueness args #{@
|
61
|
-
message << " The service has been retried #{MAX_RETRIES} times."
|
62
|
-
raise self.class::NotUniqueError
|
71
|
+
def raise_not_unique_error
|
72
|
+
message = "Service #{self.class} #{@id} with uniqueness args #{@_uniqueness_args} is not unique, a similar service is already running: #{@_similar_service_id}."
|
73
|
+
message << " The service has been retried #{MAX_RETRIES} times." if @_retries_exhausted
|
74
|
+
raise self.class::NotUniqueError.new(message)
|
63
75
|
end
|
64
76
|
|
65
77
|
def convert_for_rescheduling(arg)
|
@@ -79,7 +91,7 @@ module Services
|
|
79
91
|
|
80
92
|
def reschedule
|
81
93
|
# Convert service args for rescheduling first
|
82
|
-
reschedule_args = @
|
94
|
+
reschedule_args = @_service_args.map do |arg|
|
83
95
|
convert_for_rescheduling arg
|
84
96
|
end
|
85
97
|
log "Rescheduling to be executed in #{retry_delay} seconds." if self.respond_to?(:log)
|
@@ -109,7 +121,7 @@ module Services
|
|
109
121
|
'errors',
|
110
122
|
self.class.to_s.gsub(':', '_')
|
111
123
|
].tap do |key|
|
112
|
-
key << Digest::MD5.hexdigest(@
|
124
|
+
key << Digest::MD5.hexdigest(@_service_args.to_s) unless @_service_args.empty?
|
113
125
|
end.join(':')
|
114
126
|
end
|
115
127
|
|
data/lib/services/version.rb
CHANGED
@@ -2,52 +2,73 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
shared_examples 'checking the uniqueness properly' do
|
4
4
|
it 'notices when the same job is executed multiple times' do
|
5
|
-
wait_for_job_to_run_and_finish
|
5
|
+
wait_for_job_to_run_and_finish service_class, *args, 'fail', true do
|
6
6
|
# Check that error is raised when on_error is "fail"
|
7
|
+
puts 'Checking on_error = fail'
|
7
8
|
if defined?(fail_args)
|
9
|
+
puts "* with fail args #{fail_args}"
|
8
10
|
3.times do
|
9
11
|
fail_args.each do |fail_arg_group|
|
10
|
-
|
12
|
+
service = service_class.new
|
13
|
+
expect(service).to_not receive(:do_work)
|
14
|
+
expect { service.call(*fail_arg_group, 'fail', false) }.to raise_error(service_class::NotUniqueError)
|
11
15
|
end
|
12
16
|
end
|
13
17
|
end
|
14
18
|
if defined?(pass_args)
|
19
|
+
puts "* with pass args #{pass_args}"
|
15
20
|
3.times do
|
16
21
|
pass_args.each do |pass_arg_group|
|
22
|
+
service = service_class.new
|
23
|
+
expect(service).to receive(:do_work)
|
17
24
|
expect { service.call(*pass_arg_group, 'fail', false) }.to_not raise_error
|
18
25
|
end
|
19
26
|
end
|
20
27
|
end
|
21
28
|
|
22
29
|
# Check that no error is raised when on_error is "ignore"
|
30
|
+
puts 'Checking on_error = ignore'
|
23
31
|
if defined?(fail_args)
|
32
|
+
puts "* with fail args #{fail_args}"
|
24
33
|
3.times do
|
25
34
|
fail_args.each do |fail_arg_group|
|
35
|
+
service = service_class.new
|
36
|
+
expect(service).to receive(:do_work)
|
26
37
|
expect { service.call(*fail_arg_group, 'ignore', false) }.to_not raise_error
|
27
38
|
end
|
28
39
|
end
|
29
40
|
end
|
30
41
|
if defined?(pass_args)
|
42
|
+
puts "* with pass args #{pass_args}"
|
31
43
|
3.times do
|
32
44
|
pass_args.each do |pass_arg_group|
|
45
|
+
service = service_class.new
|
46
|
+
expect(service).to receive(:do_work)
|
33
47
|
expect { service.call(*pass_arg_group, 'ignore', false) }.to_not raise_error
|
34
48
|
end
|
35
49
|
end
|
36
50
|
end
|
37
51
|
|
38
52
|
# Check that service is rescheduled when on_error is "reschedule"
|
53
|
+
puts 'Checking on_error = reschedule'
|
39
54
|
if defined?(fail_args)
|
55
|
+
puts "* with fail args #{fail_args}"
|
40
56
|
3.times do
|
41
57
|
fail_args.each do |fail_arg_group|
|
42
|
-
|
58
|
+
service = service_class.new
|
59
|
+
expect(service).to_not receive(:do_work)
|
60
|
+
expect(service_class).to receive(:perform_in).with(an_instance_of(Fixnum), *fail_arg_group, 'reschedule', false)
|
43
61
|
expect { service.call(*fail_arg_group, 'reschedule', false) }.to_not raise_error
|
44
62
|
end
|
45
63
|
end
|
46
64
|
end
|
47
65
|
if defined?(pass_args)
|
66
|
+
puts "* with pass args #{pass_args}"
|
48
67
|
3.times do
|
49
68
|
pass_args.each do |pass_arg_group|
|
50
|
-
|
69
|
+
service = service_class.new
|
70
|
+
expect(service).to receive(:do_work)
|
71
|
+
expect(service_class).to_not receive(:perform_in)
|
51
72
|
expect { service.call(*pass_arg_group, 'reschedule', false) }.to_not raise_error
|
52
73
|
end
|
53
74
|
end
|
@@ -63,35 +84,35 @@ end
|
|
63
84
|
describe Services::Base::UniquenessChecker do
|
64
85
|
context 'when the service checks for uniqueness with the default args' do
|
65
86
|
it_behaves_like 'checking the uniqueness properly' do
|
66
|
-
let(:
|
67
|
-
let(:args)
|
68
|
-
let(:fail_args)
|
87
|
+
let(:service_class) { UniqueService }
|
88
|
+
let(:args) { [] }
|
89
|
+
let(:fail_args) { [] }
|
69
90
|
end
|
70
91
|
end
|
71
92
|
|
72
93
|
context 'when the service checks for uniqueness with custom args' do
|
73
94
|
it_behaves_like 'checking the uniqueness properly' do
|
74
|
-
let(:
|
75
|
-
let(:args)
|
76
|
-
let(:fail_args)
|
77
|
-
let(:pass_args)
|
95
|
+
let(:service_class) { UniqueWithCustomArgsService }
|
96
|
+
let(:args) { ['foo', 1, 'bar'] }
|
97
|
+
let(:fail_args) { [['foo', 1, 'pelle']] }
|
98
|
+
let(:pass_args) { [['foo', 2, 'bar']] }
|
78
99
|
end
|
79
100
|
end
|
80
101
|
|
81
102
|
context 'when the service checks for uniqueness multiple times' do
|
82
103
|
it_behaves_like 'checking the uniqueness properly' do
|
83
|
-
let(:
|
84
|
-
let(:args)
|
85
|
-
let(:fail_args)
|
86
|
-
let(:pass_args)
|
104
|
+
let(:service_class) { UniqueMultipleService }
|
105
|
+
let(:args) { ['foo', 1, true] }
|
106
|
+
let(:fail_args) { args.map { |arg| [arg] } }
|
107
|
+
let(:pass_args) { [['pelle']] }
|
87
108
|
end
|
88
109
|
end
|
89
110
|
|
90
111
|
context 'when the service does not check for uniqueness' do
|
91
112
|
it_behaves_like 'checking the uniqueness properly' do
|
92
|
-
let(:
|
93
|
-
let(:args)
|
94
|
-
let(:pass_args)
|
113
|
+
let(:service_class) { NonUniqueService }
|
114
|
+
let(:args) { [] }
|
115
|
+
let(:pass_args) { [] }
|
95
116
|
end
|
96
117
|
end
|
97
118
|
end
|
@@ -117,15 +117,19 @@ end
|
|
117
117
|
class UniqueService < Services::Base
|
118
118
|
def call(on_error, sleep)
|
119
119
|
check_uniqueness on_error: on_error
|
120
|
+
do_work
|
120
121
|
sleep 0.5 if sleep
|
121
122
|
end
|
123
|
+
def do_work; end
|
122
124
|
end
|
123
125
|
|
124
126
|
class UniqueWithCustomArgsService < Services::Base
|
125
127
|
def call(uniqueness_arg1, uniqueness_arg2, ignore_arg, on_error, sleep)
|
126
128
|
check_uniqueness uniqueness_arg1, uniqueness_arg2, on_error: on_error
|
129
|
+
do_work
|
127
130
|
sleep 0.5 if sleep
|
128
131
|
end
|
132
|
+
def do_work; end
|
129
133
|
end
|
130
134
|
|
131
135
|
class UniqueMultipleService < Services::Base
|
@@ -133,14 +137,18 @@ class UniqueMultipleService < Services::Base
|
|
133
137
|
args.each do |arg|
|
134
138
|
check_uniqueness arg, on_error: on_error
|
135
139
|
end
|
140
|
+
do_work
|
136
141
|
sleep 0.5 if sleep
|
137
142
|
end
|
143
|
+
def do_work; end
|
138
144
|
end
|
139
145
|
|
140
146
|
class NonUniqueService < Services::Base
|
141
147
|
def call(on_error, sleep)
|
148
|
+
do_work
|
142
149
|
sleep 0.5 if sleep
|
143
150
|
end
|
151
|
+
def do_work; end
|
144
152
|
end
|
145
153
|
|
146
154
|
class NestedExceptionService < Services::Base
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: services
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Manuel Meurer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-11-
|
11
|
+
date: 2014-11-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|