class Zold::Farmers::Spawn

In a child process

Public Class Methods

new(log: Log::NULL) click to toggle source
# File lib/zold/node/farmers.rb, line 83
def initialize(log: Log::NULL)
  @log = log
end

Public Instance Methods

up(score) click to toggle source
# File lib/zold/node/farmers.rb, line 87
      def up(score)
        start = Time.now
        bin = File.expand_path(File.join(File.dirname(__FILE__), '../../../bin/zold'))
        raise "Zold binary not found at #{bin}" unless File.exist?(bin)
        cmd = [
          'ruby',
          Shellwords.escape(bin),
          '--skip-upgrades',
          "--info-tid=#{Shellwords.escape(Thread.current.thread_variable_get(:tid))}",
          "--info-thread=#{Shellwords.escape(Thread.current.name)}",
          "--info-start=#{Shellwords.escape(Time.now.utc.iso8601)}",
          '--low-priority',
          'next',
          Shellwords.escape(score)
        ].join(' ')
        Open3.popen2e(cmd) do |stdin, stdout, thr|
          Thread.current.thread_variable_set(:pid, thr.pid.to_s)
          at_exit { Farmers.kill(@log, thr.pid, start) }
          @log.debug("Scoring started in proc ##{thr.pid} \
for #{score.value}/#{score.strength} at #{score.host}:#{score.port}")
          begin
            stdin.close
            buffer = +''
            loop do
              begin
                buffer << stdout.read_nonblock(16 * 1024)
                # rubocop:disable Lint/HandleExceptions
              rescue IO::WaitReadable
                # rubocop:enable Lint/HandleExceptions
                # nothing to do here
              rescue StandardError => e
                @log.error(buffer)
                raise e
              end
              break if buffer.end_with?("\n") && thr.value.to_i.zero?
              if stdout.closed?
                raise "Failed to calculate the score (##{thr.value}): #{buffer}" unless thr.value.to_i.zero?
                break
              end
              sleep(1)
              Thread.current.thread_variable_set(:buffer, buffer.length.to_s)
            end
            after = Score.parse(buffer.strip)
            @log.debug("Next score #{after.value}/#{after.strength} found in proc ##{thr.pid} \
for #{after.host}:#{after.port} in #{Age.new(start)}: #{after.suffixes}")
            after
          ensure
            Farmers.kill(@log, thr.pid, start)
          end
        end
      end