services 0.2.8 → 0.2.9
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/lib/services/modules/call_logger.rb +11 -5
- data/lib/services/modules/uniqueness_checker.rb +56 -11
- data/lib/services/version.rb +1 -1
- data/spec/services/base_spec.rb +0 -166
- data/spec/services/modules/call_logger_spec.rb +55 -0
- data/spec/services/modules/exception_wrapper_spec.rb +60 -0
- data/spec/services/modules/uniqueness_checker_spec.rb +96 -0
- data/spec/spec_helper.rb +13 -6
- data/spec/support/call_proxy.rb +11 -0
- data/spec/support/test_services.rb +11 -11
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b6a69a25c27cff265025953ddd3dfaa6f04a4f7e
|
4
|
+
data.tar.gz: fd175797287181892a619c61dd195d1062919ad4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1bb62070e8e679707ab12e04590a80a90e61895f02f2aca643248040f57d60257de7e29bc34dc306f89382f2fbf46c5e918a4e0055a52948f4e8a517c0bfe68c
|
7
|
+
data.tar.gz: 772463884aa0a6ddd64bd5ab83fa311c9881bd4e8156a5fb61253a4ed2c3d0529d5570d842ea99327a92d7adbc42e3f23239d6b05707fe200b8fdccad6a4de87
|
@@ -3,7 +3,7 @@ module Services
|
|
3
3
|
module CallLogger
|
4
4
|
def call(*args)
|
5
5
|
log "START with args #{args}"
|
6
|
-
log "CALLED BY #{caller}"
|
6
|
+
log "CALLED BY #{caller || '(not found)'}"
|
7
7
|
start = Time.now
|
8
8
|
begin
|
9
9
|
result = super
|
@@ -38,10 +38,16 @@ module Services
|
|
38
38
|
end
|
39
39
|
|
40
40
|
def caller
|
41
|
-
caller_location = caller_locations(
|
42
|
-
|
43
|
-
|
44
|
-
|
41
|
+
caller_location = caller_locations(1, 10).detect do |location|
|
42
|
+
location.path !~ /\A#{Regexp.escape File.expand_path('../..', __FILE__)}/
|
43
|
+
end
|
44
|
+
if caller_location.nil?
|
45
|
+
nil
|
46
|
+
else
|
47
|
+
caller_path = caller_location.path
|
48
|
+
caller_path = caller_path.sub(%r(\A#{Regexp.escape Rails.root.to_s}/), '') if defined?(Rails)
|
49
|
+
[caller_path, caller_location.lineno].join(':')
|
50
|
+
end
|
45
51
|
end
|
46
52
|
end
|
47
53
|
end
|
@@ -6,35 +6,66 @@ module Services
|
|
6
6
|
uniqueness
|
7
7
|
).join(':')
|
8
8
|
|
9
|
+
ON_ERROR = %i(
|
10
|
+
fail
|
11
|
+
ignore
|
12
|
+
reschedule
|
13
|
+
)
|
14
|
+
|
15
|
+
MAX_RETRIES = 10
|
16
|
+
ONE_HOUR = 60 * 60
|
17
|
+
|
9
18
|
def self.prepended(mod)
|
10
19
|
mod.const_set :NotUniqueError, Class.new(mod::Error)
|
11
20
|
end
|
12
21
|
|
13
|
-
def check_uniqueness!(*args)
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
if similar_service_id = Services.configuration.redis.get(new_uniqueness_key)
|
20
|
-
|
22
|
+
def check_uniqueness!(*args, on_error: :fail)
|
23
|
+
raise "on_error must be one of #{ON_ERROR.join(', ')}, but was #{on_error}" unless ON_ERROR.include?(on_error.to_sym)
|
24
|
+
raise 'Service args not found.' if @service_args.nil?
|
25
|
+
@uniqueness_args = args.empty? ? @service_args : args
|
26
|
+
new_uniqueness_key = uniqueness_key(@uniqueness_args)
|
27
|
+
raise "A uniqueness key with args #{@uniqueness_args.inspect} already exists." if @uniqueness_keys && @uniqueness_keys.include?(new_uniqueness_key)
|
28
|
+
if @similar_service_id = Services.configuration.redis.get(new_uniqueness_key)
|
29
|
+
case on_error.to_sym
|
30
|
+
when :ignore
|
31
|
+
false
|
32
|
+
when :fail
|
33
|
+
raise_non_unique_error
|
34
|
+
when :reschedule
|
35
|
+
error_count = (Services.configuration.redis.get(error_count_key) || 0).to_i
|
36
|
+
if error_count >= MAX_RETRIES
|
37
|
+
raise_non_unique_error
|
38
|
+
else
|
39
|
+
error_count += 1
|
40
|
+
self.class.perform_in retry_delay(error_count), @service_args
|
41
|
+
Services.configuration.redis.setex error_count_key, retry_delay(error_count) + ONE_HOUR, error_count
|
42
|
+
false
|
43
|
+
end
|
44
|
+
end
|
21
45
|
else
|
22
46
|
@uniqueness_keys ||= []
|
23
|
-
raise "A uniqueness key with args #{args.inspect} already exists." if @uniqueness_keys.include?(new_uniqueness_key)
|
24
47
|
@uniqueness_keys << new_uniqueness_key
|
25
|
-
Services.configuration.redis.setex new_uniqueness_key,
|
48
|
+
Services.configuration.redis.setex new_uniqueness_key, ONE_HOUR, @id
|
49
|
+
true
|
26
50
|
end
|
27
51
|
end
|
28
52
|
|
29
53
|
def call(*args)
|
30
|
-
@
|
54
|
+
@service_args = args
|
31
55
|
super
|
32
56
|
ensure
|
33
57
|
Services.configuration.redis.del @uniqueness_keys unless @uniqueness_keys.nil? || @uniqueness_keys.empty?
|
58
|
+
Services.configuration.redis.del error_count_key
|
34
59
|
end
|
35
60
|
|
36
61
|
private
|
37
62
|
|
63
|
+
def raise_non_unique_error(retried = false)
|
64
|
+
message = "Service #{self.class} #{@id} with uniqueness args #{@uniqueness_args} is not unique, a similar service is already running: #{@similar_service_id}."
|
65
|
+
message << " The service has been retried #{MAX_RETRIES} times."
|
66
|
+
raise self.class::NotUniqueError, message
|
67
|
+
end
|
68
|
+
|
38
69
|
def uniqueness_key(args)
|
39
70
|
[
|
40
71
|
KEY_PREFIX,
|
@@ -43,6 +74,20 @@ module Services
|
|
43
74
|
key << Digest::MD5.hexdigest(args.to_s) unless args.empty?
|
44
75
|
end.join(':')
|
45
76
|
end
|
77
|
+
|
78
|
+
def error_count_key
|
79
|
+
[
|
80
|
+
KEY_PREFIX,
|
81
|
+
'errors',
|
82
|
+
self.class.to_s
|
83
|
+
].tap do |key|
|
84
|
+
key << Digest::MD5.hexdigest(@service_args.to_s) unless @service_args.empty?
|
85
|
+
end.join(':')
|
86
|
+
end
|
87
|
+
|
88
|
+
def retry_delay(error_count)
|
89
|
+
(error_count ** 3) + 5
|
90
|
+
end
|
46
91
|
end
|
47
92
|
end
|
48
93
|
end
|
data/lib/services/version.rb
CHANGED
data/spec/services/base_spec.rb
CHANGED
@@ -58,172 +58,6 @@ describe Services::Base do
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
|
-
if StandardError.new.respond_to?(:cause)
|
62
|
-
context 'wrapping exceptions' do
|
63
|
-
it 'does not wrap service errors or subclasses' do
|
64
|
-
expect do
|
65
|
-
ErrorService.call
|
66
|
-
end.to raise_error do |error|
|
67
|
-
expect(error).to be_a(ErrorService::Error)
|
68
|
-
expect(error.message).to eq('I am a service error.')
|
69
|
-
expect(error.cause).to be_nil
|
70
|
-
end
|
71
|
-
|
72
|
-
class ServiceWithCustomError < Services::Base
|
73
|
-
CustomError = Class.new(self::Error)
|
74
|
-
def call
|
75
|
-
raise CustomError.new('I am a custom error.')
|
76
|
-
end
|
77
|
-
end
|
78
|
-
expect do
|
79
|
-
ServiceWithCustomError.call
|
80
|
-
end.to raise_error do |error|
|
81
|
-
expect(error).to be_a(ServiceWithCustomError::CustomError)
|
82
|
-
expect(error.message).to eq('I am a custom error.')
|
83
|
-
expect(error.cause).to be_nil
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
it 'wraps all other exceptions' do
|
88
|
-
class ServiceWithStandardError < Services::Base
|
89
|
-
def call
|
90
|
-
raise 'I am a StandardError.'
|
91
|
-
end
|
92
|
-
end
|
93
|
-
expect do
|
94
|
-
ServiceWithStandardError.call
|
95
|
-
end.to raise_error do |error|
|
96
|
-
expect(error).to be_a(ServiceWithStandardError::Error)
|
97
|
-
expect(error.message).to eq('I am a StandardError.')
|
98
|
-
expect(error.cause).to be_a(StandardError)
|
99
|
-
expect(error.cause.message).to eq('I am a StandardError.')
|
100
|
-
end
|
101
|
-
|
102
|
-
class ServiceWithCustomStandardError < Services::Base
|
103
|
-
CustomStandardError = Class.new(StandardError)
|
104
|
-
def call
|
105
|
-
raise CustomStandardError, 'I am a custom StandardError.'
|
106
|
-
end
|
107
|
-
end
|
108
|
-
expect do
|
109
|
-
ServiceWithCustomStandardError.call
|
110
|
-
end.to raise_error do |error|
|
111
|
-
expect(error).to be_a(ServiceWithCustomStandardError::Error)
|
112
|
-
expect(error.message).to eq('I am a custom StandardError.')
|
113
|
-
expect(error.cause).to be_a(ServiceWithCustomStandardError::CustomStandardError)
|
114
|
-
expect(error.cause.message).to eq('I am a custom StandardError.')
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
context 'checking for uniqueness' do
|
121
|
-
context 'when the service checks for uniqueness with the default args' do
|
122
|
-
it 'raises an error when the same job is executed multiple times' do
|
123
|
-
wait_for_job_to_run UniqueService do
|
124
|
-
3.times do
|
125
|
-
expect { UniqueService.call }.to raise_error(UniqueService::NotUniqueError)
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
context 'when the service checks for uniqueness with custom args' do
|
132
|
-
it 'raises an error when a job with the same custom args is executed multiple times' do
|
133
|
-
wait_for_job_to_run UniqueWithCustomArgsService, 'foo', 'bar', 'baz' do
|
134
|
-
3.times do
|
135
|
-
expect { UniqueWithCustomArgsService.call('foo', 'bar', 'pelle') }.to raise_error(UniqueWithCustomArgsService::NotUniqueError)
|
136
|
-
end
|
137
|
-
expect { UniqueWithCustomArgsService.call('foo', 'baz', 'pelle') }.to_not raise_error
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
context 'when the service checks for uniqueness multiple times' do
|
143
|
-
let(:args) { %w(foo bar baz) }
|
144
|
-
|
145
|
-
it 'raises an error when one of the checks fails' do
|
146
|
-
wait_for_job_to_run UniqueMultipleService, *args do
|
147
|
-
args.each do |arg|
|
148
|
-
3.times do
|
149
|
-
expect { UniqueMultipleService.call(arg) }.to raise_error(UniqueMultipleService::NotUniqueError)
|
150
|
-
end
|
151
|
-
end
|
152
|
-
expect { UniqueMultipleService.call('pelle') }.to_not raise_error
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
it 'does not leave any Redis keys behind' do
|
157
|
-
expect do
|
158
|
-
wait_for_job_to_run_and_finish UniqueMultipleService, *args do
|
159
|
-
args.each do |arg|
|
160
|
-
UniqueMultipleService.call(arg) rescue nil
|
161
|
-
end
|
162
|
-
UniqueMultipleService.call('pelle')
|
163
|
-
end
|
164
|
-
end.to_not change {
|
165
|
-
Services.configuration.redis.keys("*#{Services::Base::UniquenessChecker::KEY_PREFIX}*").count
|
166
|
-
}
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
context 'when the service was not set to check for uniqueness' do
|
171
|
-
it 'does not raise an error when the same job is executed twice' do
|
172
|
-
wait_for_job_to_run NonUniqueService do
|
173
|
-
expect { NonUniqueService.call }.to_not raise_error
|
174
|
-
end
|
175
|
-
end
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
context 'logging' do
|
180
|
-
it 'logs start with args and end with duration' do
|
181
|
-
service = EmptyService.new
|
182
|
-
logs = []
|
183
|
-
allow(service).to receive(:log) do |message, *|
|
184
|
-
logs << message
|
185
|
-
end
|
186
|
-
service.call 'foo', 'bar'
|
187
|
-
expect(logs.first).to eq('START with args ["foo", "bar"]')
|
188
|
-
expect(logs.last).to eq('END after 0.0 seconds')
|
189
|
-
end
|
190
|
-
|
191
|
-
it 'logs the caller' do
|
192
|
-
service_calling_service, called_service = ServiceCallingService.new, EmptyService.new
|
193
|
-
logs = []
|
194
|
-
allow(called_service).to receive(:log) do |message, *|
|
195
|
-
logs << message
|
196
|
-
end
|
197
|
-
|
198
|
-
# When Rails is not defined, the complete caller path should be logged
|
199
|
-
service_calling_service.call called_service
|
200
|
-
expect(logs).to include(/\ACALLED BY #{Regexp.escape(PROJECT_ROOT.join(SERVICES_PATH).to_s)}:\d+/)
|
201
|
-
|
202
|
-
# When Rails is defined, only the caller path relative to Rails.root is logged
|
203
|
-
class Rails
|
204
|
-
def self.root; PROJECT_ROOT; end
|
205
|
-
end
|
206
|
-
logs = []
|
207
|
-
service_calling_service.call called_service
|
208
|
-
expect(logs).to include(/\ACALLED BY #{Regexp.escape(SERVICES_PATH)}:\d+/)
|
209
|
-
Object.send :remove_const, :Rails
|
210
|
-
end
|
211
|
-
|
212
|
-
if RUBY_VERSION > '2.1'
|
213
|
-
it 'logs exceptions and exception causes' do
|
214
|
-
service = NestedExceptionService.new
|
215
|
-
logs = []
|
216
|
-
allow(service).to receive(:log) do |message, *|
|
217
|
-
logs << message
|
218
|
-
end
|
219
|
-
expect { service.call }.to raise_error(NestedExceptionService::Error)
|
220
|
-
%w(NestedError1 NestedError2).each do |error|
|
221
|
-
expect(logs).to include(/\Acaused by: NestedExceptionService::#{error}/)
|
222
|
-
end
|
223
|
-
end
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
61
|
context 'when executed asynchronously' do
|
228
62
|
it 'finds its own worker' do
|
229
63
|
3.times { OwnWorkerService.perform_async }
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Services::Base::CallLogger do
|
4
|
+
it 'logs start with args and end with duration' do
|
5
|
+
service = EmptyService.new
|
6
|
+
logs = []
|
7
|
+
allow(service).to receive(:log) do |message, *|
|
8
|
+
logs << message
|
9
|
+
end
|
10
|
+
service.call 'foo', 'bar'
|
11
|
+
expect(logs.first).to eq('START with args ["foo", "bar"]')
|
12
|
+
expect(logs.last).to eq('END after 0.0 seconds')
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'logs the caller' do
|
16
|
+
service_calling_service, called_service = ServiceCallingService.new, EmptyService.new
|
17
|
+
logs = []
|
18
|
+
allow(called_service).to receive(:log) do |message, *|
|
19
|
+
logs << message
|
20
|
+
end
|
21
|
+
|
22
|
+
# When Rails is not defined, the complete caller path should be logged
|
23
|
+
service_calling_service.call called_service
|
24
|
+
expect(logs).to include(/\ACALLED BY #{Regexp.escape PROJECT_ROOT.join(TEST_SERVICES_PATH).to_s}:\d+/)
|
25
|
+
|
26
|
+
# When Rails is defined, only the caller path relative to Rails.root is logged
|
27
|
+
class Rails
|
28
|
+
def self.root; PROJECT_ROOT; end
|
29
|
+
end
|
30
|
+
logs = []
|
31
|
+
service_calling_service.call called_service
|
32
|
+
expect(logs).to include(/\ACALLED BY #{Regexp.escape TEST_SERVICES_PATH.to_s}:\d+/)
|
33
|
+
Object.send :remove_const, :Rails
|
34
|
+
|
35
|
+
# Caller paths from services lib folder should be filtered
|
36
|
+
require 'services/call_proxy'
|
37
|
+
logs = []
|
38
|
+
Services::CallProxy.call(called_service, :call)
|
39
|
+
expect(logs).to include(/\ACALLED BY #{Regexp.escape __FILE__}:\d+/)
|
40
|
+
end
|
41
|
+
|
42
|
+
if RUBY_VERSION > '2.1'
|
43
|
+
it 'logs exceptions and exception causes' do
|
44
|
+
service = NestedExceptionService.new
|
45
|
+
logs = []
|
46
|
+
allow(service).to receive(:log) do |message, *|
|
47
|
+
logs << message
|
48
|
+
end
|
49
|
+
expect { service.call }.to raise_error(service.class::Error)
|
50
|
+
%w(NestedError1 NestedError2).each do |error|
|
51
|
+
expect(logs).to include(/\Acaused by: #{service.class}::#{error}/)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Services::Base::ExceptionWrapper do
|
4
|
+
if StandardError.new.respond_to?(:cause)
|
5
|
+
it 'does not wrap service errors or subclasses' do
|
6
|
+
expect do
|
7
|
+
ErrorService.call
|
8
|
+
end.to raise_error do |error|
|
9
|
+
expect(error).to be_a(ErrorService::Error)
|
10
|
+
expect(error.message).to eq('I am a service error.')
|
11
|
+
expect(error.cause).to be_nil
|
12
|
+
end
|
13
|
+
|
14
|
+
class ServiceWithCustomError < Services::Base
|
15
|
+
CustomError = Class.new(self::Error)
|
16
|
+
def call
|
17
|
+
raise CustomError.new('I am a custom error.')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
expect do
|
21
|
+
ServiceWithCustomError.call
|
22
|
+
end.to raise_error do |error|
|
23
|
+
expect(error).to be_a(ServiceWithCustomError::CustomError)
|
24
|
+
expect(error.message).to eq('I am a custom error.')
|
25
|
+
expect(error.cause).to be_nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'wraps all other exceptions' do
|
30
|
+
class ServiceWithStandardError < Services::Base
|
31
|
+
def call
|
32
|
+
raise 'I am a StandardError.'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
expect do
|
36
|
+
ServiceWithStandardError.call
|
37
|
+
end.to raise_error do |error|
|
38
|
+
expect(error).to be_a(ServiceWithStandardError::Error)
|
39
|
+
expect(error.message).to eq('I am a StandardError.')
|
40
|
+
expect(error.cause).to be_a(StandardError)
|
41
|
+
expect(error.cause.message).to eq('I am a StandardError.')
|
42
|
+
end
|
43
|
+
|
44
|
+
class ServiceWithCustomStandardError < Services::Base
|
45
|
+
CustomStandardError = Class.new(StandardError)
|
46
|
+
def call
|
47
|
+
raise CustomStandardError, 'I am a custom StandardError.'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
expect do
|
51
|
+
ServiceWithCustomStandardError.call
|
52
|
+
end.to raise_error do |error|
|
53
|
+
expect(error).to be_a(ServiceWithCustomStandardError::Error)
|
54
|
+
expect(error.message).to eq('I am a custom StandardError.')
|
55
|
+
expect(error.cause).to be_a(ServiceWithCustomStandardError::CustomStandardError)
|
56
|
+
expect(error.cause.message).to eq('I am a custom StandardError.')
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
shared_examples 'checking the uniqueness properly' do
|
4
|
+
it 'notices when the same job is executed multiple times' do
|
5
|
+
# Check that error is raised when on_error is "fail"
|
6
|
+
wait_for_job_to_run_and_finish service, *args, 'fail', true do
|
7
|
+
if defined?(fail_args)
|
8
|
+
3.times do
|
9
|
+
fail_args.each do |fail_arg_group|
|
10
|
+
expect { service.call(*fail_arg_group, 'fail', false) }.to raise_error(service::NotUniqueError)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
if defined?(pass_args)
|
15
|
+
3.times do
|
16
|
+
pass_args.each do |pass_arg_group|
|
17
|
+
expect { service.call(*pass_arg_group, 'fail', false) }.to_not raise_error
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Check that no error is raised when on_error is "ignore"
|
23
|
+
if defined?(fail_args)
|
24
|
+
3.times do
|
25
|
+
fail_args.each do |fail_arg_group|
|
26
|
+
expect { service.call(*fail_arg_group, 'ignore', false) }.to_not raise_error
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
if defined?(pass_args)
|
31
|
+
3.times do
|
32
|
+
pass_args.each do |pass_arg_group|
|
33
|
+
expect { service.call(*pass_arg_group, 'ignore', false) }.to_not raise_error
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Check that service is rescheduled when on_error is "reschedule"
|
39
|
+
if defined?(fail_args)
|
40
|
+
3.times do
|
41
|
+
fail_args.each do |fail_arg_group|
|
42
|
+
expect(service).to receive(:perform_in).with(an_instance_of(Fixnum), fail_arg_group + (['reschedule', false]))
|
43
|
+
service.call(*fail_arg_group, 'reschedule', false)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
if defined?(pass_args)
|
48
|
+
3.times do
|
49
|
+
pass_args.each do |pass_arg_group|
|
50
|
+
expect { service.call(*pass_arg_group, 'reschedule', false) }.to_not raise_error
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe Services::Base::UniquenessChecker do
|
59
|
+
context 'when the service checks for uniqueness with the default args' do
|
60
|
+
it_behaves_like 'checking the uniqueness properly' do
|
61
|
+
let(:service) { UniqueService }
|
62
|
+
let(:args) { [] }
|
63
|
+
let(:fail_args) { [] }
|
64
|
+
let(:keys_after_start) { 1 }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context 'when the service checks for uniqueness with custom args' do
|
69
|
+
it_behaves_like 'checking the uniqueness properly' do
|
70
|
+
let(:service) { UniqueWithCustomArgsService }
|
71
|
+
let(:args) { %w(foo bar baz) }
|
72
|
+
let(:fail_args) { [%w(foo bar pelle)] }
|
73
|
+
let(:pass_args) { [%w(foo baz pelle)] }
|
74
|
+
let(:keys_after_start) { 1 }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context 'when the service checks for uniqueness multiple times' do
|
79
|
+
it_behaves_like 'checking the uniqueness properly' do
|
80
|
+
let(:service) { UniqueMultipleService }
|
81
|
+
let(:args) { %w(foo bar baz) }
|
82
|
+
let(:fail_args) { args.map { |arg| [arg] } }
|
83
|
+
let(:pass_args) { [%w(pelle)] }
|
84
|
+
let(:keys_after_start) { 3 }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context 'when the service does not check for uniqueness' do
|
89
|
+
it_behaves_like 'checking the uniqueness properly' do
|
90
|
+
let(:service) { NonUniqueService }
|
91
|
+
let(:args) { [] }
|
92
|
+
let(:pass_args) { [] }
|
93
|
+
let(:keys_after_start) { 0 }
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -4,15 +4,16 @@ require 'redis'
|
|
4
4
|
require 'sidekiq'
|
5
5
|
|
6
6
|
require_relative '../lib/services'
|
7
|
-
require_relative 'support/helpers'
|
8
7
|
|
9
|
-
|
10
|
-
|
8
|
+
PROJECT_ROOT = Pathname.new(File.expand_path('../..', __FILE__))
|
9
|
+
TEST_SERVICES_PATH = Pathname.new(File.join('spec', 'support', 'test_services.rb'))
|
10
|
+
support_dir = Pathname.new(File.expand_path('../support', __FILE__))
|
11
|
+
log_dir = support_dir.join('log')
|
11
12
|
|
12
|
-
|
13
|
+
CALL_PROXY_SOURCE = support_dir.join('call_proxy.rb')
|
14
|
+
CALL_PROXY_DESTINATION = PROJECT_ROOT.join('lib', 'services', 'call_proxy.rb')
|
13
15
|
|
14
|
-
support_dir
|
15
|
-
log_dir = support_dir.join('log')
|
16
|
+
Dir[support_dir.join('**', '*.rb')].each { |f| require f }
|
16
17
|
|
17
18
|
redis_port = 6379
|
18
19
|
redis_pidfile = support_dir.join('redis.pid')
|
@@ -65,9 +66,15 @@ RSpec.configure do |config|
|
|
65
66
|
pidfile: sidekiq_pidfile
|
66
67
|
}
|
67
68
|
system "bundle exec sidekiq #{options_hash_to_string(sidekiq_options)}"
|
69
|
+
|
70
|
+
# Copy call proxy
|
71
|
+
FileUtils.cp CALL_PROXY_SOURCE, CALL_PROXY_DESTINATION
|
68
72
|
end
|
69
73
|
|
70
74
|
config.after :suite do
|
75
|
+
# Delete call proxy
|
76
|
+
FileUtils.rm CALL_PROXY_DESTINATION
|
77
|
+
|
71
78
|
# Stop Sidekiq
|
72
79
|
system "bundle exec sidekiqctl stop #{sidekiq_pidfile} #{sidekiq_timeout}"
|
73
80
|
while File.exist?(sidekiq_pidfile)
|
@@ -65,31 +65,31 @@ class ServiceCallingService < Services::Base
|
|
65
65
|
end
|
66
66
|
|
67
67
|
class UniqueService < Services::Base
|
68
|
-
def call
|
69
|
-
check_uniqueness!
|
70
|
-
sleep 0.5
|
68
|
+
def call(on_error, sleep)
|
69
|
+
check_uniqueness! on_error: on_error
|
70
|
+
sleep 0.5 if sleep
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
74
|
class UniqueWithCustomArgsService < Services::Base
|
75
|
-
def call(uniqueness_arg1, uniqueness_arg2, ignore_arg)
|
76
|
-
check_uniqueness! uniqueness_arg1, uniqueness_arg2
|
77
|
-
sleep 0.5
|
75
|
+
def call(uniqueness_arg1, uniqueness_arg2, ignore_arg, on_error, sleep)
|
76
|
+
check_uniqueness! uniqueness_arg1, uniqueness_arg2, on_error: on_error
|
77
|
+
sleep 0.5 if sleep
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
81
81
|
class UniqueMultipleService < Services::Base
|
82
|
-
def call(*args)
|
82
|
+
def call(*args, on_error, sleep)
|
83
83
|
args.each do |arg|
|
84
|
-
check_uniqueness! arg
|
84
|
+
check_uniqueness! arg, on_error: on_error
|
85
85
|
end
|
86
|
-
sleep 0.5
|
86
|
+
sleep 0.5 if sleep
|
87
87
|
end
|
88
88
|
end
|
89
89
|
|
90
90
|
class NonUniqueService < Services::Base
|
91
|
-
def call
|
92
|
-
sleep 0.5
|
91
|
+
def call(on_error, sleep)
|
92
|
+
sleep 0.5 if sleep
|
93
93
|
end
|
94
94
|
end
|
95
95
|
|
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: 0.2.
|
4
|
+
version: 0.2.9
|
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-08-
|
11
|
+
date: 2014-08-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -146,7 +146,11 @@ files:
|
|
146
146
|
- lib/services/version.rb
|
147
147
|
- services.gemspec
|
148
148
|
- spec/services/base_spec.rb
|
149
|
+
- spec/services/modules/call_logger_spec.rb
|
150
|
+
- spec/services/modules/exception_wrapper_spec.rb
|
151
|
+
- spec/services/modules/uniqueness_checker_spec.rb
|
149
152
|
- spec/spec_helper.rb
|
153
|
+
- spec/support/call_proxy.rb
|
150
154
|
- spec/support/helpers.rb
|
151
155
|
- spec/support/log/.gitkeep
|
152
156
|
- spec/support/redis-cli
|
@@ -178,7 +182,11 @@ specification_version: 4
|
|
178
182
|
summary: ''
|
179
183
|
test_files:
|
180
184
|
- spec/services/base_spec.rb
|
185
|
+
- spec/services/modules/call_logger_spec.rb
|
186
|
+
- spec/services/modules/exception_wrapper_spec.rb
|
187
|
+
- spec/services/modules/uniqueness_checker_spec.rb
|
181
188
|
- spec/spec_helper.rb
|
189
|
+
- spec/support/call_proxy.rb
|
182
190
|
- spec/support/helpers.rb
|
183
191
|
- spec/support/log/.gitkeep
|
184
192
|
- spec/support/redis-cli
|