process_bot 0.1.3 → 0.1.5

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: b719a497be535319bf027f1669321e58466f845657bdebb82f94d78f6d6e984f
4
- data.tar.gz: cbbbc984e75edacbcdf6e9f8579633e6ebac87cf4e0690b944a7e32b4424c4f1
3
+ metadata.gz: 8ba4b3227493fa167bf23dfa8338ab83baf626a444eb91ff98d8d7ce40056cc2
4
+ data.tar.gz: 605f53e2980a549cb945470e6010877ce2b4eed5f5adef5dd7c80f2f46976332
5
5
  SHA512:
6
- metadata.gz: fdbd9fd4a6196cf6d9183289ec7c9ee984d25e5e2af0af5c8213a5fe649865687aa70f0dcf5a49f91100c7ceae72298e9bb9bdcb9dac9861c86b50209528d1a6
7
- data.tar.gz: 97942320a0a9354770aa8f4e155a620a1c232c5fd712d2269f525d76b1a00adc2480c6c8e51c79c8eb2047a391224c6597e4c9bc74bf4b3369aa0664b7418e1d
6
+ metadata.gz: cf82581d6d23036f2bbd5a91587f752b89d45e5c24a045193acd24911eb7ef5e427991baa7d0c6bb9299207c0c67595b4b645fb13743737e5771fde19063edba
7
+ data.tar.gz: 49f2aeca472a0a5957b86f70db38be1516faf8503ba04b70108e6ef8bf91b40b1bd2cb241339e79b447ba47290e47a25c81568cf516fbfa057a0745742f7e061
data/Gemfile.lock CHANGED
@@ -1,19 +1,19 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- process_bot (0.1.3)
4
+ process_bot (0.1.5)
5
5
  knjrbfw (>= 0.0.116)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- ast (2.4.2)
10
+ ast (2.4.3)
11
11
  coderay (1.1.3)
12
12
  datet (0.0.25)
13
- diff-lcs (1.5.0)
13
+ diff-lcs (1.5.1)
14
14
  http2 (0.0.36)
15
15
  string-cases (~> 0)
16
- json (2.6.3)
16
+ json (2.10.2)
17
17
  knjrbfw (0.0.116)
18
18
  datet
19
19
  http2
@@ -21,56 +21,63 @@ GEM
21
21
  ruby_process
22
22
  tsafe
23
23
  wref (>= 0.0.8)
24
- method_source (1.0.0)
25
- parallel (1.23.0)
26
- parser (3.2.2.0)
24
+ language_server-protocol (3.17.0.4)
25
+ lint_roller (1.1.0)
26
+ method_source (1.1.0)
27
+ parallel (1.26.3)
28
+ parser (3.3.7.4)
27
29
  ast (~> 2.4.1)
30
+ racc
28
31
  php4r (0.0.4)
29
32
  datet
30
33
  http2
31
34
  string-strtr
32
- pry (0.14.2)
35
+ prism (1.4.0)
36
+ pry (0.15.2)
33
37
  coderay (~> 1.1)
34
38
  method_source (~> 1.0)
39
+ racc (1.8.1)
35
40
  rainbow (3.1.1)
36
- rake (13.0.6)
37
- regexp_parser (2.8.0)
38
- rexml (3.2.5)
39
- rspec (3.12.0)
40
- rspec-core (~> 3.12.0)
41
- rspec-expectations (~> 3.12.0)
42
- rspec-mocks (~> 3.12.0)
43
- rspec-core (3.12.0)
44
- rspec-support (~> 3.12.0)
45
- rspec-expectations (3.12.0)
41
+ rake (13.2.1)
42
+ ref (2.0.0)
43
+ regexp_parser (2.10.0)
44
+ rspec (3.13.0)
45
+ rspec-core (~> 3.13.0)
46
+ rspec-expectations (~> 3.13.0)
47
+ rspec-mocks (~> 3.13.0)
48
+ rspec-core (3.13.0)
49
+ rspec-support (~> 3.13.0)
50
+ rspec-expectations (3.13.0)
46
51
  diff-lcs (>= 1.2.0, < 2.0)
