rocketjob 5.0.0.rc1 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c53fb037073ba38fd229b6a0573a2e0a28a1f28bbb0750bc895f2f2d46b57d44
4
- data.tar.gz: c5ab8fcbe268aa97909448b4e053cf54698b1f690fe537899f1ed4a5c7f7a1ed
3
+ metadata.gz: 601a4455f5e51191440ce959b6325545d51fcaf531d179dfcd78a4ec016b44c6
4
+ data.tar.gz: 7ea8fc1b5cc632461d01e608f5c93cb33e379e14138764fc9e424d15f9c07679
5
5
  SHA512:
6
- metadata.gz: 69973ec5d30e2d9a63a338119121decb9c20ce8b5d0aba3d9a566799f80eaad626bb2055361bda7cbf5e60085b0fd82c68082f499e151d3a982659457173c5ff
7
- data.tar.gz: 8a7b75c3d55fdc1c38c549efc91b8e7cf806ac7aa323a2c0ed1ede9f7e4b7518840d282b172446e5f5f9762685dd5a0639ce9e5fc151d173a59212a0ac5d5ee7
6
+ metadata.gz: 823280f2250aaa7e2bef010b8b7477f1db1d2f04631c9ce133b80545768e23cab98a14cbc597630988b69b02cfc115acf34a647f50f84fc35e61a708af4c2c09
7
+ data.tar.gz: e562aa988c120459637cd11108a4401440faa674d1a3226a8c7e77a91ec31635935349803a9c17ace9b3603c14f8a97ec2e8196ba20a79bf518a429807152dce
@@ -58,14 +58,14 @@ module RocketJob
58
58
  # Searches for the first "\r\n" or "\n" and then uses that as the
59
59
  # delimiter for all subsequent records
60
60
  #
61
- # stream_mode: [:line | :row | :record]
61
+ # stream_mode: [:line | :array | :hash]
62
62
  # :line
63
63
  # Uploads the file a line (String) at a time for processing by workers.
64
- # :row
64
+ # :array
65
65
  # Parses each line from the file as an Array and uploads each array for processing by workers.
66
- # :record
66
+ # :hash
67
67
  # Parses each line from the file into a Hash and uploads each hash for processing by workers.
68
- # See IOStreams::Stream#each_line, IOStreams::Stream#each_row, and IOStreams::Stream#each_record.
68
+ # See IOStreams::Stream#each.
69
69
  #
70
70
  # Example:
71
71
  # # Load plain text records from a file
@@ -118,6 +118,11 @@ module RocketJob
118
118
  def upload(stream = nil, file_name: nil, category: :main, stream_mode: :line, on_first: nil, **args, &block)
119
119
  raise(ArgumentError, 'Either stream, or a block must be supplied') unless stream || block
120
120
 
121
+ stream_mode = stream_mode.to_sym
122
+ # Backward compatibility with existing v4 jobs
123
+ stream_mode = :array if stream_mode == :row
124
+ stream_mode = :hash if stream_mode == :record
125
+
121
126
  count =
122
127
  if block
123
128
  input(category).upload(on_first: on_first, &block)
@@ -126,7 +131,7 @@ module RocketJob
126
131
  path.file_name = file_name if file_name
127
132
  self.upload_file_name = path.file_name
128
133
  input(category).upload(on_first: on_first) do |io|
129
- path.public_send("each_#{stream_mode}".to_sym, **args) { |line| io << line }
134
+ path.each(stream_mode, **args) { |line| io << line }
130
135
  end
131
136
  end
132
137
  self.record_count = (record_count || 0) + count
@@ -336,7 +341,7 @@ module RocketJob
336
341
  # end
337
342
  #
338
343
  # Example: Add a header and/or trailer record to the downloaded file, letting the line writer add the line breaks:
339
- # IOStreams.path('/tmp/file.txt.gz').line_writer do |writer|
344
+ # IOStreams.path('/tmp/file.txt.gz').writer(:line) do |writer|
340
345
  # writer << "Header"
341
346
  # job.download do |line|
342
347
  # writer << line
@@ -352,7 +357,7 @@ module RocketJob
352
357
 
353
358
  return output(category).download(header_line: header_line, &block) if block
354
359
 
