SMService 0.1.4 → 0.1.8

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ba77f89b36377c88a36275cae2ee1cb0fe7933070fe29ee26dc52afcd5d3be14
4
- data.tar.gz: cf59fc3d4f92594b23817a59c4e5623d3e2ba75898894fd7f8aa52402d0fc22a
3
+ metadata.gz: 99628cf63e1cded8cfdd814002fb905aecd17833a19bd474da23671fe692c78e
4
+ data.tar.gz: 4eb82e840f5f730707784fb51fddd90f3accfe4501d9e3b5e9aa731133915490
5
5
  SHA512:
6
- metadata.gz: 9c57d922c113e68c45b4dc068e771795c4e1782b8701b1492513b55b662ac51eb73871c35cb90b27aeb911337b968d29877527894427007fdf23b6e67f76f574
7
- data.tar.gz: 0b8dc1990f4e49fb3937d7da8ab818bc71f15d9e945b625617593d39bef173398d3460c88b45928914962e3f9da02a3cb9473039a53d3352547ee0914607b838
6
+ metadata.gz: d3d7a51b6da0ff3144deefa211fd27fdd15473f2197ee0baf55d9b669e32bfd032e7c0a6d8c350c151b6c062530968c7a8e6cb13ff224799949d4e8ec456a3c1
7
+ data.tar.gz: f879a7f6182bbbac5c336f551991ea395f08953425ae6691d49712767947132413a7ef90fb898ff1495dde014f37ca0e5dfe1aceb644588c9b5e228d1133e092
data/Dockerfile CHANGED
@@ -20,8 +20,9 @@ RUN apk update \
20
20
  pcre \
21
21
  zlib \
22
22
  tzdata \
23
- mc \
23
+ tmux \
24
24
  vim \
25
+ mc \
25
26
  \
26
27
  && cp -R /usr/share/zoneinfo/Europe/Amsterdam /etc/localtime \
27
28
  && echo 'Europe/Amsterdam' > /etc/timezone \
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- SMService (0.1.3)
4
+ SMService (0.1.8)
5
5
  ffi-rzmq (~> 2.0)
6
6
  logger (~> 1.2)
7
7
  msgpack (~> 1.1)
@@ -9,6 +9,7 @@ PATH
9
9
  GEM
10
10
  remote: https://rubygems.org/
11
11
  specs:
12
+ coderay (1.1.2)
12
13
  diff-lcs (1.3)
13
14
  ffi (1.9.18)
14
15
  ffi-rzmq (2.0.5)
@@ -16,7 +17,11 @@ GEM
16
17
  ffi-rzmq-core (1.0.6)
17
18
  ffi
18
19
  logger (1.2.8)
20
+ method_source (0.9.0)
19
21
  msgpack (1.1.0)
22
+ pry (0.11.3)
23
+ coderay (~> 1.1.0)
24
+ method_source (~> 0.9.0)
20
25
  rake (10.5.0)
21
26
  rspec (3.7.0)
22
27
  rspec-core (~> 3.7.0)
@@ -38,6 +43,7 @@ PLATFORMS
38
43
  DEPENDENCIES
39
44
  SMService!
40
45
  bundler (~> 1.16)
46
+ pry (~> 0.11)
41
47
  rake (~> 10.0)
42
48
  rspec (~> 3.0)
43
49
 
@@ -36,6 +36,7 @@ Gem::Specification.new do |s|
36
36
 
37
37
 
38
38
  s.add_development_dependency "bundler", "~> 1.16"
39
+ s.add_development_dependency "pry", "~> 0.11"
39
40
  s.add_development_dependency "rake", "~> 10.0"
40
41
  s.add_development_dependency "rspec", "~> 3.0"
41
42
  end
data/bin/console CHANGED
@@ -1,16 +1,73 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ require 'rubygems'
4
+ require 'pry'
3
5
  require 'bundler'
4
6
  Bundler.setup
5
7
  Bundler.require
6
8
  require 'smservice'
9
+ require_relative '../examples/dummy'
7
10
 
8
- # You can add fixtures and/or initialization code here to make experimenting
9
- # with your gem easier. You can also use a different console, if you like.
11
+ class SMService::TestCase
12
+ include SMService
10
13
 
11
- # (If you use this, don't forget to add pry to your Gemfile!)
12
- # require "pry"
13
- # Pry.start
14
+ def initialize
15
+ super name: 'test_ruby', actions: 'test'
16
+ end
14
17
 
