Class: ProcessBot::Process

Inherits:
Object
  • Object
show all
Defined in:
lib/process_bot/process.rb

Defined Under Namespace

Classes: Handlers, Runner

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ Process

Returns a new instance of Process.



9
10
11
12
13
14
15
16
17
# File 'lib/process_bot/process.rb', line 9

def initialize(options)
  @options = options
  @stopped = false

  options.events.connect(:on_process_started, &method(:on_process_started)) # rubocop:disable Performance/MethodObjectAsBlock
  options.events.connect(:on_socket_opened, &method(:on_socket_opened)) # rubocop:disable Performance/MethodObjectAsBlock

  logger.log("Options: #{options.options}")
end

Instance Attribute Details

#current_pidObject (readonly)

Returns the value of attribute current_pid.



7
8
9
# File 'lib/process_bot/process.rb', line 7

def current_pid
  @current_pid
end

#current_process_titleObject (readonly)

Returns the value of attribute current_process_title.



7
8
9
# File 'lib/process_bot/process.rb', line 7

def current_process_title
  @current_process_title
end

#optionsObject (readonly)

Returns the value of attribute options.



7
8
9
# File 'lib/process_bot/process.rb', line 7

def options
  @options
end

#portObject (readonly)

Returns the value of attribute port.



7
8
9
# File 'lib/process_bot/process.rb', line 7

def port
  @port
end

#stoppedObject (readonly)

Returns the value of attribute stopped.



7
8
9
# File 'lib/process_bot/process.rb', line 7

def stopped
  @stopped
end

Instance Method Details

#clientObject



31
32
33
# File 'lib/process_bot/process.rb', line 31

def client
  @client ||= ProcessBot::ClientSocket.new(options: options)
end

#execute!Object



19
20
21
22
23
24
25
26
27
28
29
# File 'lib/process_bot/process.rb', line 19

def execute!
  command = options.fetch(:command)

  if command == "start"
    start
  elsif command == "graceful" || command == "stop"
    client.send_command(command: command)
  else
    raise "Unknown command: #{command}"
  end
end

#gracefulObject



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/process_bot/process.rb', line 80

def graceful
  @stopped = true

  unless current_pid
    warn "#{handler_name} not running with a PID"
    return
  end

  Process.kill("TSTP", current_pid)

  if options[:wait_for_gracefully_stopped] == "false"
    Thread.new { wait_for_no_jobs_and_stop_sidekiq }
  else
    wait_for_no_jobs_and_stop_sidekiq
  end
end

#handler_classObject



35
36
37
38
39
40
# File 'lib/process_bot/process.rb', line 35

def handler_class
  @handler_class ||= begin
    require_relative "process/handlers/#{handler_name}"
    ProcessBot::Process::Handlers.const_get(StringCases.snake_to_camel(handler_name))
  end
end

#handler_nameObject



42
43
44
# File 'lib/process_bot/process.rb', line 42

def handler_name
  @handler_name ||= options.fetch(:handler)
end

#loggerObject



46
47
48
# File 'lib/process_bot/process.rb', line 46

def logger
  @logger ||= ProcessBot::Logger.new(options: options)
end

#on_process_started(_event_name, pid:) ⇒ Object



50
51
52
53
# File 'lib/process_bot/process.rb', line 50

def on_process_started(_event_name, pid:)
  @current_pid = pid
  update_process_title
end

#on_socket_opened(_event_name, port:) ⇒ Object



55
56
57
58
# File 'lib/process_bot/process.rb', line 55

def on_socket_opened(_event_name, port:)
  @port = port
  update_process_title
end

#runObject



108
109
110
111
112
# File 'lib/process_bot/process.rb', line 108

def run
  handler_instance = handler_class.new(options)
  runner = ProcessBot::Process::Runner.new(command: handler_instance.start_command, logger: logger, options: options)
  runner.run
end

#startObject



65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/process_bot/process.rb', line 65

def start
  start_control_socket

  loop do
    run

    if stopped
      break
    else
      puts "Process stopped - starting again after 1 sec"
      sleep 1
    end
  end
end

#start_control_socketObject



60
61
62
63
# File 'lib/process_bot/process.rb', line 60

def start_control_socket
  @control_socket = ProcessBot::ControlSocket.new(options: options, process: self)
  @control_socket.start
end

#stopObject



97
98
99
100
101
102
103
104
105
106
# File 'lib/process_bot/process.rb', line 97

def stop
  @stopped = true

  unless current_pid
    warn "#{handler_name} not running with a PID"
    return
  end

  Process.kill("TERM", current_pid)
end

#update_process_titleObject



114
115
116
117
118
# File 'lib/process_bot/process.rb', line 114

def update_process_title
  process_args = {application: options[:application], handler: handler_name, id: options[:id], pid: current_pid, port: port}
  @current_process_title = "ProcessBot #{JSON.generate(process_args)}"
  Process.setproctitle(current_process_title)
end

#wait_for_no_jobsObject

rubocop:disable Metrics/AbcSize



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/process_bot/process.rb', line 120

def wait_for_no_jobs # rubocop:disable Metrics/AbcSize
  loop do
    found_process = false

    Knj::Unix_proc.list("grep" => current_pid) do |process|
      process_command = process.data.fetch("cmd")
      process_pid = process.data.fetch("pid").to_i
      next unless process_pid == current_pid

      found_process = true
      sidekiq_regex = /\Asidekiq (\d+).(\d+).(\d+) (#{options.possible_process_titles_joined_regex}) \[(\d+) of (\d+)(\]|) (.+?)(\]|)\Z/
      match = process_command.match(sidekiq_regex)
      raise "Couldnt match Sidekiq command: #{process_command} with Sidekiq regex: #{sidekiq_regex}" unless match

      running_jobs = match[5].to_i

      puts "running_jobs: #{running_jobs}"

      return if running_jobs.zero? # rubocop:disable Lint/NonLocalExitFromIterator
    end

    raise "Couldn't find running process with PID #{current_pid}" unless found_process

    sleep 1
  end
end

#wait_for_no_jobs_and_stop_sidekiqObject



147
148
149
150
151
152
# File 'lib/process_bot/process.rb', line 147

def wait_for_no_jobs_and_stop_sidekiq
  puts "Wait for no jobs and Stop sidekiq"

  wait_for_no_jobs
  stop
end