services 0.1.2 → 0.1.7
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/.travis.yml +1 -1
- data/lib/services/asyncable.rb +5 -4
- data/lib/services/base.rb +2 -3
- data/lib/services/version.rb +1 -1
- data/services.gemspec +4 -4
- data/spec/services/base_spec.rb +80 -54
- data/spec/spec_helper.rb +10 -8
- data/spec/support/helpers.rb +17 -0
- data/spec/support/test_services.rb +24 -2
- metadata +23 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 81eb2b7ac07028e41e889899270a9c0144f91443
|
4
|
+
data.tar.gz: 1464d7a79faba0c979904f3620770c791fbbcca3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 79a292567b259d7bbc5781752da14923376dd005f01cf31eb81a6a7c6fe37d8f978c1a369c4588e622c65a2d329bac1e0f1f52a28e13560864c9061e44289374
|
7
|
+
data.tar.gz: 6b5f428b5b1acc15a6f35437cbb52bf6c36009ba1866fb8956b308fb130e5466fc77af9ac016e13ba99eb6fb2f68a9b01efeee6e92570a033eb311947b2cee1d
|
data/.travis.yml
CHANGED
data/lib/services/asyncable.rb
CHANGED
@@ -2,6 +2,7 @@ require 'active_support/concern'
|
|
2
2
|
|
3
3
|
begin
|
4
4
|
require 'sidekiq'
|
5
|
+
require 'sidekiq/api'
|
5
6
|
rescue LoadError
|
6
7
|
raise Services::BackgroundProcessorNotFound
|
7
8
|
end
|
@@ -58,17 +59,17 @@ module Services
|
|
58
59
|
@own_worker = if self.jid.nil?
|
59
60
|
nil
|
60
61
|
else
|
61
|
-
own_worker = Sidekiq::Workers.new.detect do |_,
|
62
|
+
own_worker = Sidekiq::Workers.new.detect do |_, _, work|
|
62
63
|
work['payload']['jid'] == self.jid
|
63
64
|
end
|
64
|
-
raise self.class::Error, "Could not find own worker with jid #{self.jid}: #{Sidekiq::Workers.new.map{ |*args| args }}" if own_worker.nil?
|
65
|
+
raise self.class::Error, "Could not find own worker with jid #{self.jid}: #{Sidekiq::Workers.new.map { |*args| args }}" if own_worker.nil?
|
65
66
|
own_worker
|
66
67
|
end
|
67
68
|
end
|
68
69
|
|
69
70
|
def sibling_workers
|
70
|
-
@sibling_workers ||= Sidekiq::Workers.new.select do |_,
|
71
|
-
work['payload']['class'] == self.class.to_s && (own_worker.nil? || work['payload']['jid'] != own_worker[
|
71
|
+
@sibling_workers ||= Sidekiq::Workers.new.select do |_, _, work|
|
72
|
+
work['payload']['class'] == self.class.to_s && (own_worker.nil? || work['payload']['jid'] != own_worker[2]['payload']['jid'])
|
72
73
|
end
|
73
74
|
end
|
74
75
|
end
|
data/lib/services/base.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'nesty'
|
2
1
|
require 'securerandom'
|
3
2
|
require 'action_dispatch'
|
4
3
|
require 'digest'
|
@@ -7,10 +6,10 @@ module Services
|
|
7
6
|
class Base
|
8
7
|
class << self
|
9
8
|
def inherited(subclass)
|
10
|
-
subclass.const_set :Error, Class.new(
|
9
|
+
subclass.const_set :Error, Class.new(StandardError)
|
11
10
|
subclass.send :include, Rails.application.routes.url_helpers if defined?(Rails)
|
12
11
|
subclass.send :include, Asyncable if defined?(Asyncable)
|
13
|
-
subclass.send :prepend, CallLogger,
|
12
|
+
subclass.send :prepend, CallLogger, UniquenessChecker
|
14
13
|
end
|
15
14
|
|
16
15
|
delegate :call, to: :new
|
data/lib/services/version.rb
CHANGED
data/services.gemspec
CHANGED
@@ -13,7 +13,7 @@ Gem::Specification.new do |gem|
|
|
13
13
|
gem.email = 'manuel@krautcomputing.com'
|
14
14
|
gem.summary = ''
|
15
15
|
gem.description = ''
|
16
|
-
gem.homepage = ''
|
16
|
+
gem.homepage = 'http://krautcomputing.github.io/services'
|
17
17
|
gem.license = 'MIT'
|
18
18
|
|
19
19
|
gem.files = `git ls-files`.split($/)
|
@@ -23,10 +23,10 @@ Gem::Specification.new do |gem|
|
|
23
23
|
|
24
24
|
gem.add_development_dependency 'rake'
|
25
25
|
gem.add_development_dependency 'guard-rspec', '~> 4.2'
|
26
|
-
gem.add_development_dependency 'rspec', '
|
26
|
+
gem.add_development_dependency 'rspec', '~> 3.0'
|
27
27
|
gem.add_development_dependency 'sidekiq', '~> 3.0'
|
28
28
|
gem.add_development_dependency 'redis', '~> 3.0'
|
29
|
+
gem.add_development_dependency 'tries', '~> 0.3'
|
29
30
|
gem.add_runtime_dependency 'rails', '>= 3.0.0'
|
30
|
-
gem.add_runtime_dependency 'gem_config', '~> 0.3
|
31
|
-
gem.add_runtime_dependency 'nesty', '~> 1.0.2'
|
31
|
+
gem.add_runtime_dependency 'gem_config', '~> 0.3'
|
32
32
|
end
|
data/spec/services/base_spec.rb
CHANGED
@@ -1,64 +1,66 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Services::Base do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
class ServiceWithError < Services::Base
|
5
|
+
def call
|
6
|
+
raise Error.new('I am a service error.')
|
7
|
+
end
|
8
|
+
end
|
9
|
+
if ServiceWithError::Error.new.respond_to?(:cause)
|
10
|
+
context 'wrapping exceptions' do
|
11
|
+
it 'does not wrap service errors or subclasses' do
|
12
|
+
expect do
|
13
|
+
ServiceWithError.call
|
14
|
+
end.to raise_error do |error|
|
15
|
+
expect(error).to be_a(ServiceWithError::Error)
|
16
|
+
expect(error.message).to eq('I am a service error.')
|
17
|
+
expect(error.cause).to be_nil
|
9
18
|
end
|
10
|
-
end
|
11
|
-
expect do
|
12
|
-
ServiceWithError.call
|
13
|
-
end.to raise_error do |error|
|
14
|
-
expect(error).to be_a(ServiceWithError::Error)
|
15
|
-
expect(error.message).to eq('I am a service error.')
|
16
|
-
expect(error.nested).to be_nil
|
17
|
-
end
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
class ServiceWithCustomError < Services::Base
|
21
|
+
CustomError = Class.new(self::Error)
|
22
|
+
def call
|
23
|
+
raise CustomError.new('I am a custom error.')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
expect do
|
27
|
+
ServiceWithCustomError.call
|
28
|
+
end.to raise_error do |error|
|
29
|
+
expect(error).to be_a(ServiceWithCustomError::CustomError)
|
30
|
+
expect(error.message).to eq('I am a custom error.')
|
31
|
+
expect(error.cause).to be_nil
|
23
32
|
end
|
24
33
|
end
|
25
|
-
expect do
|
26
|
-
ServiceWithCustomError.call
|
27
|
-
end.to raise_error do |error|
|
28
|
-
expect(error).to be_a(ServiceWithCustomError::CustomError)
|
29
|
-
expect(error.message).to eq('I am a custom error.')
|
30
|
-
expect(error.nested).to be_nil
|
31
|
-
end
|
32
|
-
end
|
33
34
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
35
|
+
it 'wraps all other exceptions' do
|
36
|
+
class ServiceWithStandardError < Services::Base
|
37
|
+
def call
|
38
|
+
raise 'I am a StandardError.'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
expect do
|
42
|
+
ServiceWithStandardError.call
|
43
|
+
end.to raise_error do |error|
|
44
|
+
expect(error).to be_a(ServiceWithStandardError::Error)
|
45
|
+
expect(error.message).to eq('I am a StandardError.')
|
46
|
+
expect(error.cause).to be_a(StandardError)
|
47
|
+
expect(error.cause.message).to eq('I am a StandardError.')
|
38
48
|
end
|
39
|
-
end
|
40
|
-
expect do
|
41
|
-
ServiceWithStandardError.call
|
42
|
-
end.to raise_error do |error|
|
43
|
-
expect(error).to be_a(ServiceWithStandardError::Error)
|
44
|
-
expect(error.message).to eq('I am a StandardError.')
|
45
|
-
expect(error.nested).to be_a(StandardError)
|
46
|
-
expect(error.nested.message).to eq('I am a StandardError.')
|
47
|
-
end
|
48
49
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
50
|
+
class ServiceWithCustomStandardError < Services::Base
|
51
|
+
CustomStandardError = Class.new(StandardError)
|
52
|
+
def call
|
53
|
+
raise CustomStandardError, 'I am a custom StandardError.'
|
54
|
+
end
|
55
|
+
end
|
56
|
+
expect do
|
57
|
+
ServiceWithCustomStandardError.call
|
58
|
+
end.to raise_error do |error|
|
59
|
+
expect(error).to be_a(ServiceWithCustomStandardError::Error)
|
60
|
+
expect(error.message).to eq('I am a custom StandardError.')
|
61
|
+
expect(error.cause).to be_a(ServiceWithCustomStandardError::CustomStandardError)
|
62
|
+
expect(error.cause.message).to eq('I am a custom StandardError.')
|
53
63
|
end
|
54
|
-
end
|
55
|
-
expect do
|
56
|
-
ServiceWithCustomStandardError.call
|
57
|
-
end.to raise_error do |error|
|
58
|
-
expect(error).to be_a(ServiceWithCustomStandardError::Error)
|
59
|
-
expect(error.message).to eq('I am a custom StandardError.')
|
60
|
-
expect(error.nested).to be_a(ServiceWithCustomStandardError::CustomStandardError)
|
61
|
-
expect(error.nested.message).to eq('I am a custom StandardError.')
|
62
64
|
end
|
63
65
|
end
|
64
66
|
end
|
@@ -66,8 +68,7 @@ describe Services::Base do
|
|
66
68
|
context 'checking for uniqueness' do
|
67
69
|
context 'when the service was set to check for uniqueness' do
|
68
70
|
it 'raises an error when the same job is executed twice' do
|
69
|
-
UniqueService.perform_async
|
70
|
-
sleep 0.5 # Wait for Sidekiq to start processing the job
|
71
|
+
wait_for_job_to_run UniqueService.perform_async
|
71
72
|
expect do
|
72
73
|
UniqueService.call
|
73
74
|
end.to raise_error(UniqueService::NotUniqueError)
|
@@ -76,12 +77,37 @@ describe Services::Base do
|
|
76
77
|
|
77
78
|
context 'when the service was not set to check for uniqueness' do
|
78
79
|
it 'does not raise an error when the same job is executed twice' do
|
79
|
-
NonUniqueService.perform_async
|
80
|
-
sleep 0.5 # Wait for Sidekiq to start processing the job
|
80
|
+
wait_for_job_to_run NonUniqueService.perform_async
|
81
81
|
expect do
|
82
82
|
NonUniqueService.call
|
83
83
|
end.to_not raise_error
|
84
84
|
end
|
85
85
|
end
|
86
86
|
end
|
87
|
+
|
88
|
+
context 'when executed asynchronously' do
|
89
|
+
it 'finds its own worker' do
|
90
|
+
3.times do
|
91
|
+
OwnWorkerService.perform_async
|
92
|
+
end
|
93
|
+
jid = OwnWorkerService.perform_async
|
94
|
+
own_worker_data = wait_for { Services.configuration.redis.get(jid) }
|
95
|
+
own_worker_json = JSON.parse(own_worker_data)
|
96
|
+
expect(own_worker_json[2]['payload']['jid']).to eq(jid)
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'finds its sibling workers' do
|
100
|
+
sibling_worker_jids = (1..3).map do
|
101
|
+
SiblingWorkersService.perform_async
|
102
|
+
end
|
103
|
+
jid = SiblingWorkersService.perform_async
|
104
|
+
sibling_worker_data = wait_for { Services.configuration.redis.get(jid) }
|
105
|
+
sibling_worker_json = JSON.parse(sibling_worker_data)
|
106
|
+
expect(sibling_worker_json.size).to eq(3)
|
107
|
+
expected_sibling_worker_jids = sibling_worker_json.map do |_, _, work|
|
108
|
+
work['payload']['jid']
|
109
|
+
end
|
110
|
+
expect(expected_sibling_worker_jids).to match_array(sibling_worker_jids)
|
111
|
+
end
|
112
|
+
end
|
87
113
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
require 'rspec'
|
2
|
+
require 'tries'
|
2
3
|
require 'redis'
|
3
4
|
require 'sidekiq'
|
4
5
|
require_relative '../lib/services'
|
5
6
|
require_relative 'support/test_services'
|
7
|
+
require_relative 'support/helpers'
|
6
8
|
|
7
9
|
support_dir = Pathname.new(File.expand_path('../support', __FILE__))
|
8
10
|
log_dir = support_dir.join('logs')
|
@@ -12,7 +14,7 @@ redis_pidfile = support_dir.join('redis.pid')
|
|
12
14
|
redis_url = "redis://localhost:#{redis_port}/0"
|
13
15
|
|
14
16
|
sidekiq_pidfile = support_dir.join('sidekiq.pid')
|
15
|
-
sidekiq_timeout =
|
17
|
+
sidekiq_timeout = 20
|
16
18
|
|
17
19
|
Services.configure do |config|
|
18
20
|
config.redis = Redis.new
|
@@ -44,11 +46,11 @@ RSpec.configure do |config|
|
|
44
46
|
}
|
45
47
|
redis = support_dir.join('redis-server')
|
46
48
|
# TODO: Redis should be started here unless Rspec is executed by Travis CI
|
47
|
-
|
49
|
+
system "#{redis} #{options_hash_to_string(redis_options)}"
|
48
50
|
|
49
51
|
# Start Sidekiq
|
50
52
|
sidekiq_options = {
|
51
|
-
concurrency:
|
53
|
+
concurrency: 10,
|
52
54
|
daemon: true,
|
53
55
|
timeout: sidekiq_timeout,
|
54
56
|
verbose: true,
|
@@ -70,11 +72,11 @@ RSpec.configure do |config|
|
|
70
72
|
# Stop Redis
|
71
73
|
redis_cli = support_dir.join('redis-cli')
|
72
74
|
# TODO: Redis should be stopped here unless Rspec is executed by Travis CI
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
75
|
+
system "#{redis_cli} -p #{redis_port} shutdown"
|
76
|
+
while File.exist?(redis_pidfile)
|
77
|
+
puts 'Waiting for Redis to shut down...'
|
78
|
+
sleep 1
|
79
|
+
end
|
78
80
|
|
79
81
|
# Truncate log files
|
80
82
|
max_len = 1024 * 1024 # 1 MB
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'sidekiq/api'
|
2
|
+
|
3
|
+
ExpectedDataNotFoundError = Class.new(StandardError)
|
4
|
+
|
5
|
+
def wait_for(&block)
|
6
|
+
10.tries on: ExpectedDataNotFoundError, delay: 0.1 do
|
7
|
+
block.call or raise ExpectedDataNotFoundError
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def wait_for_job_to_run(jid)
|
12
|
+
wait_for do
|
13
|
+
Sidekiq::Workers.new.any? do |_, _, work|
|
14
|
+
work['payload']['jid'] == jid
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -2,12 +2,34 @@ class UniqueService < Services::Base
|
|
2
2
|
check_uniqueness!
|
3
3
|
|
4
4
|
def call
|
5
|
-
sleep
|
5
|
+
sleep 0.5
|
6
6
|
end
|
7
7
|
end
|
8
8
|
|
9
9
|
class NonUniqueService < Services::Base
|
10
10
|
def call
|
11
|
-
sleep
|
11
|
+
sleep 0.5
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class OwnWorkerService < Services::Base
|
16
|
+
def call
|
17
|
+
if own_worker.nil?
|
18
|
+
logger.error 'Could not find own worker!'
|
19
|
+
else
|
20
|
+
Services.configuration.redis.set self.jid, own_worker.to_json
|
21
|
+
end
|
22
|
+
sleep 0.5
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class SiblingWorkersService < Services::Base
|
27
|
+
def call
|
28
|
+
if sibling_workers.empty?
|
29
|
+
logger.info 'No sibling workers found.'
|
30
|
+
else
|
31
|
+
Services.configuration.redis.set self.jid, sibling_workers.to_json
|
32
|
+
end
|
33
|
+
sleep 0.5
|
12
34
|
end
|
13
35
|
end
|
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.1.
|
4
|
+
version: 0.1.7
|
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
|
+
date: 2014-07-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -42,22 +42,16 @@ dependencies:
|
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: 3.0.0.rc1
|
48
|
-
- - <
|
45
|
+
- - ~>
|
49
46
|
- !ruby/object:Gem::Version
|
50
|
-
version: '
|
47
|
+
version: '3.0'
|
51
48
|
type: :development
|
52
49
|
prerelease: false
|
53
50
|
version_requirements: !ruby/object:Gem::Requirement
|
54
51
|
requirements:
|
55
|
-
- -
|
56
|
-
- !ruby/object:Gem::Version
|
57
|
-
version: 3.0.0.rc1
|
58
|
-
- - <
|
52
|
+
- - ~>
|
59
53
|
- !ruby/object:Gem::Version
|
60
|
-
version: '
|
54
|
+
version: '3.0'
|
61
55
|
- !ruby/object:Gem::Dependency
|
62
56
|
name: sidekiq
|
63
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -87,47 +81,47 @@ dependencies:
|
|
87
81
|
- !ruby/object:Gem::Version
|
88
82
|
version: '3.0'
|
89
83
|
- !ruby/object:Gem::Dependency
|
90
|
-
name:
|
84
|
+
name: tries
|
91
85
|
requirement: !ruby/object:Gem::Requirement
|
92
86
|
requirements:
|
93
|
-
- -
|
87
|
+
- - ~>
|
94
88
|
- !ruby/object:Gem::Version
|
95
|
-
version:
|
96
|
-
type: :
|
89
|
+
version: '0.3'
|
90
|
+
type: :development
|
97
91
|
prerelease: false
|
98
92
|
version_requirements: !ruby/object:Gem::Requirement
|
99
93
|
requirements:
|
100
|
-
- -
|
94
|
+
- - ~>
|
101
95
|
- !ruby/object:Gem::Version
|
102
|
-
version:
|
96
|
+
version: '0.3'
|
103
97
|
- !ruby/object:Gem::Dependency
|
104
|
-
name:
|
98
|
+
name: rails
|
105
99
|
requirement: !ruby/object:Gem::Requirement
|
106
100
|
requirements:
|
107
|
-
- -
|
101
|
+
- - '>='
|
108
102
|
- !ruby/object:Gem::Version
|
109
|
-
version: 0.
|
103
|
+
version: 3.0.0
|
110
104
|
type: :runtime
|
111
105
|
prerelease: false
|
112
106
|
version_requirements: !ruby/object:Gem::Requirement
|
113
107
|
requirements:
|
114
|
-
- -
|
108
|
+
- - '>='
|
115
109
|
- !ruby/object:Gem::Version
|
116
|
-
version: 0.
|
110
|
+
version: 3.0.0
|
117
111
|
- !ruby/object:Gem::Dependency
|
118
|
-
name:
|
112
|
+
name: gem_config
|
119
113
|
requirement: !ruby/object:Gem::Requirement
|
120
114
|
requirements:
|
121
115
|
- - ~>
|
122
116
|
- !ruby/object:Gem::Version
|
123
|
-
version:
|
117
|
+
version: '0.3'
|
124
118
|
type: :runtime
|
125
119
|
prerelease: false
|
126
120
|
version_requirements: !ruby/object:Gem::Requirement
|
127
121
|
requirements:
|
128
122
|
- - ~>
|
129
123
|
- !ruby/object:Gem::Version
|
130
|
-
version:
|
124
|
+
version: '0.3'
|
131
125
|
description: ''
|
132
126
|
email: manuel@krautcomputing.com
|
133
127
|
executables: []
|
@@ -153,11 +147,12 @@ files:
|
|
153
147
|
- services.gemspec
|
154
148
|
- spec/services/base_spec.rb
|
155
149
|
- spec/spec_helper.rb
|
150
|
+
- spec/support/helpers.rb
|
156
151
|
- spec/support/logs/.gitkeep
|
157
152
|
- spec/support/redis-cli
|
158
153
|
- spec/support/redis-server
|
159
154
|
- spec/support/test_services.rb
|
160
|
-
homepage:
|
155
|
+
homepage: http://krautcomputing.github.io/services
|
161
156
|
licenses:
|
162
157
|
- MIT
|
163
158
|
metadata: {}
|
@@ -184,6 +179,7 @@ summary: ''
|
|
184
179
|
test_files:
|
185
180
|
- spec/services/base_spec.rb
|
186
181
|
- spec/spec_helper.rb
|
182
|
+
- spec/support/helpers.rb
|
187
183
|
- spec/support/logs/.gitkeep
|
188
184
|
- spec/support/redis-cli
|
189
185
|
- spec/support/redis-server
|