15
- require "irb"
16
- IRB.start(__FILE__)
18
+ def action_test(headers, message)
19
+ LOGGER.info "#{self.class} - Processing action 'test'. Headers: #{headers.inspect}, message: #{message.inspect}"
20
+
21
+ # triggering 'someaction' as part of test plan
22
+ @tc_reply_to = headers['reply_to'] # where TC shall report-to at the end
23
+ message[:parent_action_headers] = headers # sending also parameters from caller
24
+ execute action: 'someaction', message: message
25
+
26
+ if headers['reply_to']
27
+ # sending reply back
28
+ LOGGER.info "#{self.class} - Action 'test' sending reply"
29
+
30
+ execute action: 'REPLY',
31
+ reply_to: headers['reply_to'],
32
+ message: {status: 'OK', more_data: ['...']}
33
+
34
+ LOGGER.info "#{self.class} - Action 'test' reply sent"
35
+ end
36
+
37
+ LOGGER.info "#{self.class} - Terminating action 'test'"
38
+ end
39
+
40
+ def action_reply(headers, message)
41
+ LOGGER.info "#{self.class} - Processing action 'reply'. Headers: #{headers.inspect}, message: #{message.inspect}"
42
+
43
+ # ... if conditions and validations to ensure that it is reply for this TC, by searching UUID etc etc, and by the end:
44
+ #
45
+ LOGGER.info "#{self.class} - Forwarding collected TC data to the caller, which is #{@tc_reply_to}"
46
+ execute action: 'REPLY',
47
+ reply_to: @tc_reply_to,
48
+ message: message
49
+ end
50
+ end
51
+
52
+ class SMService::API
53
+ include SMService
54
+
55
+ def initialize
56
+ super name: 'api'
57
+ end
58
+ end
59
+
60
+
61
+ dummy = SMService::Dummy.new
62
+ dummy.start!
63
+
64
+ tc = SMService::TestCase.new
65
+ tc.start!
66
+
67
+ api = SMService::API.new
68
+ api.start!
69
+
70
+ sleep 3
71
+ api.execute(action: 'test', message: {my_request: 'ping', my_data: 'add whatever data needed'})
72
+
73
+ binding.pry
@@ -0,0 +1,15 @@
1
+ version: '3'
2
+
3
+ networks:
4
+ middleware:
5
+ external:
6
+ name: middleware_default
7
+
8
+ services:
9
+ rubygems:
10
+ build: .
11
+ container_name: rubygems
12
+ volumes:
13
+ - ./:/app
14
+ networks:
15
+ - middleware
data/docker.sh ADDED
@@ -0,0 +1,4 @@
1
+ #!/bin/sh
2
+
3
+ docker build --pull -t rubygems . && \
4
+ docker run -ti --rm --name=rubygems -v ${PWD}:/app rubygems sh
data/examples/dummy.rb ADDED
@@ -0,0 +1,25 @@
1
+ class SMService::Dummy
2
+ include SMService
3
+
4
+ def initialize
5
+ super name: 'dummy_ruby', actions: 'someaction'
6
+ end
7
+
8
+ def action_someaction(headers, message)
9
+ LOGGER.info "#{self.class} - Processing action 'someaction'. Headers: #{headers.inspect}, message: #{message.inspect}"
10
+
11
+ if headers['reply_to']
12
+ # sending reply back
13
+ LOGGER.info "#{self.class} - Action 'someaction' sending reply"
14
+
15
+ execute action: 'REPLY',
16
+ reply_to: headers['reply_to'],
17
+ message: {status: 'OK', whatever: 'add it here'}
18
+
19
+ LOGGER.info "#{self.class} - Action 'someaction' reply sent"
20
+ end
21
+
22
+ LOGGER.info "#{self.class} - Terminating action 'someaction'"
23
+
24
+ end
25
+ end
@@ -1,3 +1,3 @@
1
1
  module SMService
2
- VERSION = '0.1.4'
2
+ VERSION = '0.1.8'
3
3
  end
data/lib/smservice.rb CHANGED
@@ -10,14 +10,37 @@ module SMService
10
10
  ENDPOINT_OUT = 'tcp://proxy:6660'
11
11
  ENDPOINT_IN = 'tcp://proxy:6661'
12
12
 
13
- REGISTER_WAIT_TIME = 'infinite'
13
+ REGISTER_WAIT_TIME = 'infinite'
14
+ REGISTER_RETRY = 10
14
15
  KEEPALIVE_WAIT_TIME = 30
15
16
 
16
17
  attr_accessor :socket_in, :socket_out
17
18
  attr_reader :service_name
18
19
 
