class Orocos::RemoteProcesses::Server
A remote process management server.
It allows to start/stop and monitor the status of processes on a client/server way.
Use {ProcessClient} to access a server
Public Class Methods
create_pkgconfig_loader()
click to toggle source
# File lib/orocos/remote_processes/server.rb, line 97 def self.create_pkgconfig_loader OroGen::Loaders::RTT.new(Orocos.orocos_target) end
new(default_start_options = DEFAULT_OPTIONS, port = DEFAULT_PORT, loader = self.class.create_pkgconfig_loader)
click to toggle source
# File lib/orocos/remote_processes/server.rb, line 101 def initialize(default_start_options = DEFAULT_OPTIONS, port = DEFAULT_PORT, loader = self.class.create_pkgconfig_loader) @default_start_options = Kernel.validate_options default_start_options, :wait => false, :output => '%m-%p.txt' @loader = loader @required_port = port @port = nil @processes = Hash.new @all_ios = Array.new end
run(options = DEFAULT_OPTIONS, port = DEFAULT_PORT)
click to toggle source
Start a standalone process server using the given options and port. The options are passed to ::run when a new deployment is started
# File lib/orocos/remote_processes/server.rb, line 60 def self.run(options = DEFAULT_OPTIONS, port = DEFAULT_PORT) Orocos.disable_sigchld_handler = true Orocos.initialize new({ :wait => false }.merge(options), port).exec rescue Interrupt end
unique_dirname(base_dir, path_spec, date_tag = nil)
click to toggle source
Returns a unique directory name as a subdirectory of base_dir,
based on path_spec. The generated name is of the form
<base_dir>/a/b/c/YYYYMMDD-HHMM-basename
if path_spec = "a/b/c/basename". A .<number>
suffix is appended if the path already exists.
Shamelessly taken from Roby
# File lib/orocos/remote_processes/server.rb, line 22 def self.unique_dirname(base_dir, path_spec, date_tag = nil) if path_spec =~ /\/$/ basename = "" dirname = path_spec else basename = File.basename(path_spec) dirname = File.dirname(path_spec) end date_tag ||= Time.now.strftime('%Y%m%d-%H%M') if basename && !basename.empty? basename = date_tag + "-" + basename else basename = date_tag end # Check if +basename+ already exists, and if it is the case add a # .x suffix to it full_path = File.expand_path(File.join(dirname, basename), base_dir) base_dir = File.dirname(full_path) unless File.exists?(base_dir) FileUtils.mkdir_p(base_dir) end final_path, i = full_path, 0 while File.exists?(final_path) i += 1 final_path = full_path + ".#{i}" end final_path end
Public Instance Methods
build_system_info()
click to toggle source
# File lib/orocos/remote_processes/server.rb, line 358 def build_system_info available_projects = Hash.new available_typekits = Hash.new available_deployments = Hash.new loader.each_available_project_name do |name| available_projects[name] = loader.project_model_text_from_name(name) end loader.each_available_typekit_name do |name| available_typekits[name] = loader.typekit_model_text_from_name(name) end loader.each_available_deployment_name do |name| available_deployments[name] = loader.find_project_from_deployment_name(name) end return available_projects, available_deployments, available_typekits end
create_log_dir(log_dir, time_tag, metadata = Hash.new)
click to toggle source
# File lib/orocos/remote_processes/server.rb, line 337 def create_log_dir(log_dir, time_tag, metadata = Hash.new) log_dir = File.expand_path(log_dir) Server.debug " #{log_dir}, time: #{time_tag}" FileUtils.mkdir_p(log_dir) File.open(File.join(log_dir, 'time_tag'), 'w') do |io| io.write(time_tag) end File.open(File.join(log_dir, 'info.yml'), 'w') do |io| YAML.dump(Hash['time' => time_tag].merge(metadata), io) end end
each_client(&block)
click to toggle source
# File lib/orocos/remote_processes/server.rb, line 116 def each_client(&block) clients = @all_ios[2..-1] if clients clients.each(&block) end end
end_process(p)
click to toggle source
# File lib/orocos/remote_processes/server.rb, line 382 def end_process(p) p.kill(false) end
exec()
click to toggle source
# File lib/orocos/remote_processes/server.rb, line 123 def exec open listen end
listen()
click to toggle source
Main server loop. This will block and only return when CTRL+C is hit.
All started processes are stopped when the server quits
# File lib/orocos/remote_processes/server.rb, line 148 def listen Server.info "process server listening on port #{port}" server_io, com_r = *@all_ios[0, 2] while true readable_sockets, _ = select(@all_ios, nil, nil) if readable_sockets.include?(server_io) readable_sockets.delete(server_io) client_socket = server_io.accept client_socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, true) client_socket.fcntl(Fcntl::FD_CLOEXEC, 1) Server.debug "new connection: #{client_socket}" @all_ios << client_socket end if readable_sockets.include?(com_r) readable_sockets.delete(com_r) cmd = com_r.read(1) if cmd == INTERNAL_SIGCHLD_TRIGGERED process_dead_processes elsif cmd Server.warn "unknown internal communication code #{cmd.inspect}" end end readable_sockets.each do |socket| if !handle_command(socket) Server.debug "#{socket} closed or errored" socket.close @all_ios.delete(socket) end end end rescue Exception => e if e.class == Interrupt # normal procedure Server.fatal "process server exited normally" return end Server.fatal "process server exited because of unhandled exception" Server.fatal "#{e.message} #{e.class}" e.backtrace.each do |line| Server.fatal " #{line}" end ensure quit_and_join end
move_log_dir(log_dir, results_dir)
click to toggle source
# File lib/orocos/remote_processes/server.rb, line 349 def move_log_dir(log_dir, results_dir) date_tag = File.read(File.join(log_dir, 'time_tag')).strip Server.debug " #{log_dir} => #{results_dir}" if File.directory?(log_dir) dirname = Server.unique_dirname(results_dir + '/', '', date_tag) FileUtils.mv log_dir, dirname end end
open()
click to toggle source
# File lib/orocos/remote_processes/server.rb, line 130 def open Server.info "starting on port #{required_port}" server = TCPServer.new(nil, required_port) server.fcntl(Fcntl::FD_CLOEXEC, 1) @port = server.addr[1] com_r, com_w = IO.pipe @all_ios.clear @all_ios << server << com_r trap 'SIGCHLD' do com_w.write INTERNAL_SIGCHLD_TRIGGERED end end
process_dead_processes()
click to toggle source
# File lib/orocos/remote_processes/server.rb, line 198 def process_dead_processes while exited = ::Process.wait2(-1, ::Process::WNOHANG) pid, exit_status = *exited process_name, process = processes.find { |_, p| p.pid == pid } next if !process_name process.dead!(exit_status) processes.delete(process_name) Server.debug "announcing death: #{process_name}" each_client do |socket| begin Server.debug " announcing to #{socket}" socket.write(EVENT_DEAD_PROCESS) Marshal.dump([process_name, exit_status], socket) rescue IOError Server.debug " #{socket}: IOError" end end end rescue Errno::ECHILD end
quit()
click to toggle source
# File lib/orocos/remote_processes/server.rb, line 386 def quit raise Interrupt end
start_process(name, deployment_name, name_mappings, options)
click to toggle source
# File lib/orocos/remote_processes/server.rb, line 374 def start_process(name, deployment_name, name_mappings, options) p = Orocos::Process.new(name, deployment_name, loader: @loader, name_mappings: name_mappings) p.spawn(**self.default_start_options.merge(options)) processes[name] = p end