process_bot 0.1.3 → 0.1.4
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 +4 -4
- data/Gemfile.lock +22 -15
- data/exe/process_bot +6 -0
- data/lib/process_bot/capistrano/sidekiq_helpers.rb +26 -8
- data/lib/process_bot/client_socket.rb +13 -3
- data/lib/process_bot/control_socket.rb +30 -4
- data/lib/process_bot/logger.rb +5 -1
- data/lib/process_bot/options.rb +10 -0
- data/lib/process_bot/process/handlers/sidekiq.rb +95 -3
- data/lib/process_bot/process/runner.rb +1 -1
- data/lib/process_bot/process.rb +15 -63
- data/lib/process_bot/version.rb +1 -1
- metadata +3 -3
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 24914d42c043171014a4dacebea43987204236a2dadb14d2fcc4f8bda936e628
         | 
| 4 | 
            +
              data.tar.gz: b9248c4189e0d52826728401e940bed7ba46e330fb7f391d587ba00f23b160e3
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: a92b6568aaf9e799f5d318cd63c900185c4f6cacb4578c7f6fc3769933e571b27b7f48f27d7c33a93ce700d5e3990ea53c0f50a5b39c31ae9153130502c770bc
         | 
| 7 | 
            +
              data.tar.gz: 3eb45c1dd31b202ac80b0c1b7925e60ed682fd5f42210a768459c6b456d84b9a76cc7618b67ead9f576482ded5b9d47501039d51d158a5125bfab258097c43ff
         | 
    
        data/Gemfile.lock
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            PATH
         | 
| 2 2 | 
             
              remote: .
         | 
| 3 3 | 
             
              specs:
         | 
