class Async::Idler

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

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

@yields {|task| ...} When the system is idle, the block will be executed in a new task.
@parameter options [Hash] The options to pass to the task.
@parameter parent [Interface(:async) | Nil] The parent task to use for async operations.
@parameter arguments [Array] The arguments to pass to the block.

@asynchronous Executes the given block concurrently.

Wait until the system is idle, then execute the given block in a new task.
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

def initialize(maximum_load = 0.8, backoff: 0.01, parent: nil)

@parameter parent [Interface(:async) | Nil] The parent task to use for async operations.
@parameter backoff [Numeric] The initial backoff time, used for delaying work.
@parameter maximum_load [Numeric] The maximum load before we start shedding work.

@public Since `stable-v2`.
Create a new idler.
def initialize(maximum_load = 0.8, backoff: 0.01, parent: nil)
	@maximum_load = maximum_load
	@backoff = backoff
	@parent = parent
end

def wait

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

Wait until the system is idle, according to the maximum load specified.
def wait
	scheduler = Fiber.scheduler
	backoff = nil
	
	while true
		load = scheduler.load 
		break if load < @maximum_load
		
		if backoff
			sleep(backoff)
			backoff *= 2.0
		else
			scheduler.yield
			backoff = @backoff
		end
	end
end