Class: Stable::Services::ProcessManager

Inherits:
Object
  • Object
show all
Defined in:
lib/stable/services/process_manager.rb

Overview

Service for managing application processes

Class Method Summary collapse

Class Method Details

.find_rails_pid(port) ⇒ Object



100
101
102
103
# File 'lib/stable/services/process_manager.rb', line 100

def self.find_rails_pid(port)
  pids = Stable::Utils::Platform.find_pids_by_port(port)
  pids.first
end

.pid_alive?(pid) ⇒ Boolean

Check if a process with the given PID is still running

Returns:

  • (Boolean)


69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/stable/services/process_manager.rb', line 69

def self.pid_alive?(pid)
  return false unless pid

  # Use a cross-platform method to check if PID exists
  if RUBY_PLATFORM =~ /mingw|mswin|win32/
    # Windows: use tasklist
    system("tasklist /FI \"PID eq #{pid}\" 2>NUL | find /I \"#{pid}\" >NUL")
  else
    # Unix-like systems: check /proc or use ps
    begin
      Process.kill(0, pid)
      true
    rescue Errno::ESRCH
      false
    rescue Errno::EPERM
      # Process exists but we don't have permission to signal it
      true
    end
  end
end

.start(target) ⇒ Object



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/stable/services/process_manager.rb', line 7

def self.start(target)
  app = target.is_a?(String) ? AppRegistry.fetch(target) : target

  path = app[:path]
  port = app[:port]

  ruby = app[:ruby]
  gemset = Stable::Services::Ruby.gemset_for(app)

  if ruby && gemset
    Stable::Services::Ruby.ensure_rvm!
    system("bash -lc 'rvm #{ruby}@#{gemset} --create do true'")
    rvm_cmd = "rvm #{ruby}@#{gemset} do"
  elsif ruby
    rvm_cmd = "rvm #{ruby} do"
  else
    rvm_cmd = nil
  end

  log_file = File.join(path, 'log', 'stable.log')
  FileUtils.mkdir_p(File.dirname(log_file))

  cmd = if rvm_cmd
          "cd \"#{path}\" && #{rvm_cmd} bundle exec rails s -p #{port} -b 127.0.0.1"
        else
          "cd \"#{path}\" && bundle exec rails s -p #{port} -b 127.0.0.1"
        end

  pid = spawn('bash', '-lc', cmd, out: log_file, err: log_file)

  Process.detach(pid)

  # Wait a moment for Rails to start, then find the actual Rails PID
  sleep 2
  rails_pid = find_rails_pid(app[:port])

  AppRegistry.update(app[:name], started_at: Time.now.to_i, pid: rails_pid || pid)

  rails_pid || pid
end

.stop(app) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/stable/services/process_manager.rb', line 48

def self.stop(app)
  return unless app[:port]

  pids = Stable::Utils::Platform.find_pids_by_port(app[:port])
  if pids.empty?
    puts "No app running on port #{app[:port]}"
  else
    pids.each do |pid|
      Process.kill('TERM', pid.to_i)
    rescue StandardError
      nil
    end
    puts "Stopped #{app[:name]} on port #{app[:port]}"
  end

  AppRegistry.update(app[:name], started_at: nil, pid: nil)
rescue Errno::ESRCH
  AppRegistry.update(app[:name], started_at: nil, pid: nil)
end

.validate_app_statusesObject

Validate and clean up stale app statuses



91
92
93
94
95
96
97
98
# File 'lib/stable/services/process_manager.rb', line 91

def self.validate_app_statuses
  apps = AppRegistry.all
  apps.each do |app|
    next unless app[:started_at] && app[:pid]

    AppRegistry.update(app[:name], started_at: nil, pid: nil) unless pid_alive?(app[:pid])
  end
end