Class: Always

Inherits:
Object
  • Object
show all
Defined in:
lib/always.rb

Overview

Always.

In order to start five threads performing the same piece of code over and over again, with a 60-seconds pause between cycles, do this:

require 'always'
a = Always.new(5)
a.start(60) do
  puts 'Hello, world!
end

Then, in order to stop them all together:

a.stop

It’s possible to get a quick summary of the thread pool, by calling to_s. The result will be a “T/C/E” string, where T is the total number of currently running threads, C is the total number of all cycles so far, and E is the total number of all errors seen so far.

Author

Yegor Bugayenko ([email protected])

Copyright

Copyright © 2024 Yegor Bugayenko

License

MIT

Constant Summary collapse

VERSION =

The version of the framework.

'0.0.5'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(total, max_backtraces: 32) ⇒ Always

Constructor.

Parameters:

  • total (Integer)

    The number of threads to run

  • max_backtraces (Integer) (defaults to: 32)

    How many backtraces to keep in memory?



57
58
59
60
61
62
63
64
65
66
67
# File 'lib/always.rb', line 57

def initialize(total, max_backtraces: 32)
  raise "The number of threads (#{total}) must be positive" unless total.positive?

  @total = total
  @on_error = nil
  @threads = []
  @backtraces = []
  @cycles = Concurrent::Atom.new(0)
  @errors = Concurrent::Atom.new(0)
  @max_backtraces = max_backtraces
end

Instance Attribute Details

#backtracesObject (readonly)

Returns the value of attribute backtraces.



49
50
51
# File 'lib/always.rb', line 49

def backtraces
  @backtraces
end

Instance Method Details

#on_error(&block) ⇒ Always

What to do when an exception occurs?

Call it like this (the e provided is the exception and i is the number of the thread where it occured):

a = Always.new(5)
a.on_error do |e, i|
  puts e.message
end

If the block that you provided will also throw an error, it will simply be ignored (not logged anywhere, just ignored!)

Returns:



82
83
84
85
# File 'lib/always.rb', line 82

def on_error(&block)
  @on_error = block
  self
end

#start(pause = 0) ⇒ Object

Start them all and let them run forever (until the stop method is called).

Parameters:

  • pause (Integer) (defaults to: 0)

    The delay between cycles, in seconds



89
90
91
92
93
94
95
96
97
# File 'lib/always.rb', line 89

def start(pause = 0, &)
  raise 'It is running now, call .stop() first' unless @threads.empty?

  (0..@total - 1).each do |i|
    @threads[i] = Thread.new do
      body(pause, &)
    end
  end
end

#stopObject

Stop them all.



100
101
102
103
104
105
106
107
108
109
110
# File 'lib/always.rb', line 100

def stop
  raise 'It is not running now, call .start() first' if @threads.empty?

  @threads.delete_if do |t|
    t.kill
    sleep(0.001) while t.alive?
    true
  end
  @cycles.swap { |_| 0 }
  @errors.swap { |_| 0 }
end

#to_sString

Represent its internal state as a string.

Returns:

  • (String)

    Something like “4/230/23”, where 4 is the number of running threads, 230 is the number of successfull loops, and 23 is the number of failures occured so far.



116
117
118
# File 'lib/always.rb', line 116

def to_s
  "#{@threads.size}/#{@cycles.value}/#{@errors.value}"
end