Class: Async::Idler

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

Overview

A load balancing mechanism that can be used process work when the system is idle.

Instance Method Summary collapse

Constructor Details

#initialize(maximum_load = 0.8, backoff: 0.001, parent: nil) ⇒ Idler

Create a new idler.



16
17
18
19
20
21
22
23
# File 'lib/async/idler.rb', line 16

def initialize(maximum_load = 0.8, backoff: 0.001, parent: nil)
	@maximum_load = maximum_load
	@backoff = backoff
	@current = backoff
	
	@parent = parent
	@mutex = Mutex.new
end

Instance Method Details

#async(*arguments, parent: (@parent or Task.current), **options, &block) ⇒ Object

Wait until the system is idle, then execute the given block in a new task.



33
34
35
36
37
38
# File 'lib/async/idler.rb', line 33

def async(*arguments, parent: (@parent or Task.current), **options, &block)
	wait
	
	# It is crucial that we optimistically execute the child task, so that we prevent a tight loop invoking this method from consuming all available resources.
	parent.async(*arguments, **options, &block)
end

#waitObject

Wait until the system is idle, according to the maximum load specified.

If the scheduler is overloaded, this method will sleep for an exponentially increasing amount of time.



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/async/idler.rb', line 43

def wait
	@mutex.synchronize do
		scheduler = Fiber.scheduler
		
		while true
			load = scheduler.load
			
			if load <= @maximum_load
				# Even though load is okay, if @current is high, we were recently overloaded. Sleep proportionally to prevent burst after load drop:
				if @current > @backoff
					# Sleep a fraction of @current to rate limit:
					sleep(@current - @backoff)
					
					# Decay @current gently towards @backoff:
					alpha = 0.99
					@current *= alpha + (1.0 - alpha) * (load / @maximum_load)
				end
				
				break
			else
				# We're overloaded, so increase backoff:
				@current *= (load / @maximum_load)
				sleep(@current)
			end
		end
	end
end