19
- def initialize(name:)
20
+ # When registering node, following parameters is mandatory:
21
+ #
22
+ # name: name of service/node with its id;
23
+ # actions: list of actions, should be in lowercase and compatible to naming standard for ruby methods
24
+ # actions could be presented as array or as string if service registering only single action
25
+ #
26
+ # Example:
27
+ # SMService::SomeService.new(name: 'dummy-ruby', actions: %w(a b c ping pong))
28
+ #
29
+ # Following actions should be defined as methods for new service, i.e.
30
+ #
31
+ # def action_ping(headers, message)
32
+ # LOGGER.info "#{self.class} - Processing action: PING with headers: #{headers.inspect} and message: #{message.inspect}"
33
+ # # ... business logic here
34
+ # end
35
+ #
36
+ # Prohibited names for actions is register and update, those are reserved to let service communicate with SM.
37
+ # Check SMService::Dummy source code (in examples folder) for detais
38
+ #
39
+ def initialize(name:, actions: [])
20
40
  @service_name = name
41
+ @actions = [%w(ping), actions].flatten.sort.uniq
42
+
43
+ @mutex = Mutex.new
21
44
 
22
45
  context = ZMQ::Context.new
23
46
  @socket_in = context.socket ZMQ::DEALER
@@ -30,21 +53,46 @@ module SMService
30
53
  @socket_out.connect ENDPOINT_OUT
31
54
  end
32
55
 
33
- def register!(wait_time: REGISTER_WAIT_TIME)
56
+ # starting infinite loop in order to process service logic.
57
+ # start! or service_poller methods could be modified implementing different services, i.e. to run as threaded metod
58
+ def start!
59
+ register
60
+ keep_alive!
61
+ poller!
62
+ @started = true
63
+ end
64
+
65
+ def started?
66
+ @started
67
+ end
68
+
69
+ def poller!
70
+ Thread.start do
71
+ poller
72
+ end
73
+ end
74
+
75
+ def poller
76
+ loop do
77
+ pull
78
+ end
79
+ end
80
+
81
+ def register(wait_time: REGISTER_WAIT_TIME)
34
82
  if wait_time.to_f <= 0
35
83
  loop do
36
- register!
84
+ register_service
37
85
  break if registered?
38
86
  # not registered, retrying in 10 seconds
39
- sleep 10
87
+ sleep REGISTER_RETRY
40
88
  end
41
89
  else
42
90
  Timeout::timeout(wait_time) do
43
91
  loop do
44
- register!
92
+ register_service
45
93
  break if registered?
46
94
  # not registered, retrying in 10 seconds
47
- sleep 10
95
+ sleep REGISTER_RETRY
48
96
  end
49
97
  end
50
98
  end
@@ -52,11 +100,11 @@ module SMService
52
100
 
53
101
  def keep_alive!(wait_time: KEEPALIVE_WAIT_TIME)
54
102
  Thread.start do
55
- LOGGER.info "Starting registration update loop with periodic interval #{wait_time} sec"
103
+ LOGGER.info "#{self.class} - Starting registration update loop with periodic interval #{wait_time} sec"
56
104
  loop do
57
105
  break unless registered?
58
106
  sleep wait_time
59
- service_manager('UPDATE', [])
107
+ request(action: 'UPDATE')
60
108
  end
61
109
  LOGGER.info 'Registration update loop terminated'
62
110
  end
@@ -66,55 +114,66 @@ module SMService
66
114
  @registered
67
115
  end
68
116
 
69
- def register!
70
- service_manager('REGISTER', services: [service_name])
71
- pull_action
117
+ def action_register(headers, message)
118
+ if headers['action'] == 'REGISTER' && message['result'] == 'OK'
119
+ @registered = true
120
+ LOGGER.info "#{self.class} - Action: REGISTER (successful), headers: #{headers.inspect}, message: #{message.inspect}"
121
+ else
122
+ LOGGER.info "#{self.class} - Action: REGISTER (failure), headers: #{headers.inspect}, message: #{message.inspect}"
123
+ end
72
124
  end
73
125
 
74
- def service_poller
75
- loop do
76
- pull_action
77
- end
126
+ def action_ping(headers, message)
127
+ LOGGER.info "#{self.class} - Processing action 'ping'. Headers: #{headers.inspect}, message: #{message.inspect}"
78
128
  end
79
129
 
80
- def start!
81
- register!
82
- keep_alive!
83
- service_poller
130
+ def action_update(headers, message)
131
+ LOGGER.info "#{self.class} - Processing action 'update'. Headers: #{headers.inspect}, message: #{message.inspect}"
84
132
  end
