# Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details. # frozen_string_literal: true module Contrast module Api module Communication # Handles local service startup module ServiceLifecycle include Contrast::Components::Interface access_component :logging, :contrast_service def attempt_local_service_startup zombie_check service_starter_thread.join(5) is_service_started = Contrast::Utils::OS.running? if is_service_started logger.info('The bundled service was successfully started.') else logger.error('The bundled service could not be started. The agent will not function properly.') end is_service_started end # check if there's a zombie service that exists, and wait on it if so. currently, this only happens when trying # to initialize speedracer def zombie_check zombie_pid_list = Contrast::Utils::OS.zombie_pids zombie_pid_list.each do |pid| Process.wait(pid.to_i) rescue Errno::ECHILD => _e # Sometimes the zombie process dies between us finding it and killing it end end def determine_startup_options return { out: :out, err: :out } if CONTRAST_SERVICE.logger_path == 'STDOUT' return { out: :err, err: :err } if CONTRAST_SERVICE.logger_path == 'STDERR' { out: File::NULL, err: File::NULL } end # This is a separate method so we can overwrite it globally in specs def spawn_service options = determine_startup_options logger.debug('Spawning service') spawn 'contrast_service', options end def service_starter_thread Contrast::Agent::Thread.new do # Always check to see if it already started unless Contrast::Utils::OS.running? # Spawn the service process spawn_service # Block until service is running sleep(0.1) until Contrast::Utils::OS.running? end end end end end end end