Project

hustle

0.0
No commit activity in last 3 years
No release in over 3 years
Run Ruby blocks inside their own process.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

~> 1.5
~> 0.4.4
>= 0
>= 0

Runtime

~> 0.9.6
 Project Readme

Hustle

Code Climate

NOTE: This is experimental. Use at your own risk.

Overview

Ever wish MRI was better at CPU bound concurrency?

Hustle makes it easy by allowing you offload CPU intense blocks to separate processes.

Examples

Fire & Forget

Hustle.go do
  # this block is executed in a separate process
  sleep 5 # heavy lifing...
end

# this will run immediately
foo = :bar

Wait for All Blocks to Finish

8.times do
  Hustle.go do
    # each invocation of this block is executed in a separate process
    sleep 5 # heavy lifing...
  end
end

Hustle.wait

Callbacks

print_value = -> (value) do
  # this will run when the Hustle.go block completes
  puts "<#{Process.pid}> #{value}" # => <99693> Hello from: <99728>
end

Hustle.go(callback: print_value) do
  # this block is executed in a separate process
  sleep 5 # heavy lifing...
  "Hello from: <#{Process.pid}>" # this is the return value
end

# this will run immediately
foo = :bar

Lexical Scope & Context

Important: Traditional lexical scoping of Ruby blocks does not work as you might expect. This is because the block gets executed in a separate process.

Think of the Hustle.go block as a "true" lambda i.e. an anonymous function without the closure (an isolated scope)

Hustle supports passing a context object to Hustle.go. Think of this as passing a variable (by value) to the lambda.

data = { message: "I'm from the parent process." }

print_data = -> (value) do
  puts data.inspect # => {:message=>"I'm from the parent process."}
  puts value.inspect # => {:message=>"I'm from the child process."}
end

Hustle.go context: data, callback: print_data do
  # this block is executed in a separate process
  # the "data" variable will NOT be available
  # the "context" variable is available
  # you can think of "context" as a copy of "data" in this case
  context[:message] = "I'm from the child process."
  context
end

Error Handling

callback = -> (value) do
  value.is_a? StandardError # => true
  value.message # => Error in block!
end

Hustle.go(callback: callback) do
  # this block is executed in a separate process
  raise "Error in block!"
end