| 4 | 
            -
                process_bot (0.1. | 
| 4 | 
            +
                process_bot (0.1.4)
         | 
| 5 5 | 
             
                  knjrbfw (>= 0.0.116)
         | 
| 6 6 |  | 
| 7 7 | 
             
            GEM
         | 
| @@ -13,7 +13,7 @@ GEM | |
| 13 13 | 
             
                diff-lcs (1.5.0)
         | 
| 14 14 | 
             
                http2 (0.0.36)
         | 
| 15 15 | 
             
                  string-cases (~> 0)
         | 
| 16 | 
            -
                json (2. | 
| 16 | 
            +
                json (2.7.0)
         | 
| 17 17 | 
             
                knjrbfw (0.0.116)
         | 
| 18 18 | 
             
                  datet
         | 
| 19 19 | 
             
                  http2
         | 
| @@ -21,10 +21,12 @@ GEM | |
| 21 21 | 
             
                  ruby_process
         | 
| 22 22 | 
             
                  tsafe
         | 
| 23 23 | 
             
                  wref (>= 0.0.8)
         | 
| 24 | 
            +
                language_server-protocol (3.17.0.3)
         | 
| 24 25 | 
             
                method_source (1.0.0)
         | 
| 25 26 | 
             
                parallel (1.23.0)
         | 
| 26 | 
            -
                parser (3.2.2. | 
| 27 | 
            +
                parser (3.2.2.4)
         | 
| 27 28 | 
             
                  ast (~> 2.4.1)
         | 
| 29 | 
            +
                  racc
         | 
| 28 30 | 
             
                php4r (0.0.4)
         | 
| 29 31 | 
             
                  datet
         | 
| 30 32 | 
             
                  http2
         | 
| @@ -32,10 +34,11 @@ GEM | |
| 32 34 | 
             
                pry (0.14.2)
         | 
| 33 35 | 
             
                  coderay (~> 1.1)
         | 
| 34 36 | 
             
                  method_source (~> 1.0)
         | 
| 37 | 
            +
                racc (1.7.3)
         | 
| 35 38 | 
             
                rainbow (3.1.1)
         | 
| 36 | 
            -
                rake (13.0 | 
| 37 | 
            -
                regexp_parser (2.8. | 
| 38 | 
            -
                rexml (3.2. | 
| 39 | 
            +
                rake (13.1.0)
         | 
| 40 | 
            +
                regexp_parser (2.8.2)
         | 
| 41 | 
            +
                rexml (3.2.6)
         | 
| 39 42 | 
             
                rspec (3.12.0)
         | 
| 40 43 | 
             
                  rspec-core (~> 3.12.0)
         | 
| 41 44 | 
             
                  rspec-expectations (~> 3.12.0)
         | 
| @@ -49,28 +52,32 @@ GEM | |
| 49 52 | 
             
                  diff-lcs (>= 1.2.0, < 2.0)
         | 
| 50 53 | 
             
                  rspec-support (~> 3.12.0)
         | 
| 51 54 | 
             
                rspec-support (3.12.0)
         | 
| 52 | 
            -
                rubocop (1. | 
| 55 | 
            +
                rubocop (1.58.0)
         | 
| 53 56 | 
             
                  json (~> 2.3)
         | 
| 57 | 
            +
                  language_server-protocol (>= 3.17.0)
         | 
| 54 58 | 
             
                  parallel (~> 1.10)
         | 
| 55 | 
            -
                  parser (>= 3.2. | 
| 59 | 
            +
                  parser (>= 3.2.2.4)
         | 
| 56 60 | 
             
                  rainbow (>= 2.2.2, < 4.0)
         | 
| 57 61 | 
             
                  regexp_parser (>= 1.8, < 3.0)
         | 
| 58 62 | 
             
                  rexml (>= 3.2.5, < 4.0)
         | 
| 59 | 
            -
                  rubocop-ast (>= 1. | 
| 63 | 
            +
                  rubocop-ast (>= 1.30.0, < 2.0)
         | 
| 60 64 | 
             
                  ruby-progressbar (~> 1.7)
         | 
| 61 65 | 
             
                  unicode-display_width (>= 2.4.0, < 3.0)
         | 
| 62 | 
            -
                rubocop-ast (1. | 
| 66 | 
            +
                rubocop-ast (1.30.0)
         | 
| 63 67 | 
             
                  parser (>= 3.2.1.0)
         | 
| 64 | 
            -
                rubocop-capybara (2. | 
| 68 | 
            +
                rubocop-capybara (2.19.0)
         | 
| 65 69 | 
             
                  rubocop (~> 1.41)
         | 
| 66 | 
            -
                rubocop- | 
| 70 | 
            +
                rubocop-factory_bot (2.24.0)
         | 
| 71 | 
            +
                  rubocop (~> 1.33)
         | 
| 72 | 
            +
                rubocop-performance (1.19.1)
         | 
| 67 73 | 
             
                  rubocop (>= 1.7.0, < 2.0)
         | 
| 68 74 | 
             
                  rubocop-ast (>= 0.4.0)
         | 
| 69 75 | 
             
                rubocop-rake (0.6.0)
         | 
| 70 76 | 
             
                  rubocop (~> 1.0)
         | 
| 71 | 
            -
                rubocop-rspec (2. | 
| 72 | 
            -
                  rubocop (~> 1. | 
| 77 | 
            +
                rubocop-rspec (2.25.0)
         | 
| 78 | 
            +
                  rubocop (~> 1.40)
         | 
| 73 79 | 
             
                  rubocop-capybara (~> 2.17)
         | 
| 80 | 
            +
                  rubocop-factory_bot (~> 2.22)
         | 
| 74 81 | 
             
                ruby-progressbar (1.13.0)
         | 
| 75 82 | 
             
                ruby_process (0.0.13)
         | 
| 76 83 | 
             
                  string-cases
         | 
| @@ -79,7 +86,7 @@ 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. | 
| 89 | 
            +
                unicode-display_width (2.5.0)
         | 
| 83 90 | 
             
                wref (0.0.8)
         | 
| 84 91 |  | 
| 85 92 | 
             
            PLATFORMS
         | 
    
        data/exe/process_bot
    CHANGED
    
    
| @@ -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 | 
            -
                 | 
| 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  | 
| 44 | 
            -
                   | 
| 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 ||=  | 
| 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  | 
| 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 | 
            -
                 | 
| 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
         | 
| @@ -8,6 +8,10 @@ class ProcessBot::ControlSocket | |
| 8 8 | 
             
                @process = process
         | 
| 9 9 | 
             
              end
         | 
| 10 10 |  | 
| 11 | 
            +
              def logger
         | 
| 12 | 
            +
                @logger ||= ProcessBot::Logger.new(options: options)
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
             | 
| 11 15 | 
             
              def port
         | 
| 12 16 | 
             
                options.fetch(:port).to_i
         | 
| 13 17 | 
             
              end
         | 
| @@ -16,7 +20,7 @@ class ProcessBot::ControlSocket | |
| 16 20 | 
             
                @server = TCPServer.new("localhost", port)
         | 
| 17 21 | 
             
                run_client_loop
         | 
| 18 22 |  | 
| 19 | 
            -
                 | 
| 23 | 
            +
                logger.logs "TCPServer started"
         | 
| 20 24 |  | 
| 21 25 | 
             
                options.events.call(:on_socket_opened, port: port)
         | 
| 22 26 | 
             
              end
         | 
| @@ -45,16 +49,38 @@ class ProcessBot::ControlSocket | |
| 45 49 |  | 
| 46 50 | 
             
                  if command_type == "graceful" || command_type == "stop"
         | 
| 47 51 | 
             
                    begin
         | 
| 48 | 
            -
                       | 
| 52 | 
            +
                      command_options = if command["options"]
         | 
| 53 | 
            +
                        symbolize_keys(command.fetch("options"))
         | 
| 54 | 
            +
                      else
         | 
| 55 | 
            +
                        {}
         | 
| 56 | 
            +
                      end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                      logger.logs "Command #{command_type} with options #{command_options}"
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                      process.__send__(command_type, **command_options)
         | 
| 49 61 | 
             
                      client.puts(JSON.generate(type: "success"))
         | 
| 50 62 | 
             
                    rescue => e # rubocop:disable Style/RescueStandardError
         | 
| 51 | 
            -
                       | 
| 63 | 
            +
                      logger.logs e.message, type: :stderr
         | 
| 64 | 
            +
                      logger.logs e.backtrace, type: :stderr
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                      client.puts(JSON.generate(type: "error", message: e.message, backtrace: e.backtrace))
         | 
| 52 67 |  | 
| 53 68 | 
             
                      raise e
         | 
| 54 69 | 
             
                    end
         | 
| 55 70 | 
             
                  else
         | 
| 56 | 
            -
                    client.puts(JSON.generate(type: "error", message: "Unknown command: #{command_type}"))
         | 
| 71 | 
            +
                    client.puts(JSON.generate(type: "error", message: "Unknown command: #{command_type}", backtrace: Thread.current.backtrace))
         | 
| 57 72 | 
             
                  end
         | 
| 58 73 | 
             
                end
         | 
| 59 74 | 
             
              end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
              def symbolize_keys(hash)
         | 
| 77 | 
            +
                new_hash = {}
         | 
| 78 | 
            +
                hash.each do |key, value|
         | 
| 79 | 
            +
                  next if key == "port"
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                  new_hash[key.to_sym] = value
         | 
| 82 | 
            +
                end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                new_hash
         | 
| 85 | 
            +
              end
         | 
| 60 86 | 
             
            end
         | 
    
        data/lib/process_bot/logger.rb
    CHANGED
    
    | @@ -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
         | 
    
        data/lib/process_bot/options.rb
    CHANGED
    
    | @@ -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( | 
| 5 | 
            -
                @ | 
| 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. | 
| 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|
         | 
    
        data/lib/process_bot/process.rb
    CHANGED
    
    | @@ -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. | 
| 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 | 
            -
                     | 
| 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  | 
| 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
         | 
    
        data/lib/process_bot/version.rb
    CHANGED
    
    
    
        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. | 
| 4 | 
            +
              version: 0.1.4
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - kaspernj
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: exe
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2023- | 
| 11 | 
            +
            date: 2023-12-15 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: knjrbfw
         | 
| @@ -86,7 +86,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 86 86 | 
             
                - !ruby/object:Gem::Version
         | 
| 87 87 | 
             
                  version: '0'
         | 
| 88 88 | 
             
            requirements: []
         | 
| 89 | 
            -
            rubygems_version: 3. | 
| 89 | 
            +
            rubygems_version: 3.4.17
         | 
| 90 90 | 
             
            signing_key: 
         | 
| 91 91 | 
             
            specification_version: 4
         | 
| 92 92 | 
             
            summary: Run and control processes.
         |