47
- rspec-support (~> 3.12.0)
48
- rspec-mocks (3.12.0)
52
+ rspec-support (~> 3.13.0)
53
+ rspec-mocks (3.13.0)
49
54
  diff-lcs (>= 1.2.0, < 2.0)
50
- rspec-support (~> 3.12.0)
51
- rspec-support (3.12.0)
52
- rubocop (1.50.2)
55
+ rspec-support (~> 3.13.0)
56
+ rspec-support (3.13.0)
57
+ rubocop (1.75.2)
53
58
  json (~> 2.3)
59
+ language_server-protocol (~> 3.17.0.2)
60
+ lint_roller (~> 1.1.0)
54
61
  parallel (~> 1.10)
55
- parser (>= 3.2.0.0)
62
+ parser (>= 3.3.0.2)
56
63
  rainbow (>= 2.2.2, < 4.0)
57
- regexp_parser (>= 1.8, < 3.0)
58
- rexml (>= 3.2.5, < 4.0)
59
- rubocop-ast (>= 1.28.0, < 2.0)
64
+ regexp_parser (>= 2.9.3, < 3.0)
65
+ rubocop-ast (>= 1.44.0, < 2.0)
60
66
  ruby-progressbar (~> 1.7)
61
- unicode-display_width (>= 2.4.0, < 3.0)
62
- rubocop-ast (1.28.0)
63
- parser (>= 3.2.1.0)
64
- rubocop-capybara (2.18.0)
65
- rubocop (~> 1.41)
66
- rubocop-performance (1.17.1)
67
- rubocop (>= 1.7.0, < 2.0)
68
- rubocop-ast (>= 0.4.0)
69
- rubocop-rake (0.6.0)
70
- rubocop (~> 1.0)
71
- rubocop-rspec (2.20.0)
72
- rubocop (~> 1.33)
73
- rubocop-capybara (~> 2.17)
67
+ unicode-display_width (>= 2.4.0, < 4.0)
68
+ rubocop-ast (1.44.0)
69
+ parser (>= 3.3.7.2)
70
+ prism (~> 1.4)
71
+ rubocop-performance (1.25.0)
72
+ lint_roller (~> 1.1)
73
+ rubocop (>= 1.75.0, < 2.0)
74
+ rubocop-ast (>= 1.38.0, < 2.0)
75
+ rubocop-rake (0.7.1)
76
+ lint_roller (~> 1.1)
77
+ rubocop (>= 1.72.1)
78
+ rubocop-rspec (3.5.0)
79
+ lint_roller (~> 1.1)
80
+ rubocop (~> 1.72, >= 1.72.1)
74
81
  ruby-progressbar (1.13.0)
75
82
  ruby_process (0.0.13)
76
83
  string-cases
@@ -79,8 +86,11 @@ GEM
79
86
  string-cases (0.0.4)
80
87
  string-strtr (0.0.3)
81
88
  tsafe (0.0.12)
82
- unicode-display_width (2.4.2)
83
- wref (0.0.8)
89
+ unicode-display_width (3.1.4)
90
+ unicode-emoji (~> 4.0, >= 4.0.4)
91
+ unicode-emoji (4.0.4)
92
+ wref (0.0.11)
93
+ ref
84
94
 
85
95
  PLATFORMS
86
96
  ruby
data/README.md CHANGED
@@ -2,7 +2,10 @@
2
2
 
3
3
  Run your app through ProcessBot for automatic restart if crashing, but still support normal deployment through Capistrano.
4
4
 
5
- In the future ProcessBot will also watch memory usage and restart processes if leaking memory automatically and gracefully.
5
+ Watch memory usage for Sidekiq and restart gracefully if it exceeds a given limit (to counter memory leaks).
6
+
7
+ When deploying can gracefully exit Sidekiq to let long running jobs finish on old version of code, and start new Sidekiq processes after finishing deploy (but still let the old ones finish gracefully so nothing gets interrupted).
8
+ This requires not to remove columns, rename columns or any other intrusive database changes.
6
9
 
7
10
  ## Installation
8
11
 
data/exe/process_bot CHANGED
@@ -18,6 +18,12 @@ while argv_i < ARGV.length
18
18
 
19
19
  if (match = arg.match(/\A--(.+)\Z/))
20
20
  key = match[1].tr("-", "_").to_sym
