process_bot 0.1.16 → 0.1.18

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: 7d79a43f8a6bdf408f637e66fff579115ab45f57f0c8c0314d98c1e84a8f4430
4
- data.tar.gz: 716c9b8e69f54f1dc60a322d1ddad7f4336b464e338964ffa9f736d7cac11477
3
+ metadata.gz: 00371cf3c9ed3fa904d5d3a8655be99178ce77a729ab2aad459572fc63bb4779
4
+ data.tar.gz: db9145067629c7872c810c03e1e97caa6c626837ec26d07fa6ceeebf1a623bdd
5
5
  SHA512:
6
- metadata.gz: 2739cfa0148b5085b45f0ca273d583f609413346e7d7ebed3693fb3715ebeb2ad4c14475b212c82a86e3bc1081585f2edc606c0d2f7ae2159a61722cfc1bc0c1
7
- data.tar.gz: f59153145d7e36da05d9d9dc98d6e7d2f0a3b8f03fcfb51606b800453685f2fcb45e07eca46395cbdeac095f041749eb2064b9f98bc6dfe1c5e7d3fad5611e35
6
+ metadata.gz: 89a0dde6cbadf510efb51b07f690ec90ca03af46ba06c9a1eca1f75a86e718bf23d263207aedd5a2763463e9470d9655d81487d5073f24a077edd1798acb2691
7
+ data.tar.gz: 27a95d5f8911f704c15faf58339c0173ca6cc01a3d7e8caa70743d6f3eadbbb9a44122b2ece7e74feaf4b7b6e7a03b1d7809e22cfa26efb4eb9967972f6846ff
data/CHANGELOG.md CHANGED
@@ -1,4 +1,5 @@
1
1
  ## [Unreleased]
2
+ - Stop accepting new control commands during shutdown so in-flight responses complete reliably.
2
3
 
3
4
  ## [0.1.0] - 2022-04-03
4
5
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- process_bot (0.1.16)
4
+ process_bot (0.1.18)
5
5
  knjrbfw (>= 0.0.116)
6
6
  pry
7
7
  rake
data/README.md CHANGED
@@ -44,7 +44,7 @@ ProcessBot provides these Sidekiq tasks:
44
44
  - `process_bot:sidekiq:stop`
45
45
  - `process_bot:sidekiq:graceful` (stops fetching new jobs and waits for running jobs by default)
46
46
  - `process_bot:sidekiq:graceful_no_wait` (stops fetching new jobs and returns immediately)
47
- - `process_bot:sidekiq:ensure_running` (starts missing processes, ignoring ones in graceful shutdown)
47
+ - `process_bot:sidekiq:ensure_running` (starts missing processes, including replacements for graceful shutdowns)
48
48
  - `process_bot:sidekiq:restart`
49
49
 
50
50
  You can also skip waiting for graceful completion:
@@ -70,7 +70,7 @@ namespace :process_bot do
70
70
  end
71
71
  end
72
72
 
73
- desc "Ensure the configured number of Sidekiq ProcessBots are running (excluding graceful shutdowns)"
73
+ desc "Ensure the configured number of Sidekiq ProcessBots are running (starts replacements for graceful shutdowns)"
74
74
  task :ensure_running do
75
75
  on roles fetch(:sidekiq_roles) do |role|
76
76
  git_plugin.switch_user(role) do
@@ -91,10 +91,12 @@ namespace :process_bot do
91
91
  git_plugin.process_bot_sidekiq_index(process_bot_data)
92
92
  end
93
93
 
94
- puts "ProcessBot Sidekiq in graceful shutdown: #{graceful_indexes.join(", ")}" if graceful_indexes.any?
94
+ if graceful_indexes.any?
95
+ puts "ProcessBot Sidekiq in graceful shutdown: #{graceful_indexes.join(", ")}"
96
+ puts "Starting replacements for graceful shutdowns to reach #{desired_processes} running processes"
97
+ end
95
98
 
96
- desired_indexes = (0...desired_processes).to_a
97
- missing_indexes = desired_indexes - active_indexes - graceful_indexes
99
+ missing_indexes = git_plugin.missing_sidekiq_indexes(desired_processes, active_indexes)
98
100
  missing_count = desired_processes - active_indexes.count
99
101
 
100
102
  if missing_count.negative?
@@ -107,14 +109,9 @@ namespace :process_bot do
107
109
  puts "Starting Sidekiq with ProcessBot #{idx} (missing)"
108
110
  git_plugin.start_sidekiq(idx)
109
111
  end
110
- else
112
+ elsif missing_count.zero?
111
113
  puts "All ProcessBot Sidekiq processes are running (#{active_indexes.count}/#{desired_processes})"
