remote_service 0.1.2 → 0.2.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/.codeclimate.yml +19 -0
- data/.rubocop.yml +1156 -0
- data/.travis.yml +5 -1
- data/Gemfile.lock +2 -2
- data/LICENSE.txt +1 -1
- data/README.md +4 -1
- data/examples/client.rb +5 -4
- data/examples/service_a.rb +2 -1
- data/lib/remote_service/call.rb +1 -1
- data/lib/remote_service/connector/nats.rb +4 -4
- data/lib/remote_service/queue.rb +32 -14
- data/lib/remote_service/service.rb +2 -2
- data/lib/remote_service/version.rb +1 -1
- data/lib/remote_service/worker_pool.rb +61 -0
- data/lib/remote_service.rb +2 -1
- metadata +4 -1
data/.travis.yml
CHANGED
data/Gemfile.lock
CHANGED
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# RemoteService  [](https://badge.fury.io/rb/remote_service)
|
1
|
+
# RemoteService  [](https://codeclimate.com/github/marekgalovic/ruby-remote-service) [](https://badge.fury.io/rb/remote_service)
|
2
2
|
Remote services made easy. This gem is basically RPC client/server implemented on top of awesome [NATS](http://nats.io/) project. Every service you want to use is exposed through class that extends `RemoteService::Proxy`. Service itself extends `RemoteService::Service` and should define all methods that you want to call from clients.
|
3
3
|
|
4
4
|
## Installation
|
@@ -59,6 +59,9 @@ sleep(0.1) # wait for non-blocking call to execute
|
|
59
59
|
puts ServiceA.all(123, keyword: 'value')
|
60
60
|
```
|
61
61
|
|
62
|
+
# Todo
|
63
|
+
Service worker threads
|
64
|
+
|
62
65
|
## Contributing
|
63
66
|
|
64
67
|
Bug reports and pull requests are welcome on GitHub at https://github.com/marekgalovic/ruby-remote-service. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
data/examples/client.rb
CHANGED
@@ -4,7 +4,7 @@ require "bundler/setup"
|
|
4
4
|
require "remote_service"
|
5
5
|
|
6
6
|
class ServiceA < RemoteService::Proxy
|
7
|
-
timeout
|
7
|
+
timeout 1000
|
8
8
|
end
|
9
9
|
|
10
10
|
class ServiceB < RemoteService::Proxy
|
@@ -14,13 +14,14 @@ end
|
|
14
14
|
RemoteService.logger.level = Logger::DEBUG
|
15
15
|
RemoteService.connect(brokers: ['nats://127.0.0.1:4222', 'nats://127.0.0.1:5222', 'nats://127.0.0.1:6222'])
|
16
16
|
|
17
|
+
|
17
18
|
clients = []
|
18
|
-
|
19
|
+
16.times do
|
19
20
|
clients << Thread.new do
|
20
21
|
loop do
|
21
22
|
ServiceA.all(123, keyword: 'value')
|
22
|
-
ServiceB.users
|
23
|
-
sleep(
|
23
|
+
# ServiceB.users
|
24
|
+
sleep(1)
|
24
25
|
end
|
25
26
|
end
|
26
27
|
end
|
data/examples/service_a.rb
CHANGED
data/lib/remote_service/call.rb
CHANGED
@@ -17,7 +17,7 @@ module RemoteService
|
|
17
17
|
private
|
18
18
|
|
19
19
|
def call_service
|
20
|
-
|
20
|
+
Queue.instance.request(queue, {action: action, params: params}) do |response|
|
21
21
|
yield(response['result'], response['error'])
|
22
22
|
end
|
23
23
|
end
|
@@ -5,7 +5,7 @@ module RemoteService
|
|
5
5
|
class Nats
|
6
6
|
attr_reader :brokers
|
7
7
|
|
8
|
-
def initialize(brokers
|
8
|
+
def initialize(brokers)
|
9
9
|
@brokers = brokers
|
10
10
|
@mutex = Mutex.new
|
11
11
|
end
|
@@ -15,8 +15,8 @@ module RemoteService
|
|
15
15
|
connect(&block)
|
16
16
|
end
|
17
17
|
|
18
|
-
def
|
19
|
-
|
18
|
+
def exit
|
19
|
+
@conn_thread.exit
|
20
20
|
end
|
21
21
|
|
22
22
|
def publish(to_queue, message)
|
@@ -55,7 +55,7 @@ module RemoteService
|
|
55
55
|
|
56
56
|
def connection_thread
|
57
57
|
lock = Util::Lock.new
|
58
|
-
Thread.new do
|
58
|
+
@conn_thread = Thread.new do
|
59
59
|
connect do |connection|
|
60
60
|
lock.unlock(connection)
|
61
61
|
end
|
data/lib/remote_service/queue.rb
CHANGED
@@ -6,14 +6,19 @@ module RemoteService
|
|
6
6
|
class Queue
|
7
7
|
include Singleton
|
8
8
|
|
9
|
+
EXIT_SIGNALS = ['INT', 'TERM', 'SIGQUIT']
|
10
|
+
|
9
11
|
def connect(brokers, &block)
|
10
|
-
|
12
|
+
brokers ||= ENV.fetch('REMOTE_SERVICE_BROKERS', 'nats://127.0.0.1:4222').split(',')
|
13
|
+
@conn = Connector::Nats.new(brokers)
|
11
14
|
@conn.start(&block)
|
12
15
|
end
|
13
16
|
|
14
|
-
def service(service_handler, workers
|
17
|
+
def service(service_handler, workers, monitor_interval)
|
18
|
+
workers ||= ENV.fetch('REMOTE_SERVICE_WORKERS', 4)
|
19
|
+
monitor_interval ||= ENV.fetch('REMOTE_SERVICE_MONITOR_INTERVAL', 5)
|
20
|
+
@worker_pool = WorkerPool.new(workers.to_i, monitor_interval.to_i)
|
15
21
|
@service_handler = service_handler
|
16
|
-
@workers = workers
|
17
22
|
start_service_subscriber
|
18
23
|
end
|
19
24
|
|
@@ -40,17 +45,20 @@ module RemoteService
|
|
40
45
|
|
41
46
|
def start_service_subscriber
|
42
47
|
RemoteService.logger.debug "SERVICE QUEUE: #{service_queue_name}"
|
43
|
-
@
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
48
|
+
@worker_pool.start
|
49
|
+
@conn.subscribe(service_queue_name) do |*args|
|
50
|
+
@worker_pool.run(*args) do |request, reply_to|
|
51
|
+
begin
|
52
|
+
payload = decode(request)
|
53
|
+
RemoteService.logger.debug "FETCHED - REPLY_TO:[#{reply_to}] PAYLOAD:[#{payload}]"
|
54
|
+
@service_handler.handle(payload, reply_to)
|
55
|
+
rescue => e
|
56
|
+
RemoteService.logger.error(e)
|
57
|
+
Queue.instance.publish(
|
58
|
+
reply_to,
|
59
|
+
{result: nil, error: {name: e.class.name, message: e.message, backtrace: e.backtrace}},
|
60
|
+
)
|
61
|
+
end
|
54
62
|
end
|
55
63
|
end
|
56
64
|
end
|
@@ -70,5 +78,15 @@ module RemoteService
|
|
70
78
|
def decode(payload)
|
71
79
|
MessagePack.unpack(payload)
|
72
80
|
end
|
81
|
+
|
82
|
+
def setup_signal_handlers
|
83
|
+
EXIT_SIGNALS.each do |sig|
|
84
|
+
trap(sig) do
|
85
|
+
@worker_pool.exit if service?
|
86
|
+
@conn.exit if !service?
|
87
|
+
EM.stop
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
73
91
|
end
|
74
92
|
end
|
@@ -25,10 +25,10 @@ module RemoteService
|
|
25
25
|
end
|
26
26
|
|
27
27
|
class << self
|
28
|
-
def start(brokers, workers
|
28
|
+
def start(brokers:nil, workers:nil, monitor_interval:nil)
|
29
29
|
queue = Queue.instance
|
30
30
|
queue.connect(brokers) do
|
31
|
-
queue.service(self.instance, workers)
|
31
|
+
queue.service(self.instance, workers, monitor_interval)
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module RemoteService
|
2
|
+
class WorkerPool
|
3
|
+
attr_reader :queue, :threads
|
4
|
+
|
5
|
+
def initialize(worker_count, monitor_interval)
|
6
|
+
@worker_count = worker_count
|
7
|
+
@monitor_interval = monitor_interval
|
8
|
+
@threads = []
|
9
|
+
@queue = ::Queue.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def run(*args, &block)
|
13
|
+
queue.push({ args: args, callable: block })
|
14
|
+
end
|
15
|
+
|
16
|
+
def start
|
17
|
+
spawn_workers
|
18
|
+
monitor_thread
|
19
|
+
RemoteService.logger.info "WORKER POOL - WORKERS: #{threads.size}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def join
|
23
|
+
threads.each do |thread|
|
24
|
+
thread.join
|
25
|
+
end
|
26
|
+
monitor_thread.join
|
27
|
+
end
|
28
|
+
|
29
|
+
def exit
|
30
|
+
threads.each do |thread|
|
31
|
+
thread.exit
|
32
|
+
end
|
33
|
+
monitor_thread.exit
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def spawn_workers
|
39
|
+
@worker_count.times do
|
40
|
+
@threads << Thread.new do
|
41
|
+
loop do
|
42
|
+
data = queue.pop
|
43
|
+
data[:callable].call(*data[:args])
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def monitor_thread
|
50
|
+
@monitor_thread ||= begin
|
51
|
+
RemoteService.logger.info "WORKER POOL - MONITOR INTERVAL: #{@monitor_interval}s"
|
52
|
+
Thread.new do
|
53
|
+
loop do
|
54
|
+
RemoteService.logger.info "WORKER POOL - WAITING: #{queue.size}"
|
55
|
+
sleep(@monitor_interval)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/lib/remote_service.rb
CHANGED
@@ -2,6 +2,7 @@ require "remote_service/version"
|
|
2
2
|
require "remote_service/errors"
|
3
3
|
require "remote_service/util/lock"
|
4
4
|
require "remote_service/connector/nats"
|
5
|
+
require "remote_service/worker_pool"
|
5
6
|
require "remote_service/queue"
|
6
7
|
require "remote_service/call"
|
7
8
|
require "remote_service/base"
|
@@ -13,7 +14,7 @@ module RemoteService
|
|
13
14
|
extend self
|
14
15
|
attr_writer :logger
|
15
16
|
|
16
|
-
def connect(brokers
|
17
|
+
def connect(brokers:, &block)
|
17
18
|
queue = Queue.instance
|
18
19
|
queue.connect(brokers, &block)
|
19
20
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: remote_service
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marek Galovic
|
@@ -102,7 +102,9 @@ executables: []
|
|
102
102
|
extensions: []
|
103
103
|
extra_rdoc_files: []
|
104
104
|
files:
|
105
|
+
- ".codeclimate.yml"
|
105
106
|
- ".gitignore"
|
107
|
+
- ".rubocop.yml"
|
106
108
|
- ".travis.yml"
|
107
109
|
- Gemfile
|
108
110
|
- Gemfile.lock
|
@@ -124,6 +126,7 @@ files:
|
|
124
126
|
- lib/remote_service/service.rb
|
125
127
|
- lib/remote_service/util/lock.rb
|
126
128
|
- lib/remote_service/version.rb
|
129
|
+
- lib/remote_service/worker_pool.rb
|
127
130
|
- remote_service.gemspec
|
128
131
|
homepage: https://github.com/marekgalovic/ruby-remote-service
|
129
132
|
licenses:
|