21
+
22
+ if key == :path
23
+ puts "Path: #{File.realpath("#{__dir__}/..")}"
24
+ exit
25
+ end
26
+
21
27
  argv_i += 1
22
28
  value = ARGV.fetch(argv_i)
23
29
 
@@ -32,16 +32,34 @@ module ProcessBot::Capistrano::SidekiqHelpers # rubocop:disable Metrics/ModuleLe
32
32
  end
33
33
  end
34
34
 
35
- def process_bot_command(process_bot_data, command)
35
+ def process_bot_command(process_bot_data, command) # rubocop:disable Metrics/AbcSize
36
36
  raise "No port in process bot data? #{process_bot_data}" unless process_bot_data["port"]
37
37
 
38
- backend_command = "cd #{release_path} && " \
39
- "#{SSHKit.config.command_map.prefix[:bundle].join(" ")} bundle exec process_bot " \
40
- "--command #{command} " \
41
- "--port #{process_bot_data.fetch("port")}"
38
+ mode = "exec"
42
39
 
43
- if command == :graceful && !fetch(:process_bot_wait_for_gracefully_stopped).nil?
44
- backend_command << " --wait-for-gracefully-stopped #{fetch(:process_bot_wait_for_gracefully_stopped)}"
40
+ if mode == "runner"
41
+ args = {command: command, port: process_bot_data.fetch("port")}
42
+
43
+ if command == :graceful && !fetch(:process_bot_wait_for_gracefully_stopped).nil?
44
+ args["wait_for_gracefully_stopped"] = fetch(:process_bot_wait_for_gracefully_stopped)
45
+ end
46
+
47
+ escaped_args = JSON.generate(args).gsub("\"", "\\\"")
48
+ rails_runner_command = "require 'process_bot'; ProcessBot::Process.new(ProcessBot::Options.from_args(#{escaped_args})).execute!"
49
+
50
+ backend_command = "cd #{release_path} && " \
51
+ "#{SSHKit.config.command_map.prefix[:bundle].join(" ")} bundle exec rails runner \"#{rails_runner_command}\""
52
+ elsif mode == "exec"
53
+ backend_command = "cd #{release_path} && " \
54
+ "#{SSHKit.config.command_map.prefix[:bundle].join(" ")} bundle exec process_bot " \
55
+ "--command #{command} " \
56
+ "--port #{process_bot_data.fetch("port")}"
57
+
58
+ if command == :graceful && !fetch(:process_bot_wait_for_gracefully_stopped).nil?
59
+ backend_command << " --wait-for-gracefully-stopped #{fetch(:process_bot_wait_for_gracefully_stopped)}"
60
+ end
61
+ else
62
+ raise "Unknown mode: #{mode}"
45
63
  end
46
64
 
47
65
  backend.execute backend_command
@@ -126,7 +144,7 @@ module ProcessBot::Capistrano::SidekiqHelpers # rubocop:disable Metrics/ModuleLe
126
144
  screen_args = ["-dmS process-bot--sidekiq--#{idx}-#{latest_release_version}"]
127
145
 
128
146
  if (process_bot_sidekiq_log = fetch(:process_bot_sidekig_log))
129
- screen_args << "-L -Logfile #{process_bot_sidekiq_log}"
147
+ screen_args << "-L -Logfile #{process_bot_sidekiq_log}_#{latest_release_version}_#{idx}.log"
130
148
  elsif fetch(:sidekiq_log)
131
149
  screen_args << "-L -Logfile #{fetch(:sidekiq_log)}"
132
150
  end
@@ -8,14 +8,19 @@ class ProcessBot::ClientSocket
8
8
  end
9
9
 
10
10
  def client
11
- @client ||= TCPSocket.new("localhost", options.fetch(:port).to_i)
11
+ @client ||= Socket.tcp("localhost", options.fetch(:port).to_i, connect_timeout: 2)
12
12
  end
13
13
 
14
14
  def close
15
15
  client.close
16
16
  end
17
17
 
18
- def send_command(data)
18
+ def logger
19
+ @logger ||= ProcessBot::Logger.new(options: options)
20
+ end
21
+
22
+ def send_command(data) # rubocop:disable Metrics/AbcSize
23
+ logger.log "Sending: #{data}"
19
24
  client.puts(JSON.generate(data))