355
- IOStreams.new(stream).line_writer(**args) do |io|
360
+ IOStreams.new(stream).writer(:line, **args) do |io|
356
361
  output(category).download(header_line: header_line) { |record| io << record }
357
362
  end
358
363
  end
@@ -13,18 +13,18 @@ module RocketJob
13
13
  field :tabular_input_header, type: Array, class_attribute: true, user_editable: true
14
14
  field :tabular_input_format, type: Symbol, default: :csv, class_attribute: true, user_editable: true
15
15
 
16
- # tabular_input_mode: [:line | :row | :record]
16
+ # tabular_input_mode: [:line | :array | :hash]
17
17
  # :line
18
18
  # Uploads the file a line (String) at a time for processing by workers.
19
- # :row
19
+ # :array
20
20
  # Parses each line from the file as an Array and uploads each array for processing by workers.
21
- # :record
21
+ # :hash
22
22
  # Parses each line from the file into a Hash and uploads each hash for processing by workers.
23
- # See IOStreams#each_line, IOStreams#each_row, and IOStreams#each_record.
23
+ # See IOStreams#each.
24
24
  field :tabular_input_mode, type: Symbol, default: :line, class_attribute: true, user_editable: true, copy_on_restart: true
25
25
 
26
26
  validates_inclusion_of :tabular_input_format, in: IOStreams::Tabular.registered_formats
27
- validates_inclusion_of :tabular_input_mode, in: %i[line row record]
27
+ validates_inclusion_of :tabular_input_mode, in: %i[line array hash row record]
28
28
  validate :tabular_input_header_present
29
29
 
30
30
  class_attribute :tabular_input_white_list
@@ -72,16 +72,16 @@ module RocketJob
72
72
  tabular_input_cleanse_header
73
73
  self.tabular_input_header = tabular_input.header.columns
74
74
  end
75
- super(input_stream, on_first: parse_header, stream_mode: tabular_input_mode, **args, &block)
76
- when :row
75
+ super(input_stream, on_first: parse_header, stream_mode: :line, **args, &block)
76
+ when :array, :row
77
77
  set_header = -> (row) do
78
78
  tabular_input.header.columns = row
79
79
  tabular_input_cleanse_header
80
80
  self.tabular_input_header = tabular_input.header.columns
81
81
  end
82
- super(input_stream, on_first: set_header, stream_mode: tabular_input_mode, **args, &block)
83
- when :record
84
- super(input_stream, stream_mode: tabular_input_mode, **args, &block)
82
+ super(input_stream, on_first: set_header, stream_mode: :array, **args, &block)
83
+ when :hash, :record
84
+ super(input_stream, stream_mode: :hash, **args, &block)
85
85
  else
86
86
  raise(ArgumentError, "Invalid tabular_input_mode: #{stream_mode.inspect}")
87
87
  end
@@ -113,7 +113,7 @@ module RocketJob
113
113
  end
114
114
 
115
115
  def tabular_input_header_present
116
- return if tabular_input_header.present? || !tabular_input.header? || (tabular_input_mode == :record)
116
+ return if tabular_input_header.present? || !tabular_input.header? || (tabular_input_mode == :hash || tabular_input_mode == :record)
117
117
 
118
118
  errors.add(:tabular_input_header, "is required when tabular_input_format is #{tabular_input_format.inspect}")
119
119
  end
@@ -10,9 +10,11 @@ module RocketJob
10
10
  include SemanticLogger::Loggable
11
11
  attr_accessor :environment, :pidfile, :directory, :quiet,
12
12
  :log_level, :log_file, :mongo_config, :symmetric_encryption_config,
13
- :max_workers, :include_filter, :exclude_filter, :where_filter
13
+ :max_workers, :include_filter, :exclude_filter, :where_filter, :server,
14
+ :stop_server, :kill_server, :pause_server, :resume_server, :thread_dump, :list_servers, :refresh
14
15
 
15
16
  def initialize(argv)
17
+ @server = true
16
18
  @quiet = false
17
19
  @environment = nil
18
20
  @pidfile = nil
@@ -23,13 +25,19 @@ module RocketJob
23
25
  @symmetric_encryption_config = nil
24
26
  @include_filter = nil
25
27
  @exclude_filter = nil
