Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #554 - Adding Farmers::Fork #567

Merged
merged 8 commits into from Nov 27, 2018
34 changes: 31 additions & 3 deletions lib/zold/node/farmers.rb 100644 → 100755
Expand Up @@ -37,6 +37,10 @@ module Zold
module Farmers
# Plain and simple
class Plain
def initialize(log: Log::NULL)
@log = log
end

def up(score)
score.next
end
Expand All @@ -49,9 +53,8 @@ def initialize(log: Log::NULL)
end

def up(score)
if POSIX::Spawn::Child.new('ps', 'ax').out.include?(score.to_s.split(' ').take(4).join(' '))
raise "We are farming the score already: #{score}"
end
raise "We are farming the score already: #{score}" if
POSIX::Spawn::Child.new('ps', 'ax').out.include?(score.to_s.split(' ').take(4).join(' '))
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)
Expand Down Expand Up @@ -112,5 +115,30 @@ def kill(pid, start)
@log.debug("No need to kill process ##{pid} since it's dead already: #{e.message}")
end
end

# In a child process using fork
class Fork
def initialize(log: Log::NULL)
@log = log
end

def up(score)
start = Time.now
stdin, stdout = IO.pipe
Process.fork do
score = score.next
stdout.puts "#{score}|#{Process.pid}"
end
Process.wait
stdout.close
output = stdin.read
buffer, pid = output.split('|')
after = Score.parse(buffer.strip)
stdin.close
@log.debug("Next score #{after.value}/#{after.strength} found in proc ##{pid.strip} \
for #{after.host}:#{after.port} in #{Age.new(start)}: #{after.suffixes}")
after
end
end
end
end
44 changes: 21 additions & 23 deletions test/node/test_farmers.rb 100644 → 100755
Expand Up @@ -29,48 +29,46 @@
class FarmersTest < Zold::Test
def test_calculates_next_score
before = Zold::Score.new(host: 'some-host', port: 9999, invoice: 'NOPREFIX4@ffffffffffffffff', strength: 3)
farmer = Zold::Farmers::Spawn.new(log: test_log)
after = farmer.up(before)
assert_equal(1, after.value)
assert(!after.expired?)
assert_equal('some-host', after.host)
assert_equal(9999, after.port)
[Zold::Farmers::Plain, Zold::Farmers::Spawn, Zold::Farmers::Fork].each do |farmer_class|
farmer = farmer_class.new(log: test_log)
after = farmer.up(before)
assert_equal(1, after.value)
assert(!after.expired?)
assert_equal('some-host', after.host)
assert_equal(9999, after.port)
end
end

def test_calculates_large_score
log = TestLogger.new(test_log)
thread = Thread.start do
farmer = Zold::Farmers::Spawn.new(log: log)
farmer.up(Zold::Score.new(host: 'a', port: 1, invoice: 'NOPREFIX4@ffffffffffffffff', strength: 20))
[Zold::Farmers::Spawn, Zold::Farmers::Fork].each do |farmer_class|
farmer = farmer_class.new(log: log)
farmer.up(Zold::Score.new(host: 'a', port: 1, invoice: 'NOPREFIX4@ffffffffffffffff', strength: 20))
end
end
assert_wait { !log.msgs.find { |m| m.include?('Scoring started') }.nil? }
thread.kill
thread.join
assert(log.msgs.find { |m| m.include?('killed') })
end

def test_calculates_next_score_plain
before = Zold::Score.new(host: 'some-host', port: 9999, invoice: 'NOPREFIX4@ffffffffffffffff', strength: 1)
farmer = Zold::Farmers::Plain.new
after = farmer.up(before)
assert_equal(1, after.value)
assert(!after.expired?)
assert_equal('some-host', after.host)
assert_equal(9999, after.port)
end

def test_avoid_duplicate_processes
log = TestLogger.new(test_log)
time = Time.now
thread = Thread.start do
farmer = Zold::Farmers::Spawn.new(log: log)
farmer.up(Zold::Score.new(time: time, host: 'a', port: 1, invoice: 'prefixone@ffffffffffffffff', strength: 20))
[Zold::Farmers::Spawn, Zold::Farmers::Fork].each do |farmer_class|
farmer = farmer_class.new(log: log)
farmer.up(Zold::Score.new(time: time, host: 'a', port: 1, invoice: 'prefixone@ffffffffffffffff', strength: 20))
end
end
assert_wait { !log.msgs.find { |m| m.include?('Scoring started') }.nil? }
assert_raises do
Zold::Farmers::Spawn.new(log: log).up(
Zold::Score.new(time: time, host: 'a', port: 1, invoice: 'prefixtwo@ffffffffffffffff', strength: 20)
)
[Zold::Farmers::Spawn, Zold::Farmers::Fork].each do |farmer_class|
farmer_class.new(log: log).up(
Zold::Score.new(time: time, host: 'a', port: 1, invoice: 'prefixtwo@ffffffffffffffff', strength: 20)
)
end
end
thread.kill
thread.join
Expand Down