20
25
  response_raw = client.gets
21
26
 
@@ -26,6 +31,11 @@ class ProcessBot::ClientSocket
26
31
 
27
32
  return :success if response.fetch("type") == "success"
28
33
 
29
- raise "Command raised an error: #{response.fetch("message")}" if response.fetch("type") == "error"
34
+ if response.fetch("type") == "error"
35
+ error = RuntimeError.new("Command raised an error: #{response.fetch("message")}")
36
+ error.set_backtrace(response.fetch("backtrace") + Thread.current.backtrace)
37
+
38
+ raise error
39
+ end
30
40
  end
31
41
  end
@@ -1,24 +1,36 @@
1
1
  require "socket"
2
2
 
3
3
  class ProcessBot::ControlSocket
4
- attr_reader :options, :process, :server
4
+ attr_reader :options, :port, :process, :server
5
5
 
6
6
  def initialize(options:, process:)
7
7
  @options = options
8
8
  @process = process
9
+ @port = options.fetch(:port).to_i
9
10
  end
10
11
 
11
- def port
12
- options.fetch(:port).to_i
12
+ def logger
13
+ @logger ||= ProcessBot::Logger.new(options: options)
13
14
  end
14
15
 
15
16
  def start
16
- @server = TCPServer.new("localhost", port)
17
+ start_tcp_server
17
18
  run_client_loop
19
+ logger.logs "TCPServer started"
20
+ options.events.call(:on_socket_opened, port: @port)
21
+ end
18
22
 
19
- puts "TCPServer started"
20
-
21
- options.events.call(:on_socket_opened, port: port)
23
+ def start_tcp_server
24
+ tries ||= 0
25
+ tries += 1
26
+ @server = TCPServer.new("localhost", @port)
27
+ rescue Errno::EADDRNOTAVAIL => e
28
+ if tries <= 100
29
+ @port += 1
30
+ retry
31
+ else
32
+ raise e
33
+ end
22
34
  end
23
35
 
24
36
  def stop
@@ -45,16 +57,38 @@ class ProcessBot::ControlSocket
45
57
 
46
58
  if command_type == "graceful" || command_type == "stop"
47
59
  begin
48
- process.__send__(command_type)
60
+ command_options = if command["options"]
61
+ symbolize_keys(command.fetch("options"))
62
+ else
63
+ {}
64
+ end
65
+
66
+ logger.logs "Command #{command_type} with options #{command_options}"
67
+
68
+ process.__send__(command_type, **command_options)
49
69
  client.puts(JSON.generate(type: "success"))
50
70
  rescue => e # rubocop:disable Style/RescueStandardError
51
- client.puts(JSON.generate(type: "error", message: e.message))
71
+ logger.logs e.message, type: :stderr
72
+ logger.logs e.backtrace, type: :stderr
73
+
74
+ client.puts(JSON.generate(type: "error", message: e.message, backtrace: e.backtrace))
52
75
 
53
76
  raise e
54
77
  end
55
78
  else
56
- client.puts(JSON.generate(type: "error", message: "Unknown command: #{command_type}"))
79
+ client.puts(JSON.generate(type: "error", message: "Unknown command: #{command_type}", backtrace: Thread.current.backtrace))
57
80
  end
58
81
  end
59
82
  end
83
+
84
+ def symbolize_keys(hash)
85
+ new_hash = {}
86
+ hash.each do |key, value|
87
+ next if key == "port"
88
+
89
+ new_hash[key.to_sym] = value
90
+ end
91
+
92
+ new_hash
93
+ end
60
94
  end
@@ -6,7 +6,7 @@ class ProcessBot::Logger
6
6
  end
7
7
 
8
8
  def log(output, type: :stdout)
9
- if type == :stdout
9
+ if type == :stdout || (type == :debug && options[:debug])
10
10
  $stdout.print output
11
11
  elsif type == :stderr
12
12
  $stderr.print output
@@ -20,6 +20,10 @@ class ProcessBot::Logger
20
20
  fp_log.flush
21
21
  end
22
22
 