28
+ @stop_server = nil
29
+ @kill_server = nil
30
+ @pause_server = nil
31
+ @resume_server = nil
32
+ @thread_dump = nil
33
+ @list_servers = nil
26
34
  parse(argv)
27
35
  end
28
36
 
29
37
  # Run a RocketJob::Server from the command line
30
38
  def run
31
39
  Thread.current.name = 'rocketjob main'
32
- RocketJob.server!
40
+ RocketJob.server! if server
33
41
  setup_environment
34
42
  setup_logger
35
43
  rails? ? boot_rails : boot_standalone
@@ -39,14 +47,22 @@ module RocketJob
39
47
  # In case Rails did not load the Mongoid Config
40
48
  RocketJob::Config.load!(environment, mongo_config, symmetric_encryption_config) if ::Mongoid::Config.clients.empty?
41
49
 
50
+ return perform_server_action(stop_server, :stop) if stop_server
51
+ return perform_server_action(kill_server, :kill) if kill_server
52
+ return perform_server_action(pause_server, :pause) if pause_server
53
+ return perform_server_action(resume_server, :resume) if resume_server
54
+ return perform_server_action(thread_dump, :thread_dump) if thread_dump
55
+ return perform_list_servers(list_servers) if list_servers
56
+
42
57
  Supervisor.run
43
58
  end
44
59
 
45
60
  def rails?
46
- @rails ||= begin
47
- boot_file = Pathname.new(directory).join('config/environment.rb').expand_path
48
- boot_file.file?
49
- end
61
+ @rails ||=
62
+ begin
63
+ boot_file = Pathname.new(directory).join('config/environment.rb').expand_path
64
+ boot_file.file?
65
+ end
50
66
  end
51
67
 
52
68
  # Initialize the Rails environment
@@ -155,6 +171,68 @@ module RocketJob
155
171
  end
156
172
  end
157
173
 
