Class: ShopifyCli::ProcessSupervision

Inherits:
Object
  • Object
show all
Defined in:
lib/shopify-cli/process_supervision.rb

Overview

ProcessSupervision wraps a running process spawned by exec and keeps track if its pid and keeps a log file for it as well

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(identifier, pid: nil, time: Time.now.strftime('%s')) ⇒ ProcessSupervision

:nodoc:



131
132
133
134
135
136
137
138
# File 'lib/shopify-cli/process_supervision.rb', line 131

def initialize(identifier, pid: nil, time: Time.now.strftime('%s')) # :nodoc:
  @identifier = identifier
  @pid = pid
  @time = time
  FileUtils.mkdir_p(ShopifyCli::ProcessSupervision.run_dir)
  @pid_path = File.join(ShopifyCli::ProcessSupervision.run_dir, "#{identifier}.pid")
  @log_path = File.join(ShopifyCli::ProcessSupervision.run_dir, "#{identifier}.log")
end

Instance Attribute Details

#identifierObject (readonly)

a string or a symbol to identify this process by



9
10
11
# File 'lib/shopify-cli/process_supervision.rb', line 9

def identifier
  @identifier
end

#log_pathObject (readonly)

filepath to the logfile for this process



17
18
19
# File 'lib/shopify-cli/process_supervision.rb', line 17

def log_path
  @log_path
end

#pidObject

process ID for the running process



11
12
13
# File 'lib/shopify-cli/process_supervision.rb', line 11

def pid
  @pid
end

#pid_pathObject (readonly)

filepath to the pidfile for this process



15
16
17
# File 'lib/shopify-cli/process_supervision.rb', line 15

def pid_path
  @pid_path
end

#timeObject (readonly)

starttime of the process



13
14
15
# File 'lib/shopify-cli/process_supervision.rb', line 13

def time
  @time
end

Class Method Details

.for_ident(identifier) ⇒ Object

Will find and create a new instance of ProcessSupervision for a running process if it is currently running. It will return nil if the process is not running.

#### Parameters

  • identifier - a string or a symbol that a process was started with

#### Returns

  • process - ProcessSupervision instance if the process is running this will be nil if the process is not running.



38
39
40
41
42
43
# File 'lib/shopify-cli/process_supervision.rb', line 38

def for_ident(identifier)
  pid, time = File.read(File.join(ShopifyCli::ProcessSupervision.run_dir, "#{identifier}.pid")).split(':')
  new(identifier, pid: Integer(pid), time: time)
rescue Errno::ENOENT
  nil
end

.run_dirObject



20
21
22
23
# File 'lib/shopify-cli/process_supervision.rb', line 20

def run_dir
  # is the directory where the pid and logfile are kept
  File.join(ShopifyCli.cache_dir, 'sv')
end

.running?(identifier) ⇒ Boolean

will help identify if your process is still running in the background.

#### Parameters

  • identifier - a string or symbol to identify the new process by.

#### Returns

  • running - [true, false]

Returns:

  • (Boolean)


124
125
126
127
128
# File 'lib/shopify-cli/process_supervision.rb', line 124

def running?(identifier)
  process = for_ident(identifier)
  return false unless process
  process.alive?
end

.start(identifier, args) ⇒ Object

will fork and spawn a new process that is separate from the current process. This process will keep running beyond the command running so be careful!

#### Parameters

  • identifier - a string or symbol to identify the new process by.

  • args - a command to run, either a string or array of strings

#### Returns

  • process - ProcessSupervision instance if the process is running, this will be nil if the process did not start.



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/shopify-cli/process_supervision.rb', line 59

def start(identifier, args)
  return for_ident(identifier) if running?(identifier)

  # Windows doesn't support forking process without extra gems, so we resort to spawning a new child process -
  # that means that it dies along with the original process if it is interrupted. On UNIX, we fork the process so
  # that it doesn't have to be restarted on every run.
  if Context.new.windows?
    pid_file = new(identifier)

    # Make sure the file exists and is empty, otherwise Windows fails
    File.open(pid_file.log_path, 'w') {}
    pid = Process.spawn(
      *args,
      out: pid_file.log_path,
      err: pid_file.log_path,
      in: Context.new.windows? ? "nul" : "/dev/null",
    )
    pid_file.pid = pid
    pid_file.write

    Process.detach(pid)
  else
    fork do
      pid_file = new(identifier, pid: Process.pid)
      pid_file.write
      STDOUT.reopen(pid_file.log_path, "w")
      STDERR.reopen(pid_file.log_path, "w")
      STDIN.reopen("/dev/null", "r")
      Process.setsid
      exec(*args)
    end
  end

  sleep(0.1)
  for_ident(identifier)
end

.stop(identifier) ⇒ Object

will attempt to shutdown a running process

#### Parameters

  • identifier - a string or symbol to identify the new process by.

#### Returns

  • stopped - [true, false]



107
108
109
110
111
# File 'lib/shopify-cli/process_supervision.rb', line 107

def stop(identifier)
  process = for_ident(identifier)
  return false unless process
  process.stop
end

Instance Method Details

#alive?Boolean

will help identify if your process is still running in the background.

#### Returns

  • alive - [true, false]

Returns:

  • (Boolean)


166
167
168
# File 'lib/shopify-cli/process_supervision.rb', line 166

def alive?
  stat(pid)
end

#stopObject

will attempt to shutdown a running process

#### Parameters

  • ctx - the context of this command

#### Returns

  • stopped - [true, false]



151
152
153
154
155
156
157
# File 'lib/shopify-cli/process_supervision.rb', line 151

def stop
  kill_proc
  unlink
  true
rescue
  false
end

#writeObject

persists the pidfile



173
174
175
176
# File 'lib/shopify-cli/process_supervision.rb', line 173

def write
  FileUtils.mkdir_p(File.dirname(pid_path))
  File.write(pid_path, "#{pid}:#{time}")
end