module Mosquito::Runnable

Overview

Runnable implements a general purpose spawn/loop which carries a state enum.

Managing a Runnable

The primary purpose of Runnable is to cleanly abstract the details of spawning a thread, running a loop, and shutting down when asked.

A service which manages a Runnable might look like this:

runnable = MyRunnable.new

# This will spawn and return immediately.
runnable.start

puts runnable.state # => State::Working

# Some time later...
should_be_stopped = runnable.stop has_stopped =
should_be_stopped.receive

Implementing a Runnable

A runnable implementation needs to implement only two methods: #each_run and #runnable_name. In addition, pre_run and post_run are available for setup and teardown.

Runnable state is managed automatically through startup and shutdown, but within each_run it can be manually altered with #state=.

Example

class MyRunnable
  include Mosquito::Runnable

  # Optional
  def pre_run
    puts "my runnable is starting"
  end

  def each_run
    puts "my runnable is running"
  end

  # Optional
  def post_run
    puts "my runnable has stopped"
  end

  def runnable_name
    "MyRunnable"
  end
end

Implementation details about what work should be done in the spawned fiber are placed in #each_run.

Direct including types

Defined in:

mosquito/runnable.cr

Instance Method Summary

Instance Method Detail

def dead? : Bool #

abstract def each_run : Nil #

Implementation of what this Runnable should do on each cycle.

Take care that @state is #running? at the end of the method unless it is finished and should exit.


def fiber : Fiber | Nil #

After #run has been called this holds a reference to the Fiber which is used to check that the fiber is still running.


def my_name : String #

def post_run : Nil #

Available to hook any teardown logic after the run loop.


def pre_run : Nil #

Available to hook a one time setup before the run loop.


def run #

Start the Runnable, and capture the fiber to a property.

The spawned fiber will not return as long as state.running?.

State can be altered internally or externally to cause it to exit but the cleanest way to do that is to call #stop.


abstract def runnable_name : String #

Used to print a pretty name for logging.


def state : State #

Tracks the state of this runnable.

Initially it will be State::Starting. After #run is called it will be State::Working.

When #stop is called it will be State::Stopping. After #run finishes, it will be State::Finished.

It is not necessary to set this manually, but it's available to an implementation if needed. See Mosquito::Runners::Executor#state= (source code) for an example.


def stop : Channel(Bool) #

Request that the next time the run loop cycles it should exit instead. The runnable doesn't exit immediately so #stop returns a notification channel.

#stop spawns a fiber which monitors the state and sends a bool in two circumstances. It will stop waiting for the spawn to exit at 25 seconds. If the spawn has actually stopped the notification channel will broadcast a true, otherwise false.