174
+ def perform_list_servers(filter)
175
+ return list_the_servers(filter) unless refresh
176
+
177
+ while true
178
+ list_the_servers(filter)
179
+ sleep(refresh)
180
+ puts
181
+ end
182
+ end
183
+
184
+ def list_the_servers(filter)
185
+ format = "%50.50s %20.20s %20.20s %20.20s %10.10s"
186
+ puts format % %w[Server\ Name Workers(Current/Max) Started Heartbeat State]
187
+ header = "=" * 50
188
+ puts format % [header, header, header, header, header]
189
+ query = filter == :all ? RocketJob::Server.all : RocketJob::Server.where(name: /#{filter}/)
190
+ query.each do |server|
191
+ workers = "#{server&.heartbeat&.workers}/#{server.max_workers}"
192
+ duration = Time.now - (server.started_at || Time.now)
193
+ started = "#{RocketJob.seconds_as_duration(duration)} ago"
194
+ duration = Time.now - (server&.heartbeat&.updated_at || Time.now)
195
+ heartbeat = "#{RocketJob.seconds_as_duration(duration)} ago"
196
+ puts format % [server.name, workers, started, heartbeat, server.state]
197
+ end
198
+ 0
199
+ end
200
+
201
+ def perform_server_action(server_name, action)
202
+ server_ids(server_name).each { |server_id| RocketJob::Subscribers::Server.publish(action, server_id: server_id) }
203
+ #RocketJob::Subscribers::Worker.publish(:stop, worker_id: 1, server_id: RocketJob::Server.running.last.id)
204
+ 0
205
+ end
206
+
207
+ # Returns server ids for the supplied exact server name, or partial match.
208
+ #
209
+ # When no ':' is supplied a partial hostname lookup is performed.
210
+ #
211
+ # Example: Exact server name (hostname and pid) match:
212
+ # "9cdbe7e995bc:1"
213
+ #
214
+ # Example: Matches all servers that contain the string '.batch.user.org':
215
+ # ".batch.user.org"
216
+ def server_ids(server_name)
217
+ raise(ArgumentError, "Missing server name") unless server_name
218
+
219
+ return [nil] if server_name == :all
220
+
221
+ hostname, pid = server_name.split(":")
222
+ raise(ArgumentError, "Missing server name in: #{server_name}") unless hostname
223
+
224
+ if pid
225
+ server = RocketJob::Server.where(name: server_name).first
226
+ raise(ArgumentError, "No server with exact name: #{server_name} was found.") unless server
227
+ return [server.id]
228
+ end
229
+
230
+ server_ids = RocketJob::Server.where(name: /#{hostname}/).collect(&:id)
231
+ raise(ArgumentError, "No server with partial name: #{server_name} was found.") if server_ids.empty?
232
+
233
+ server_ids
234
+ end
235
+
158
236
  # Parse command line options placing results in the corresponding instance variables
159
237
  def parse(argv)
160
238
  parser = OptionParser.new do |o|
@@ -201,6 +279,39 @@ module RocketJob
201
279
  o.on('-s', '--symmetric-encryption SYMMETRIC_ENCRYPTION_CONFIG_FILE_NAME', 'Path and filename of Symmetric Encryption config file. Default: config/symmetric-encryption.yml') do |arg|
202
280
  @symmetric_encryption_config = arg
203
281
  end
282
+ o.on('--list [FILTER]', "List active servers. Supply either an exact server name or a partial name as a filter.") do |filter|
283
+ @quiet = true
284
+ @server = false
285
+ @list_servers = filter || :all
286
+ end
287
+ o.on('--refresh [SECONDS]', "When listing active servers, update the list by this number of seconds. Defaults to every 1 second.") do |seconds|
288
+ @refresh = (seconds || 1).to_s.to_f
289
+ end
290
+ o.on('--stop [SERVER_NAME]', "Send event to stop a server once all in-process workers have completed. Optionally supply the complete or partial name of the server(s) to stop. Default: All servers.") do |server_name|
291
+ @quiet = true
292
+ @server = false
293
+ @stop_server = server_name || :all
294
+ end
295
+ o.on('--kill [SERVER_NAME]', "Send event to hard kill a server. Optionally supply the complete or partial name of the server(s) to kill. Default: All servers.") do |server_name|
296
+ @quiet = true
297
+ @server = false
298
+ @kill_server = server_name || :all
299
+ end
300
+ o.on('--pause [SERVER_NAME]', "Send event to pause a server. Optionally supply the complete or partial name of the server(s) to pause. Default: All servers.") do |server_name|
301
+ @quiet = true
302
+ @server = false
303
+ @pause_server = server_name || :all
304
+ end
305
+ o.on('--resume [SERVER_NAME]', "Send event to resume a server. Optionally supply the complete or partial name of the server(s) to resume. Default: All servers.") do |server_name|
306
+ @quiet = true
307
+ @server = false
308
+ @resume_server = server_name || :all
309
+ end
310
+ o.on('--dump [SERVER_NAME]', "Send event for a server to send a worker thread dump to its log file. Optionally supply the complete or partial name of the server(s). Default: All servers.") do |server_name|
311
+ @quiet = true
312
+ @server = false
313
+ @thread_dump = server_name || :all
314
+ end
204
315
  o.on('-v', '--version', 'Print the version information') do
205
316
  puts "Rocket Job v#{RocketJob::VERSION}"
206
317
  exit 1
@@ -81,11 +81,11 @@ module RocketJob
81
81
  end
82
82
  end
83
83
 
84
+ synchronize { server.refresh(worker_pool.living_count) }
85
+
84
86
  self.class.wait_for_event(Config.heartbeat_seconds)
85
87
 
86
88
  break if self.class.shutdown?
87
-
88
- synchronize { server.refresh(worker_pool.living_count) }
89
89
  end
90
90
  end
91
91
 
@@ -1,3 +1,3 @@
1
1
  module RocketJob
2
- VERSION = '5.0.0.rc1'.freeze
2
+ VERSION = '5.0.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rocketjob
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.0.rc1
4
+ version: 5.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Reid Morrison
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-12-09 00:00:00.000000000 Z
11
+ date: 2020-01-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aasm
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 1.0.0.beta2
47
+ version: '1.0'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 1.0.0.beta2
54
+ version: '1.0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: mongoid
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -192,9 +192,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
192
192
  version: '2.3'
193
193
  required_rubygems_version: !ruby/object:Gem::Requirement
194
194
  requirements:
195
- - - ">"
195
+ - - ">="
196
196
  - !ruby/object:Gem::Version
197
- version: 1.3.1
197
+ version: '0'
198
198
  requirements: []
199
199
  rubygems_version: 3.0.6
200
200
  signing_key: