What is a Box?

A box is a Groovy-based class that follows the rules:

  • Boxes’ inputs are functions.
  • The code at the root is the one that will be executed by the box.

Here is the simplest box code you can write:

// No functions, so no inputs
 
// No code, so running the box does nothing

As explained in What is a Workflow?, a box is executed. This execution is simply a call of the execute method. In a real workflow, this execution can trigger GPU computation or call external libraries but, for now, you focus on inputs and outputs of a sample box that only performs dummy computations.

Inputs

You can define inputs of your box by creating a function. The name of the function has to match the name of the input. For instance, we create an input trade for our SampleBox like this:

def trade (def t){
    if (tradeList == null)
        tradeList = []
    tradeList.add(t)
}

In this example, the trade method will be called each time a box or the calling stack writes to the SampleBox.trade input. Since we want to handle several trades, we create a list called tradeList and use it to store any trade we receive.

The input functions are not made for storage purposes only. You can use them to perform computations or pass data directly to one of the box output (see Outputs section below).

You can also define your own custom functions as long as their names are not conflicting with one of the input names.

Outputs

A box can also send data to another box or to the workflow outputs. This is done through the output() method. You need to specify the name of the output you want to write to, as well as the serializable objects you want to send.

The output you are writing to must be specified in the workflow definition. In the example below, we write the number of trades we received to the tradeCount output.

def trade (def t){
    if (tradeList == null)
        tradeList = []
    tradeList.add(t)
}

output("tradeCount", tradeList.size())
close("tradeCount")

Note that we are closing the tradeCount output. This is useless here since all outputs are closed at the end of the box execution.

If we were to perform intensive computations after the tradeList.size() output, closing tradeCount would tell the destination box that we will not send anything else through this link and that it can consider its input as closed, allowing it to execute in parallel.

Best Practices

In order to optimize the use of the boxes, let us describe some best practices:

  • Close outputs as soon as they are not needed anymore. This may allow other boxes to execute sooner, accelerating the workflow execution in the process.
  • Groovy is not the fastest language ever. If you need computation intensive work on the CPU, consider writing them in pure java and call them from the box code