85
133
 
86
- def action_update(headers, message)
87
- LOGGER.info("Action: UPDATE (successful)")
134
+ def action_reply(headers, message)
135
+ LOGGER.info "#{self.class} - Processing action 'reply'. Headers: #{headers.inspect}, message: #{message.inspect}"
88
136
  end
89
137
 
90
- def action_register(headers, message)
91
- if headers['action'] == 'REGISTER' && message['result'] == 'OK'
92
- @registered = true
93
- LOGGER.info "Action: REGISTER (successful), headers: #{headers.inspect}, message: #{message.inspect}"
94
- else
95
- LOGGER.info "Action: REGISTER (failure), headers: #{headers.inspect}, message: #{message.inspect}"
96
- end
138
+ # Requesting another service, registered at SM to execute given action, example:
139
+ # execute(action: 'create_customer_portal', message: {my_request: 'should create a customer', my_data: 'add whatever data needed'})
140
+ #
141
+ def execute(action:, reply_to: nil, message: nil)
142
+ LOGGER.info "#{self.class} - SM execute request. Action: #{action.inspect}, message: #{message.inspect}"
143
+ action = {service: action, reply_to: (reply_to || @service_name)}.to_msgpack
144
+ message = message.to_msgpack
145
+ @socket_out.send_strings [action, message]
97
146
  end
98
147
 
99
148
  private
100
149
 
150
+ def register_service
151
+ LOGGER.info "#{self.class} - Registering service #{service_name}"
152
+ request(action: 'REGISTER', message: {services: @actions})
153
+ pull
154
+ end
155
+
101
156
  # Sending request to the Service Manager
102
- #
103
- def service_manager(action, message)
104
- LOGGER.info "SM request. Action: #{action.inspect}, message: #{message.inspect}"
157
+ def request(action:, message: nil)
158
+ LOGGER.info "#{self.class} - SM request. Action: #{action.inspect}, message: #{message.inspect}"
105
159
  action = {action: action}.to_msgpack
106
160
  message = message.to_msgpack
107
- @socket_in.send_strings [action, message]
161
+ @mutex.synchronize do
162
+ @socket_in.send_strings [action, message]
163
+ end
108
164
  end
109
165
 
110
- def pull_action
111
- @socket_in.recv_strings( response = [] )
166
+ def pull
167
+ response = []
168
+ @mutex.synchronize do
169
+ @socket_in.recv_strings(response)
170
+ end
112
171
 
113
172
  headers, message = response
114
173
  headers = MessagePack.unpack(headers)
115
174
  message = MessagePack.unpack(message)
116
175
 
117
- LOGGER.info "SM response received by pull_action. Headers: #{headers.inspect}, message: #{message.inspect}"
176
+ LOGGER.info "#{self.class} - SM response received by pull. Headers: #{headers.inspect}, message: #{message.inspect}"
118
177
 
119
178
  # Validates is action_name exists as class method and calling it.
120
179
  # In case, if Service Manager return headers['action'] == 'METHOD_NAME',
@@ -128,17 +187,11 @@ private
128
187
  # - action_register, that confirms registration of node with Service Manager, and
129
188
  # - action_update, that confirms successfule registration update, we need it to support keep-alive
130
189
  #
131
- action_name = "action_#{headers['action'].downcase}".to_sym
190
+ action_name = "action_#{(headers['action'] || headers['service']).downcase}".to_sym
132
191
  if respond_to? action_name.to_sym
133
192
  send(action_name, headers, message)
193
+ else
194
+ LOGGER.error "#{self.class} - Method #{action_name} does not exist in class instance for action name #{headers['action']}"
134
195
  end
135
196
  end
136
197
  end
137
-
138
- class SMService::Dummy
139
- include SMService
140
-
141
- def initialize
142
- super name: 'dummy-ruby'
143
- end
144
- end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: SMService
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrius Kairiukstis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-11-17 00:00:00.000000000 Z
11
+ date: 2017-11-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: logger
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '1.16'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.11'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.11'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: rake
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -112,11 +126,14 @@ files:
112
126
  - LICENSE.txt
113
127
  - README.md
114
128
  - Rakefile
129
+ - SMService.gemspec
115
130
  - bin/console
116
131
  - bin/setup
132
+ - docker-compose.yml
133
+ - docker.sh
134
+ - examples/dummy.rb
117
135
  - lib/smservice.rb
118
136
  - lib/smservice/version.rb
119
- - smservice.gemspec
120
137
  homepage: https://github.com/andrius/smservice
121
138
  licenses:
122
139
  - MIT