Class: Zold::Farm

Inherits:
Object
  • Object
show all
Defined in:
lib/zold/node/farm.rb

Overview

Farm

Defined Under Namespace

Classes: Empty

Instance Method Summary collapse

Constructor Details

#initialize(invoice, cache = File.join(Dir.pwd, 'farm'), log: Log::NULL, farmer: Farmers::Plain.new, lifetime: 24 * 60 * 60, strength: Score::STRENGTH) ⇒ Farm

Makes an instance of a farm. There should be only farm in the entire application, but you can, of course, start as many of them as necessary for the purpose of unit testing.

cache is the file where the farm will keep all the scores it manages to find. If the file is absent, it will be created, together with the necessary parent directories.

lifetime is the amount of seconds for a score to live in the farm, by default it’s the entire day, since the Score expires in 24 hours; can be decreased for the purpose of unit testing.



61
62
63
64
65
66
67
68
69
70
71
# File 'lib/zold/node/farm.rb', line 61

def initialize(invoice, cache = File.join(Dir.pwd, 'farm'), log: Log::NULL,
  farmer: Farmers::Plain.new, lifetime: 24 * 60 * 60, strength: Score::STRENGTH)
  @log = log
  @cache = File.expand_path(cache)
  @invoice = invoice
  @pipeline = Queue.new
  @farmer = farmer
  @threads = ThreadPool.new('farm', log: log)
  @lifetime = lifetime
  @strength = strength
end

Instance Method Details

#bestObject

Returns the list of best scores the farm managed to find up to now. The list is NEVER empty, even if the farm has just started. If it’s empty, it’s definitely a bug. If the farm is just fresh start, the list will contain a single score with a zero value.



77
78
79
# File 'lib/zold/node/farm.rb', line 77

def best
  load
end

#start(host, port, threads: Concurrent.processor_count) ⇒ Object

Starts a farm, all threads, and yields the block provided. You are supposed to use it only with the block:

Farm.new.start('example.org', 4096) do |farm|
  score = farm.best[0]
  # Everything else...
end

The farm will stop all its threads and close all resources safely right after the block provided exists.



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/zold/node/farm.rb', line 110

def start(host, port, threads: Concurrent.processor_count)
  raise 'Block is required for the farm to start' unless block_given?
  @log.info('Zero-threads farm won\'t score anything!') if threads.zero?
  if best.empty?
    @log.info("No scores found in the cache at #{@cache}")
  else
    @log.info("#{best.size} scores pre-loaded from #{@cache}, the best is: #{best[0]}")
  end
  (1..threads).map do |t|
    @threads.add do
      Thread.current.thread_variable_set(:tid, t.to_s)
      Endless.new("f#{t}", log: @log).run do
        cycle(host, port, threads)
      end
    end
  end
  unless threads.zero?
    ready = false
    @threads.add do
      Endless.new('cleanup', log: @log).run do
        cleanup(host, port, threads)
        ready = true
        sleep(1)
      end
    end
    loop { break if ready }
  end
  if threads.zero?
    cleanup(host, port, threads)
    @log.info("Farm started with no threads (there will be no score) at #{host}:#{port}")
  else
    @log.info("Farm started with #{@threads.count} threads (one for cleanup) \
at #{host}:#{port}, strength is #{@strength}")
  end
  begin
    yield(self)
  ensure
    @threads.kill
  end
end

#to_jsonObject

Renders the Farm into JSON to show for the end-user in front.rb.



91
92
93
94
95
96
97
98
# File 'lib/zold/node/farm.rb', line 91

def to_json
  {
    threads: @threads.to_json,
    pipeline: @pipeline.size,
    best: best.map(&:to_mnemo).join(', '),
    farmer: @farmer.class.name
  }
end

#to_textObject



81
82
83
84
85
86
87
88
# File 'lib/zold/node/farm.rb', line 81

def to_text
  [
    "Current time: #{Time.now.utc.iso8601}",
    "Ruby processes: #{`ps ax | grep zold | wc -l`}",
    JSON.pretty_generate(to_json),
    @threads.to_s
  ].flatten.join("\n\n")
end