workmesh 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/workmesh.rb +391 -0
  3. metadata +172 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 729804b3c48a7bdc88018de15bb49f297da200e310ebd306d2f4f75bb8832d3d
4
+ data.tar.gz: 4477a6b46a6e2ee01ba3576b722d5ffcde51b1128b7c916f1875e9b9f59e3305
5
+ SHA512:
6
+ metadata.gz: 7306d782ff3a70b3e0e13f6436b9035e72e00b99d52103888d08713851af0685e06c31b62066c3f49b5452088498361632b1c0b6af6aa01a162f7cc90a5ba3ed
7
+ data.tar.gz: e9af5b428c21d0b6aa5ec5070a3a20121c54c4a9006893a1bef0e0a268efc7834b2ea8b78d5fa0e5e4c4d68ef3353727a8ea16fc3c2006ea39f4e4763fc9ba2e
data/lib/workmesh.rb ADDED
@@ -0,0 +1,391 @@
1
+ require 'colorize'
2
+ require 'sequel'
3
+ require 'blackstack-core'
4
+ require 'blackstack-nodes'
5
+ require 'blackstack-deployer'
6
+ require 'simple_command_line_parser'
7
+ require 'simple_cloud_logging'
8
+
9
+ require_relative '../deployment-routines/update-config'
10
+ require_relative '../deployment-routines/update-source'
11
+
12
+ =begin
13
+ # TODO: Move this to a gem with the CRDB module
14
+ #
15
+ # return a postgresql uuid
16
+ #
17
+ def guid()
18
+ DB['SELECT gen_random_uuid() AS id'].first[:id]
19
+ end
20
+ =end
21
+
22
+ # TODO: Move new() to a gem with the CRDB module
23
+ #
24
+ # return current datetime with format `%Y-%m-%d %H:%M:%S %Z`, using the timezone of the database (`select current_setting('TIMEZONE')`)
25
+ # TODO: I am hardcoding the value of `tz` because for any reason `SELECT current_setting('TIMEZONE')` returns `UTC` instead of
26
+ # `America/Argentina/Buenos_Aires` when I run it from Ruby. Be sure your database is ALWAYS configured with the correct timezone.
27
+ #
28
+ def now()
29
+ tz = 'America/Argentina/Buenos_Aires' #DB["SELECT current_setting('TIMEZONE') AS tz"].first[:tz]
30
+ DB["SELECT current_timestamp() at TIME ZONE '#{tz}' AS now"].first[:now]
31
+ end
32
+
33
+ module BlackStack
34
+ module Workmesh
35
+ # stub node class
36
+ # stub node class is already defined in the blackstack-nodes gem: https://github.com/leandrosardi/blackstack-nodes
37
+ # we inherit from it to add some extra methods and attributes
38
+ class Node
39
+ # stub node class is already defined in the blackstack-nodes gem: https://github.com/leandrosardi/blackstack-nodes
40
+ # we inherit from it to add some extra methods and attributes
41
+ include BlackStack::Infrastructure::NodeModule
42
+ # array of workers belonging to this node
43
+ attr_accessor :workmesh_api_key
44
+ attr_accessor :workmesh_port
45
+ attr_accessor :workmesh_service
46
+ # add validations to the node descriptor
47
+ def self.descriptor_errors(h)
48
+ errors = BlackStack::Infrastructure::NodeModule.descriptor_errors(h)
49
+ # validate: the key :max_workers exists and is an integer
50
+ errors << "The key :workmesh_api_key is missing" if h[:workmesh_api_key].nil?
51
+ errors << "The key :workmesh_api_key must be an String" unless h[:workmesh_api_key].is_a?(String)
52
+ # validate: the key :workmesh_port exists and is an integer
53
+ errors << "The key :workmesh_port is missing" if h[:workmesh_port].nil?
54
+ errors << "The key :workmesh_port must be an Integer" unless h[:workmesh_port].is_a?(Integer)
55
+ # validate: the key :workmesh_service exists and is an symbol, and its string matches with the name of one of the services in the @@services array
56
+ errors << "The key :workmesh_service is missing" if h[:workmesh_service].nil?
57
+ errors << "The key :workmesh_service must be an Symbol" unless h[:workmesh_service].is_a?(Symbol)
58
+ errors << "The key :workmesh_service must be one of the following: #{BlackStack::Workmesh.services.map { |s| s.name }}" unless BlackStack::Workmesh.services.map { |s| s.name }.include?(h[:workmesh_service].to_s)
59
+ # return list of errors
60
+ errors.uniq
61
+ end
62
+ # initialize the node
63
+ def initialize(h, i_logger=nil)
64
+ errors = BlackStack::Workmesh::Node.descriptor_errors(h)
65
+ raise "The node descriptor is not valid: #{errors.uniq.join(".\n")}" if errors.length > 0
66
+ super(h, i_logger)
67
+ self.workmesh_api_key = h[:workmesh_api_key]
68
+ self.workmesh_port = h[:workmesh_port]
69
+ self.workmesh_service = h[:workmesh_service]
70
+ end # def self.create(h)
71
+ # returh a hash descriptor of the node
72
+ def to_hash()
73
+ ret = super()
74
+ ret[:workmesh_api_key] = self.workmesh_api_key
75
+ ret[:workmesh_port] = self.workmesh_port
76
+ ret[:workmesh_service] = self.workmesh_service
77
+ ret
78
+ end
79
+ # run deployment routines
80
+ def deploy(l=nil)
81
+ l = BlackStack::DummyLogger.new(nil) if l.nil?
82
+
83
+ l.logs 'Updating config.rb... '
84
+ BlackStack::Deployer::run_routine(self.name, 'workmesh-update-config')
85
+ l.done
86
+
87
+ l.logs 'Updating source... '
88
+ BlackStack::Deployer::run_routine(self.name, 'workmesh-update-source')
89
+ l.done
90
+ end
91
+ end # class Node
92
+
93
+ class Protocol
94
+ attr_accessor :name
95
+ attr_accessor :entity_table, :entity_field_id, :entity_field_sort
96
+ attr_accessor :push_function, :entity_field_push_time, :entity_field_push_success, :entity_field_push_error_description
97
+ attr_accessor :pull_status_access_point
98
+ attr_accessor :pull_function, :enttity_field_pull_time, :entity_field_pull_success, :entity_field_pull_error_description
99
+
100
+ def self.descriptor_errors(h)
101
+ errors = []
102
+ # validate: the key :name exists and is a string
103
+ errors << "The key :name is missing" if h[:name].nil?
104
+ errors << "The key :name must be an String" unless h[:name].is_a?(String)
105
+ # validate: the key :entity_table exists and is an symbol
106
+ errors << "The key :entity_table is missing" if h[:entity_table].nil?
107
+ errors << "The key :entity_table must be an Symbol" unless h[:entity_table].is_a?(Symbol)
108
+ # validate: the key :entity_field_id exists and is an symbol
109
+ errors << "The key :entity_field_id is missing" if h[:entity_field_id].nil?
110
+ errors << "The key :entity_field_id must be an Symbol" unless h[:entity_field_id].is_a?(Symbol)
111
+ # validate: the key :entity_field_sort exists and is an symbol
112
+ errors << "The key :entity_field_sort is missing" if h[:entity_field_sort].nil?
113
+ errors << "The key :entity_field_sort must be an Symbol" unless h[:entity_field_sort].is_a?(Symbol)
114
+
115
+ # validate: the key :push_function is null or it is a procedure
116
+ #errors << "The key :push_function must be an Symbol" unless h[:push_function].nil? || h[:push_function].is_a?()
117
+ # validate: if :push_function exists, the key :entity_field_push_time exists and it is a symbol
118
+ errors << "The key :entity_field_push_time is missing" if h[:push_function] && h[:entity_field_push_time].nil?
119
+ # validate: if :push_function exists, the key :entity_field_push_success exists and it is a symbol
120
+ errors << "The key :entity_field_push_success is missing" if h[:push_function] && h[:entity_field_push_success].nil?
121
+ # validate: if :push_function exists, the key :entity_field_push_error_description exists and it is a symbol
122
+ errors << "The key :entity_field_push_error_description is missing" if h[:push_function] && h[:entity_field_push_error_description].nil?
123
+
124
+ # valiudate: if :pull_function exists, the key :pull_status_access_point exists and it is a string
125
+ errors << "The key :pull_status_access_point is missing" if h[:pull_function] && h[:pull_status_access_point].nil?
126
+ errors << "The key :pull_status_access_point must be an String" unless h[:pull_function].nil? || h[:pull_status_access_point].is_a?(String)
127
+ # validate: if :pull_function exists, the key :entity_field_pull_time exists and it is a symbol
128
+ errors << "The key :entity_field_pull_time is missing" if h[:pull_function] && h[:entity_field_pull_time].nil?
129
+ # validate: if :pull_function exists, the key :entity_field_pull_success exists and it is a symbol
130
+ errors << "The key :entity_field_pull_success is missing" if h[:pull_function] && h[:entity_field_pull_success].nil?
131
+ # validate: if :pull_function exists, the key :entity_field_pull_error_description exists and it is a symbol
132
+ errors << "The key :entity_field_pull_error_description is missing" if h[:pull_function] && h[:entity_field_pull_error_description].nil?
133
+
134
+ # return list of errors
135
+ errors.uniq
136
+ end
137
+
138
+ def initialize(h)
139
+ errors = BlackStack::Workmesh::Protocol.descriptor_errors(h)
140
+ raise "The protocol descriptor is not valid: #{errors.uniq.join(".\n")}" if errors.length > 0
141
+ self.name = h[:name]
142
+ self.entity_table = h[:entity_table]
143
+ self.entity_field_id = h[:entity_field_id]
144
+ self.entity_field_sort = h[:entity_field_sort]
145
+ self.push_function = h[:push_function]
146
+ self.entity_field_push_time = h[:entity_field_push_time]
147
+ self.entity_field_push_success = h[:entity_field_push_success]
148
+ self.entity_field_push_error_description = h[:entity_field_push_error_description]
149
+ self.pull_function = h[:pull_function]
150
+ self.enttity_field_pull_time = h[:entity_field_pull_time]
151
+ self.entity_field_pull_success = h[:entity_field_pull_success]
152
+ self.entity_field_pull_error_description = h[:entity_field_pull_error_description]
153
+ end
154
+
155
+ def to_hash()
156
+ ret = super()
157
+ ret[:name] = self.name
158
+ ret[:entity_table] = self.entity_table
159
+ ret[:entity_field_id] = self.entity_field_id
160
+ ret[:entity_field_sort] = self.entity_field_sort
161
+ ret[:push_function] = self.push_function
162
+ ret[:entity_field_push_time] = self.entity_field_push_time
163
+ ret[:entity_field_push_success] = self.entity_field_push_success
164
+ ret[:entity_field_push_error_description] = self.entity_field_push_error_description
165
+ ret[:pull_function] = self.pull_function
166
+ ret[:enttity_field_pull_time] = self.enttity_field_pull_time
167
+ ret[:entity_field_pull_success] = self.entity_field_pull_success
168
+ ret[:entity_field_pull_error_description] = self.entity_field_pull_error_description
169
+ ret
170
+ end
171
+
172
+ # execute the push function of this protocol, and update the push flags
173
+ def push(entity, node)
174
+ raise 'The push function is not defined' if self.push_function.nil?
175
+ entity[entity_field_push_time] = now()
176
+ begin
177
+ self.push_function.call(entity, node)
178
+ entity[entity_field_push_success] = true
179
+ entity[entity_field_push_error_description] = nil
180
+ entity.save
181
+ rescue => e
182
+ entity[entity_field_push_success] = false
183
+ entity[entity_field_push_error_description] = e.message
184
+ entity.save
185
+ raise e
186
+ end
187
+ end
188
+ end # class Protocol
189
+
190
+ # stub worker class
191
+ class Service
192
+ ASSIGANTIONS = [:entityweight, :roundrobin, :entitynumber]
193
+ # name to identify uniquely the worker
194
+ attr_accessor :name, :entity_table, :entity_field_assignation, :protocols, :assignation
195
+ # return an array with the errors found in the description of the job
196
+ def self.descriptor_errors(h)
197
+ errors = []
198
+ # validate: the key :name exists and is an string
199
+ errors << "The key :name is missing" if h[:name].nil?
200
+ errors << "The key :name must be an String" unless h[:name].is_a?(String)
201
+ # validate: the key :entity_table exists and is an symbol
202
+ errors << "The key :entity_table is missing" if h[:entity_table].nil?
203
+ errors << "The key :entity_table must be an Symbol" unless h[:entity_table].is_a?(Symbol)
204
+ # validate: the key :entity_field_assignation exists and is an symbol
205
+ errors << "The key :entity_field_assignation is missing" if h[:entity_field_assignation].nil?
206
+ errors << "The key :entity_field_assignation must be an Symbol" unless h[:entity_field_assignation].is_a?(Symbol)
207
+ # validate: the key :protocols exists is nil or it is an array of valid hash descritors of the Protocol class.
208
+ errors << "The key :protocols must be an Array" unless h[:protocols].nil? || h[:protocols].is_a?(Array)
209
+ if h[:protocols].is_a?(Array)
210
+ h[:protocols].each do |protocol|
211
+ errors << "The key :protocols must be an Array of valid hash descritors of the Protocol class" unless protocol.is_a?(Hash)
212
+ errors << "The key :protocols must be an Array of valid hash descritors of the Protocol class" unless Protocol.descriptor_errors(protocol).length == 0
213
+ end
214
+ end
215
+ # validate: the key :assignation is nil or it is a symbol belonging the array ASSIGANTIONS
216
+ errors << "The key :assignation must be an Symbol" unless h[:assignation].nil? || h[:assignation].is_a?(Symbol)
217
+ unless h[:assignation].nil?
218
+ errors << "The key :assignation must be one of the following values: #{ASSIGANTIONS.join(", ")}" unless ASSIGANTIONS.include?(h[:assignation])
219
+ end
220
+ # return list of errors
221
+ errors.uniq
222
+ end
223
+ # setup dispatcher configuration here
224
+ def initialize(h)
225
+ errors = BlackStack::Workmesh::Service.descriptor_errors(h)
226
+ raise "The worker descriptor is not valid: #{errors.uniq.join(".\n")}" if errors.length > 0
227
+ self.name = h[:name]
228
+ self.entity_table = h[:entity_table]
229
+ self.entity_field_assignation = h[:entity_field_assignation]
230
+ self.protocols = []
231
+ if h[:protocols]
232
+ h[:protocols].each do |i|
233
+ self.protocols << BlackStack::Workmesh::Protocol.new(i)
234
+ end
235
+ end
236
+ self.assignation = h[:assignation]
237
+ end
238
+ # return a hash descriptor of the worker
239
+ def to_hash()
240
+ {
241
+ :name => self.name,
242
+ :entity_table => self.entity_table,
243
+ :entity_field_assignation => self.entity_field_assignation,
244
+ :protocols => self.protocols.map { |p| p.to_hash },
245
+ :assignation => self.assignation
246
+ }
247
+ end
248
+ # get a protocol from its name
249
+ def protocol(name)
250
+ self.protocols.select { |p| p.name.to_s == name.to_s }.first
251
+ end
252
+ end # class Service
253
+
254
+ # hash with the round-robin positions per service.
255
+ @@roundrobin = {}
256
+
257
+ # infrastructure configuration
258
+ @@nodes = []
259
+ @@services = []
260
+
261
+ # logger configuration
262
+ @@log_filename = nil
263
+ @@logger = BlackStack::DummyLogger.new(nil)
264
+
265
+ # Connection string to the database. Example: mysql2://user:password@localhost:3306/database
266
+ @@connection_string = nil
267
+
268
+ # define a filename for the log file.
269
+ def self.set_log_filename(s)
270
+ @@log_filename = s
271
+ @@logger = BlackStack::LocalLogger.new(s)
272
+ end
273
+
274
+ # return the logger.
275
+ def self.logger()
276
+ @@logger
277
+ end
278
+
279
+ def self.set_logger(l)
280
+ @@logger = l
281
+ end
282
+
283
+ # return the log filename.
284
+ def self.log_filename()
285
+ @@log_filename
286
+ end
287
+
288
+ # define the connectionstring to the database.
289
+ def self.set_connection_string(s)
290
+ @@connection_string = s
291
+ end
292
+
293
+ # return connection string to the database. Example: mysql2://user:password@localhost:3306/database
294
+ def self.connection_string()
295
+ @@connection_string
296
+ end
297
+
298
+ # add_node
299
+ # add a node to the infrastructure
300
+ def self.add_node(h)
301
+ @@nodes << BlackStack::Workmesh::Node.new(h)
302
+ # add to deployer
303
+ BlackStack::Deployer.add_node(h) #if @@integrate_with_blackstack_deployer
304
+ end
305
+
306
+ def self.nodes
307
+ @@nodes
308
+ end
309
+
310
+ def self.node(name)
311
+ @@nodes.select { |n| n.name.to_s == name.to_s }.first
312
+ end
313
+
314
+ # add_service
315
+ # add a service to the infrastructure
316
+ def self.add_service(h)
317
+ @@services << BlackStack::Workmesh::Service.new(h)
318
+ end
319
+
320
+ def self.services
321
+ @@services
322
+ end
323
+
324
+ def self.service(name)
325
+ @@services.select { |s| s.name.to_s == name.to_s }.first
326
+ end
327
+
328
+ # assign object to a node using a round-robin algorithm
329
+ # this method is used when the service assignation is :roundrobin
330
+ # this method is for internal use only, and it should not be called directly.
331
+ def self.roundrobin(o, service_name)
332
+ @@roundrobin[service_name] = 0 if @@roundrobin[service_name].nil?
333
+ # getting the service
334
+ s = @@services.select { |s| s.name.to_s == service_name.to_s }.first
335
+ # getting all the nodes assigned to the service
336
+ nodes = @@nodes.select { |n| n.workmesh_service.to_s == service_name.to_s }.sort_by { |n| n.name.to_s }
337
+ # increase i
338
+ @@roundrobin[service_name] += 1
339
+ @@roundrobin[service_name] = 0 if @@roundrobin[service_name] >= nodes.length
340
+ # assign the object to the node
341
+ n = nodes[@@roundrobin[service_name]]
342
+ o[s.entity_field_assignation] = n.name
343
+ o.save
344
+ # return
345
+ n
346
+ end
347
+
348
+ # return the assigned node to an object, for a specific service.
349
+ # if the object has not a node assigned, then return nil.
350
+ def self.assigned_node(o, service_name)
351
+ # getting the service
352
+ s = @@services.select { |s| s.name.to_s == service_name.to_s }.first
353
+ # validate: the service exists
354
+ raise "The service #{service_name} does not exists" if s.nil?
355
+ # validate: the object o is an instance of the Sequel Class mapping the table :entity_table
356
+ raise "The object o is not an instance of :entity_table (#{s.entity_table.to_s})" unless o.is_a?(Sequel::Model) && o.class.table_name.to_s == s.entity_table.to_s
357
+ # if the object has not a node assigned, then return nil.
358
+ return nil if o[s.entity_field_assignation].nil?
359
+ # return the node
360
+ @@nodes.select { |n| n.name.to_s == o[s.entity_field_assignation].to_s }.first
361
+ end
362
+
363
+ # assign object to a node
364
+ def self.assign(o, service_name, h = {})
365
+ # getting the service
366
+ s = @@services.select { |s| s.name.to_s == service_name.to_s }.first
367
+ # validate: the service exists
368
+ raise "The service #{service_name} does not exists" if s.nil?
369
+ # validate: the object o is an instance of the Sequel Class mapping the table :entity_table
370
+ raise "The object o is not an instance of :entity_table (#{s.entity_table.to_s})" unless o.is_a?(Sequel::Model) && o.class.table_name.to_s == s.entity_table.to_s
371
+ # reassign
372
+ if h[:reassign] == true
373
+ o[s.entity_field_assignation] = nil
374
+ o.save
375
+ end
376
+ # validate: the object o has not been assigned yet
377
+ raise "The object o has been already assigned to a node. Use the :reassign parameter for reassignation." unless o[s.entity_field_assignation].nil?
378
+ # decide the assignation method
379
+ if s.assignation == :entityweight
380
+ raise 'The assignation method :entityweight is not implemented yet.'
381
+ elsif s.assignation == :roundrobin
382
+ return BlackStack::Workmesh.roundrobin(o, service_name)
383
+ elsif s.assignation == :entitynumber
384
+ raise 'The assignation method :entitynumber is not implemented yet.'
385
+ else
386
+ raise "The assignation method #{s.assignation} is unknown."
387
+ end
388
+ end
389
+
390
+ end # module Workmesh
391
+ end # module BlackStack
metadata ADDED
@@ -0,0 +1,172 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: workmesh
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Leandro Daniel Sardi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-06-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: sequel
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 5.56.0
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 5.56.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: 5.56.0
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 5.56.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: blackstack-core
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: 1.2.3
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 1.2.3
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: 1.2.3
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 1.2.3
53
+ - !ruby/object:Gem::Dependency
54
+ name: blackstack-nodes
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: 1.2.11
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: 1.2.11
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: 1.2.11
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 1.2.11
73
+ - !ruby/object:Gem::Dependency
74
+ name: blackstack-deployer
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: 1.2.24
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 1.2.24
83
+ type: :runtime
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 1.2.24
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: 1.2.24
93
+ - !ruby/object:Gem::Dependency
94
+ name: simple_command_line_parser
95
+ requirement: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - "~>"
98
+ - !ruby/object:Gem::Version
99
+ version: 1.1.2
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: 1.1.2
103
+ type: :runtime
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: 1.1.2
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: 1.1.2
113
+ - !ruby/object:Gem::Dependency
114
+ name: simple_cloud_logging
115
+ requirement: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - "~>"
118
+ - !ruby/object:Gem::Version
119
+ version: 1.2.2
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: 1.2.2
123
+ type: :runtime
124
+ prerelease: false
125
+ version_requirements: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - "~>"
128
+ - !ruby/object:Gem::Version
129
+ version: 1.2.2
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: 1.2.2
133
+ description: "WorkMesh is an open-source micro-services orchestration system for automatng
134
+ software scaling and work distribution.\n\n Some hints:\n \n - In the **WorkMesh**
135
+ world, a **micro-service** is an **external web-service** who receives tasks for
136
+ any kind of offline processing, and returns the result to **master**. Just that.
137
+ Nothing more.\n \n - This library is for defininng the micro-service protocol
138
+ at the **master** side.\n \n - For creating your own micro-service, refer to [micro.template](https://github.com/leandrosardi/micro.template)
139
+ project.\n \n - If you are looking for a multi-threading processing framework,
140
+ you should refer to [Pampa](https://github.com/leandrosardi/pampa) instead.\n \nFind
141
+ documentation here: https://github.com/leandrosardi/workmesh\n"
142
+ email: leandro.sardi@expandedventure.com
143
+ executables: []
144
+ extensions: []
145
+ extra_rdoc_files: []
146
+ files:
147
+ - lib/workmesh.rb
148
+ homepage: https://rubygems.org/gems/workmesh
149
+ licenses:
150
+ - MIT
151
+ metadata: {}
152
+ post_install_message:
153
+ rdoc_options: []
154
+ require_paths:
155
+ - lib
156
+ required_ruby_version: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ version: '0'
161
+ required_rubygems_version: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - ">="
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ requirements: []
167
+ rubygems_version: 3.3.7
168
+ signing_key:
169
+ specification_version: 4
170
+ summary: WorkMesh is an open-source micro-services orchestration system for automatng
171
+ software scaling and work distribution.
172
+ test_files: []