23
+ def logs(output, **args)
24
+ log("#{output}\n", **args)
25
+ end
26
+
23
27
  def log_file_path
24
28
  options.fetch(:log_file_path)
25
29
  end
@@ -1,6 +1,16 @@
1
1
  class ProcessBot::Options
2
2
  attr_reader :options
3
3
 
4
+ def self.from_args(args)
5
+ options = ProcessBot::Options.new
6
+
7
+ args.each do |key, value|
8
+ options.set(key, value)
9
+ end
10
+
11
+ options
12
+ end
13
+
4
14
  def initialize(options = {})
5
15
  @options = options
6
16
  end
@@ -1,14 +1,38 @@
1
1
  class ProcessBot::Process::Handlers::Sidekiq
2
- attr_reader :options
2
+ attr_reader :options, :process
3
3
 
4
- def initialize(options)
5
- @options = options
4
+ def initialize(process)
5
+ @process = process
6
+ @options = process.options
7
+ end
8
+
9
+ def current_pid
10
+ process.current_pid
11
+ end
12
+
13
+ def daemonize
14
+ logger.logs "Daemonize!"
15
+
16
+ pid = Process.fork do
17
+ Process.daemon
18
+ yield
19
+ end
20
+
21
+ Process.detach(pid) if pid
22
+ end
23
+
24
+ def false_value?(value)
25
+ !value || value == "false"
6
26
  end
7
27
 
8
28
  def fetch(*args, **opts)
9
29
  options.fetch(*args, **opts)
10
30
  end
11
31
 
32
+ def logger
33
+ @logger ||= ProcessBot::Logger.new(options: options)
34
+ end
35
+
12
36
  def set_option(key, value)
13
37
  raise "Unknown option for Sidekiq handler: #{key}" unless options.key?(key)
14
38
 
@@ -42,4 +66,72 @@ class ProcessBot::Process::Handlers::Sidekiq
42
66
  command << "'"
43
67
  command
44
68
  end
