Getting Started#
Writing a Project#
While not mandatory, the easiest way to encapsulate a collection of tasks is to write a class that implements Barista::Project.
A Project provides some helpful abstractions to collect tasks in a Barista::Registry automatically, which can return a Directed Acyclic Graph.
Note: Certain Behavior mixins will also provide additional functionality for a project.
class SanityProject < Barista::Project
@@name = "sanity-project"
end
Writing your first task#
A task in Barista is simply a task that implements the Barista::Task interface.
The interface expects the task class to have an #execute
method.
class SayHello < Barista::Task
def execute : Nil
puts "Hello, world."
end
end
SayHello.new.execute # => Hello, World
This isn't all that useful on it's own, but we can orchestrate the timing of how and when tasks execute by using an Orchestrator and declaring dependencies: Barista::TaskClassMethods#dependency
Barista::BelongsTo#
Barista provides an Annotation to associate a task with Projects.
We can use it like this:
# This annotation will add the Task class to SanityProject's task list.
# When the class is instantiated, the new object will be added to SanityProject's registry
@[Barista::BelongsTo(SanityProject)]
class SayHello < Barista::Task
def execute : Nil
puts "Hello, world."
end
end
task = SayHello.new
project = SanityProject.new
orchestrator = Barista::Orchestrator(Barista::Task).new(project.registry)
orchestrator.execute # => Hello, world.
Putting it all together#
With a rudimentary task runner, lets define a set of tasks that are orchestrated concurrently.
class Coffeeshop < Barista::Project
@@name = "coffeeshop"
def execute(workers : Int32)
# instantiate the tasks so they get added to the registry
tasks.each(&.new)
Barista::Orchestrator(Barista::Task).new(registry, workers: workers).execute
end
end
@[Barista::BelongsTo(Coffeeshop)]
class GrindCoffeeBeans < Barista::Task
def execute : Nil
puts "Grinding coffee beans..."
sleep 1
puts "Coffee beans are ready"
end
end
@[Barista::BelongsTo(Coffeshop)]
class SteamMilk < Barista::Task
def execute : Nil
puts "Steaming the Milk..."
sleep 2
puts "Milk is ready"
end
end
@[Barista::BelongsTo(Coffeeshop)]
class BrewCoffee < Barista::Task
dependency GrindCoffeeBeans
def execute : Nil
puts "Percolating Coffee..."
end
end
@[Barista::BelongsTo(Coffeeshop)]
class ServeCoffe < Barista::Task
dependency BrewCoffee
dependency SteamMilk
def execute : Nil
puts "Serving the coffee. Have a good day!"
end
end
# Run the tasks against 4 concurrent workers.
Coffeeshop.new.execute(workers: 4)
This program will start the tasks in the following order:
GrindCoffeeBeans
andSteamMilk
will start at the same time.- When
GrindCoffeeBeans
is done,BrewCoffee
will start. - When
BrewCoffee
andSteamMilk
are done,ServeCoffee
will run.
Producing this output:
Grinding coffee beans...
Steaming the Milk...
Coffee beans are ready
Percolating Coffee...
Milk is ready
Serving the coffee. Have a good day!