#!/opt/puppetlabs/server/apps/bolt-server/bin/ruby
# frozen_string_literal: true

lib = File.expand_path('../lib', __dir__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'plan_runner/plan_runner'

# The service itself depends on the root logger to ensure thread/fork
# safety. Instead of passing around a bunch of logging objects, we let
# the default behavior of the logging gem work for us. The root logger
# (and all the appenders attached to the root logger) are inherited by
# all other loggers created in the service. We only ever add one appender
# to the root logger, which is then inherited by all other loggers.
# Appenders are already built to work concurrently with a mutex, so
# inside forks the only thing we need to worry about is resetting file
# descriptors per https://github.com/TwP/logging/blob/master/examples/fork.rb
#
# We initialize logging at the info level to stdout so we can see any
# warnings from config loading, and then reinitialize logging with
# the configured log level/log file during config loading.
Logging.init PlanRunner::LoggingHelper::LOGGING_LEVELS
Logging.logger.root.add_appenders Logging.appenders.stdout(
  'console',
  layout: PlanRunner::LoggingHelper.logging_layout,
  level: 'info'
)

config = PlanRunner::Service::ConfigLoader.new.load
runner = PlanRunner::Service::Runner.new(config)

# Run the 'control' process that loops over operations in its' own
# ruby 'thread'. We do this to allow that process to continue logging
# when we trap the term signal and use stop! to tell it to stop gracefully.
#
# We can't use logging in the main thread here because once we trap we
# can no longer use Mutexes and the logging gem uses mutexes for concurrency
controller_thread = Thread.new { runner.run! }

Signal.trap("TERM") do
  runner.stop!
  # Give the runner process a little time to try and shut everything down
  # nicely. Then just kill it after 20 seconds if it hasn't finished.
  unless controller_thread.join(20)
    controller_thread.kill
  end
end

controller_thread.join