69
+
70
+ def graceful(**args)
71
+ wait_for_gracefully_stopped = args.fetch(:wait_for_gracefully_stopped, true)
72
+ process.set_stopped
73
+
74
+ unless current_pid
75
+ warn "Sidekiq not running with a PID"
76
+ return
77
+ end
78
+
79
+ Process.kill("TSTP", current_pid)
80
+
81
+ if false_value?(wait_for_gracefully_stopped)
82
+ logger.logs "Dont wait for gracefully stopped - doing that in fork..."
83
+
84
+ daemonize do
85
+ wait_for_no_jobs_and_stop_sidekiq
86
+ exit
87
+ end
88
+ else
89
+ logger.logs "Wait for gracefully stopped..."
90
+ wait_for_no_jobs_and_stop_sidekiq
91
+ end
92
+ end
93
+
94
+ def stop(**_args)
95
+ process.set_stopped
96
+
97
+ unless current_pid
98
+ warn "#{handler_name} not running with a PID"
99
+ return
100
+ end
101
+
102
+ Process.kill("TERM", current_pid)
103
+ end
104
+
105
+ def wait_for_no_jobs # rubocop:disable Metrics/AbcSize
106
+ loop do
107
+ found_process = false
108
+
109
+ Knj::Unix_proc.list("grep" => current_pid) do |process|
110
+ process_command = process.data.fetch("cmd")
111
+ process_pid = process.data.fetch("pid").to_i
112
+ next unless process_pid == current_pid
113
+
114
+ found_process = true
115
+ sidekiq_regex = /\Asidekiq (\d+).(\d+).(\d+) (#{options.possible_process_titles_joined_regex}) \[(\d+) of (\d+)(\]|) (.+?)(\]|)\Z/
116
+ match = process_command.match(sidekiq_regex)
117
+ raise "Couldnt match Sidekiq command: #{process_command} with Sidekiq regex: #{sidekiq_regex}" unless match
118
+
119
+ running_jobs = match[5].to_i
120
+
121
+ logger.logs "running_jobs: #{running_jobs}"
122
+
123
+ return if running_jobs.zero? # rubocop:disable Lint/NonLocalExitFromIterator
124
+ end
125
+
126
+ raise "Couldn't find running process with PID #{current_pid}" unless found_process
127
+
128
+ sleep 1
129
+ end
130
+ end
131
+
132
+ def wait_for_no_jobs_and_stop_sidekiq
133
+ logger.logs "Wait for no jobs and Stop sidekiq"
134
+ wait_for_no_jobs
135
+ stop
136
+ end
45
137
  end
@@ -27,7 +27,7 @@ class ProcessBot::Process::Runner
27
27
 
28
28
  PTY.spawn(command, err: stderr_writer.fileno) do |stdout, _stdin, pid|
29
29
  @subprocess_pid = pid
30
- logger.log "Command running with PID #{pid}: #{command}\n"
30
+ logger.logs "Command running with PID #{pid}: #{command}"
31
31
 
32
32
  stdout_reader_thread = Thread.new do
33
33
  stdout.each_char do |chunk|
@@ -1,6 +1,13 @@
1
+ require "forwardable"
1
2
  require "json"
3
+ require "string-cases"
2
4
 
3
5
  class ProcessBot::Process
6
+ extend Forwardable
7
+
8
+ def_delegator :handler_instance, :graceful
9
+ def_delegator :handler_instance, :stop
10
+
4
11
  autoload :Handlers, "#{__dir__}/process/handlers"
5
12
  autoload :Runner, "#{__dir__}/process/runner"
6
13
 
@@ -13,7 +20,7 @@ class ProcessBot::Process
13
20
  options.events.connect(:on_process_started, &method(:on_process_started)) # rubocop:disable Performance/MethodObjectAsBlock
14
21
  options.events.connect(:on_socket_opened, &method(:on_socket_opened)) # rubocop:disable Performance/MethodObjectAsBlock
15
22
 
16
- logger.log("Options: #{options.options}")
23
+ logger.logs("ProcessBot 1 - Options: #{options.options}")
17
24
  end
18
25
 
19
26
  def execute!
@@ -22,7 +29,7 @@ class ProcessBot::Process
22
29
  if command == "start"
23
30
  start
24
31
  elsif command == "graceful" || command == "stop"
25
- client.send_command(command: command)
32
+ client.send_command(command: command, options: options.options)
26
33
  else
27
34
  raise "Unknown command: #{command}"
28
35
  end
@@ -39,6 +46,10 @@ class ProcessBot::Process
39
46
  end
40
47
  end
41
48
 
49
+ def handler_instance
50
+ @handler_instance ||= handler_class.new(self)
51
+ end
52
+
42
53
  def handler_name
43
54
  @handler_name ||= options.fetch(:handler)
44
55
  end
@@ -71,42 +82,17 @@ class ProcessBot::Process
71
82
  if stopped
72
83
  break
73
84
  else
74
- puts "Process stopped - starting again after 1 sec"
85
+ logger.logs "Process stopped - starting again after 1 sec"
75
86
  sleep 1
76
87
  end
77
88
  end
78
89
  end
79
90
 
80
- def graceful
81
- @stopped = true
82
-
83
- unless current_pid
84
- warn "#{handler_name} not running with a PID"
85
- return
86
- end
87
-
88
- Process.kill("TSTP", current_pid)
89
-
90
- if options[:wait_for_gracefully_stopped] == "false"
91
- Thread.new { wait_for_no_jobs_and_stop_sidekiq }
92
- else
93
- wait_for_no_jobs_and_stop_sidekiq
94
- end
95
- end
96
-
97
- def stop
91
+ def set_stopped
98
92
  @stopped = true
99
-
100
- unless current_pid
101
- warn "#{handler_name} not running with a PID"
102
- return
103
- end
104
-
105
- Process.kill("TERM", current_pid)
106
93
  end
107
94
 
108
95
  def run
109
- handler_instance = handler_class.new(options)
110
96
  runner = ProcessBot::Process::Runner.new(command: handler_instance.start_command, logger: logger, options: options)
111
97
  runner.run
112
98
  end
@@ -116,38 +102,4 @@ class ProcessBot::Process
116
102
  @current_process_title = "ProcessBot #{JSON.generate(process_args)}"
117
103
  Process.setproctitle(current_process_title)
118
104
  end
119
-
120
- def wait_for_no_jobs # rubocop:disable Metrics/AbcSize
121
- loop do
122
- found_process = false
123
-
124
- Knj::Unix_proc.list("grep" => current_pid) do |process|
125
- process_command = process.data.fetch("cmd")
126
- process_pid = process.data.fetch("pid").to_i
127
- next unless process_pid == current_pid
128
-
129
- found_process = true
130
- sidekiq_regex = /\Asidekiq (\d+).(\d+).(\d+) (#{options.possible_process_titles_joined_regex}) \[(\d+) of (\d+)(\]|) (.+?)(\]|)\Z/
131
- match = process_command.match(sidekiq_regex)
132
- raise "Couldnt match Sidekiq command: #{process_command} with Sidekiq regex: #{sidekiq_regex}" unless match
133
-
134
- running_jobs = match[5].to_i
135
-
136
- puts "running_jobs: #{running_jobs}"
137
-
138
- return if running_jobs.zero? # rubocop:disable Lint/NonLocalExitFromIterator
139
- end
140
-
141
- raise "Couldn't find running process with PID #{current_pid}" unless found_process
142
-
143
- sleep 1
144
- end
145
- end
146
-
147
- def wait_for_no_jobs_and_stop_sidekiq
148
- puts "Wait for no jobs and Stop sidekiq"
149
-
150
- wait_for_no_jobs
151
- stop
152
- end
153
105
  end
@@ -1,3 +1,3 @@
1
1
  module ProcessBot
2
- VERSION = "0.1.3".freeze
2
+ VERSION = "0.1.5".freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: process_bot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - kaspernj
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-07-11 00:00:00.000000000 Z
11
+ date: 2025-04-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: knjrbfw
@@ -60,7 +60,6 @@ files:
60
60
  - lib/process_bot/process/runner.rb
61
61
  - lib/process_bot/version.rb
62
62
  - peak_flow.yml
63
- - process_bot.gemspec
64
63
  - sig/process_bot.rbs
65
64
  homepage: https://github.com/kaspernj/process_bot
66
65
  licenses:
@@ -71,7 +70,7 @@ metadata:
71
70
  source_code_uri: https://github.com/kaspernj/process_bot
72
71
  changelog_uri: https://github.com/kaspernj/process_bot/blob/master/CHANGELOG.md
73
72
  rubygems_mfa_required: 'true'
74
- post_install_message:
73
+ post_install_message:
75
74
  rdoc_options: []
76
75
  require_paths:
77
76
  - lib
@@ -87,7 +86,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
87
86
  version: '0'
88
87
  requirements: []
89
88
  rubygems_version: 3.1.6
90
- signing_key:
89
+ signing_key:
91
90
  specification_version: 4
92
91
  summary: Run and control processes.
93
92
  test_files: []
data/process_bot.gemspec DELETED
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "lib/process_bot/version"
4
-
5
- Gem::Specification.new do |spec|
6
- spec.name = "process_bot"
7
- spec.version = ProcessBot::VERSION
8
- spec.authors = ["kaspernj"]
9
- spec.email = ["k@spernj.org"]
10
-
11
- spec.summary = "Run and control processes."
12
- spec.description = "Run and control processes."
13
- spec.homepage = "https://github.com/kaspernj/process_bot"
14
- spec.license = "MIT"
15
- spec.required_ruby_version = ">= 2.7.0"
16
-
17
- spec.metadata["allowed_push_host"] = "https://rubygems.org"
18
-
19
- spec.metadata["homepage_uri"] = spec.homepage
20
- spec.metadata["source_code_uri"] = "https://github.com/kaspernj/process_bot"
21
- spec.metadata["changelog_uri"] = "https://github.com/kaspernj/process_bot/blob/master/CHANGELOG.md"
22
-
23
- # Specify which files should be added to the gem when it is released.
24
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
25
- spec.files = Dir.chdir(File.expand_path(__dir__)) do
26
- `git ls-files -z`.split("\x0").reject do |f|
27
- (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
28
- end
29
- end
30
- spec.bindir = "exe"
31
- spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
32
- spec.require_paths = ["lib"]
33
-
34
- spec.add_dependency "knjrbfw", ">= 0.0.116"
35
-
36
- spec.metadata["rubygems_mfa_required"] = "true"
37
- end