Class: OpenC3::OperatorProcess

Inherits:
Object
  • Object
show all
Defined in:
lib/openc3/operators/operator.rb

Direct Known Subclasses

ProcessManagerProcess

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(process_definition, work_dir: '/openc3/lib/openc3/microservices', temp_dir: nil, env: {}, scope:, container: nil, config: nil) ⇒ OperatorProcess

container is not used, it’s just here for Enterprise



39
40
41
42
43
44
45
46
47
48
49
# File 'lib/openc3/operators/operator.rb', line 39

def initialize(process_definition, work_dir: '/openc3/lib/openc3/microservices', temp_dir: nil, env: {}, scope:, container: nil, config: nil)
  @process = nil
  @process_definition = process_definition
  @work_dir = work_dir
  @temp_dir = temp_dir
  @new_temp_dir = temp_dir
  @env = env
  @scope = scope
  # @config only used in start to help print a better Logger message
  @config = config
end

Instance Attribute Details

#envObject

Returns the value of attribute env.



29
30
31
# File 'lib/openc3/operators/operator.rb', line 29

def env
  @env
end

#new_temp_dirObject

Returns the value of attribute new_temp_dir.



30
31
32
# File 'lib/openc3/operators/operator.rb', line 30

def new_temp_dir
  @new_temp_dir
end

#process_definitionObject

Returns the value of attribute process_definition.



27
28
29
# File 'lib/openc3/operators/operator.rb', line 27

def process_definition
  @process_definition
end

#scopeObject (readonly)

Returns the value of attribute scope.



32
33
34
# File 'lib/openc3/operators/operator.rb', line 32

def scope
  @scope
end

#temp_dirObject (readonly)

Returns the value of attribute temp_dir.



31
32
33
# File 'lib/openc3/operators/operator.rb', line 31

def temp_dir
  @temp_dir
end

#work_dirObject

Returns the value of attribute work_dir.



28
29
30
# File 'lib/openc3/operators/operator.rb', line 28

def work_dir
  @work_dir
end

Class Method Details

.setupObject



34
35
36
# File 'lib/openc3/operators/operator.rb', line 34

def self.setup
  # Perform any setup steps necessary
end

Instance Method Details

#alive?Boolean

Returns:

  • (Boolean)


87
88
89
90
91
92
93
# File 'lib/openc3/operators/operator.rb', line 87

def alive?
  if @process
    @process.alive?
  else
    false
  end
end

#exit_codeObject



95
96
97
98
99
100
101
# File 'lib/openc3/operators/operator.rb', line 95

def exit_code
  if @process
    @process.exit_code
  else
    nil
  end
end

#extract_output(max_length_stdout = 65536, max_length_stderr = 65536) ⇒ Object



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/openc3/operators/operator.rb', line 127

def extract_output(max_length_stdout = 65536, max_length_stderr = 65536)
  if @process
    @process.io.stdout.rewind
    output = @process.io.stdout.read
    @process.io.stdout.close
    @process.io.stdout.unlink
    @process.io.stderr.rewind
    err_output = @process.io.stderr.read
    @process.io.stderr.close
    @process.io.stderr.unlink
    return "Stdout:\n#{output[-max_length_stdout..-1] || output}\n\nStderr:\n#{err_output[-max_length_stderr..-1] || err_output}\n"
  else
    return ""
  end
end

#hard_stopObject



110
111
112
113
114
115
116
117
# File 'lib/openc3/operators/operator.rb', line 110

def hard_stop
  if @process and !@process.exited?
    Logger.info("Hard shutting down process: #{@process_definition.join(' ')}", scope: @scope)
    @process.stop
  end
  FileUtils.remove_entry(@temp_dir) if @temp_dir and File.exist?(@temp_dir)
  @process = nil
end

#soft_stopObject



103
104
105
106
107
108
# File 'lib/openc3/operators/operator.rb', line 103

def soft_stop
  Thread.new do
    Logger.info("Soft shutting down process: #{@process_definition.join(' ')}", scope: @scope)
    Process.kill("SIGINT", @process.pid) if @process # Signal the process to stop
  end
end

#startObject



51
52
53
54
55
56
57
58
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
# File 'lib/openc3/operators/operator.rb', line 51

def start
  @temp_dir = @new_temp_dir
  @new_temp_dir = nil

  # In ProcessManager processes, the process_definition is the actual thing run
  # e.g. OpenC3::ProcessManager.instance.spawn(["ruby", "/openc3/bin/openc3cli", "load", ...])
  # However, if the MicroserviceOperator is spawning the proceses it sets
  # process_definition = ["ruby", "plugin_microservice.rb"]
  # which then calls exec(*@config["cmd"]) to actually run
  # So check if the @config['cmd'] is defined to give the user more info in the log
  cmd = @process_definition.join(' ')
  if @config && @config['cmd']
    cmd = @config['cmd'].join(' ')
  end
  Logger.info("Starting: #{cmd}", scope: @scope)

  @process = ChildProcess.build(*@process_definition)
  # This lets the ChildProcess use the parent IO ... but it breaks unit tests
  # @process.io.inherit!
  @process.cwd = @work_dir
  # Spawned process should not be controlled by same Bundler constraints as spawning process
  ENV.each do |key, value|
    if key =~ /^BUNDLER/
      @process.environment[key] = nil
    end
  end
  @env['RUBYOPT'] = nil # Removes loading bundler setup
  @env.each do |key, value|
    @process.environment[key] = value
  end
  @process.environment['OPENC3_SCOPE'] = @scope
  @process.io.stdout = Tempfile.new("child-output")
  @process.io.stderr = Tempfile.new("child-output")
  @process.start
end

#stderrObject



123
124
125
# File 'lib/openc3/operators/operator.rb', line 123

def stderr
  @process.io.stderr
end

#stdoutObject



119
120
121
# File 'lib/openc3/operators/operator.rb', line 119

def stdout
  @process.io.stdout
end