112
114
  end
113
-
114
- return unless missing_count > missing_indexes.length
115
-
116
- puts "Skipped starting #{missing_count - missing_indexes.length} processes because " \
117
- "they are still in graceful shutdown"
118
115
  end
119
116
  end
120
117
  end
@@ -118,6 +118,12 @@ module ProcessBot::Capistrano::SidekiqHelpers # rubocop:disable Metrics/ModuleLe
118
118
  false
119
119
  end
120
120
 
121
+ def missing_sidekiq_indexes(desired_processes, active_indexes)
122
+ desired = desired_processes.to_i
123
+ desired_indexes = (0...desired).to_a
124
+ desired_indexes - active_indexes
125
+ end
126
+
121
127
  def sidekiq_user(role = nil)
122
128
  if role.nil?
123
129
  fetch(:sidekiq_user)
@@ -79,13 +79,20 @@ class ProcessBot::ControlSocket
79
79
 
80
80
  if command_type == "graceful" || command_type == "graceful_no_wait" || command_type == "stop"
81
81
  begin
82
+ unless process.accept_control_commands?
83
+ client.puts(JSON.generate(type: "error", message: "ProcessBot is shutting down", backtrace: Thread.current.backtrace))
84
+ break
85
+ end
86
+
82
87
  command_options = if command["options"]
83
88
  symbolize_keys(command.fetch("options"))
84
89
  else
85
90
  {}
86
91
  end
87
92
 
88
- run_command(command_type, command_options, client)
93
+ process.with_control_command do
94
+ run_command(command_type, command_options, client)
95
+ end
89
96
  rescue => e # rubocop:disable Style/RescueStandardError
90
97
  logger.error e.message
91
98
  logger.error e.backtrace
@@ -1,5 +1,6 @@
1
1
  require "forwardable"
2
2
  require "json"
3
+ require "monitor"
3
4
  require "string-cases"
4
5
 
5
6
  class ProcessBot::Process
@@ -12,11 +13,14 @@ class ProcessBot::Process
12
13
  autoload :Handlers, "#{__dir__}/process/handlers"
13
14
  autoload :Runner, "#{__dir__}/process/runner"
14
15
 
15
- attr_reader :current_pid, :current_process_title, :options, :port, :stopped
16
+ attr_reader :control_command_monitor, :current_pid, :current_process_title, :options, :port, :stopped
16
17
 
17
18
  def initialize(options)
18
19
  @options = options
19
20
  @stopped = false
21
+ @accept_control_commands = true
22
+ @control_command_monitor = Monitor.new
23
+ @control_commands_in_flight = 0
20
24
 
21
25
  options.events.connect(:on_process_started, &method(:on_process_started)) # rubocop:disable Performance/MethodObjectAsBlock
22
26
  options.events.connect(:on_socket_opened, &method(:on_socket_opened)) # rubocop:disable Performance/MethodObjectAsBlock
@@ -86,6 +90,8 @@ class ProcessBot::Process
86
90
  run
87
91
 
88
92
  if stopped
93
+ stop_accepting_control_commands
94
+ wait_for_control_commands
89
95
  break
90
96
  else
91
97
  logger.logs "Process stopped - starting again after 1 sec"
@@ -127,4 +133,35 @@ class ProcessBot::Process
127
133
  @current_process_title = "ProcessBot #{JSON.generate(process_args)}"
128
134
  Process.setproctitle(current_process_title)
129
135
  end
136
+
137
+ def with_control_command
138
+ control_command_monitor.synchronize do
139
+ @control_commands_in_flight += 1
140
+ end
141
+
142
+ yield
143
+ ensure
144
+ control_command_monitor.synchronize do
145
+ @control_commands_in_flight -= 1
146
+ end
147
+ end
148
+
149
+ def accept_control_commands?
150
+ @accept_control_commands
151
+ end
152
+
153
+ def stop_accepting_control_commands
154
+ @accept_control_commands = false
155
+ @control_socket&.stop
156
+ end
157
+
158
+ def wait_for_control_commands
159
+ sleep 0.1 while control_commands_in_flight.positive?
160
+ end
161
+
162
+ def control_commands_in_flight
163
+ control_command_monitor.synchronize do
164
+ @control_commands_in_flight
165
+ end
166
+ end
130
167
  end
@@ -1,3 +1,3 @@
1
1
  module ProcessBot
2
- VERSION = "0.1.16".freeze
2
+ VERSION = "0.1.18".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.16
4
+ version: 0.1.18
5
5
  platform: ruby
6
6
  authors:
7
7
  - kaspernj
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-01-06 00:00:00.000000000 Z
11
+ date: 2026-01-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: knjrbfw