How to write a Brick

A Titan flow consists of a sequence of Bricks that process Flow Packets. You can
write custom Bricks if the desired functionality is not available in any other
Brick. In the following describes how to write your own Brick in Python.

Brick implementation

You can write a Brick in two ways:

  1. as a Python file (e.g. bricks/my_brick.py)
  2. as a Python module (e.g. bricks.my_brick )

A Brick performing a simple task comes as a single Python script file (first option).
There are several cases in which the second way, providing a Python module, may
be preferred: In case the Brick implements a complex feature with several
functions and submodules, in case you want to equip your Brick with parameters,
which requires a separate parameter configuration file, or if you want to be
able to install the Brick as a Python site-package.

Brick content requirements

The Brick content with the logic you want to implement is executed by
a Brick Runner. It handles the communication with the Titan flow engine, i.e.
delivers input data and receives and sends your result data.
The Brick Runner uses one of two alternative entry points when executing a Brick:

  1. The Brick derives from the BrickBase base class
  2. The Brick contains a function do_brick_processing (deprecated)

1. The Brick derives from the base class BrickBase

You can write you Brick by creating a class called Brick that inherits from
the class BrickBase which is part of the module brick.

from titanfe.brick import BrickBase

class Brick(BrickBase):
    def __init__(self, adapter, parameters):
        super().__init__(adapter, parameters)

    def setup(self):
       '''your setup method'''

    def teardown(self):
       '''your teardown method'''

    def process(self, input: Type[UjoBase] = UJO_VARIANT_NONE):
       '''your Bricks Flow Packet processing logic'''

BrickBase has the attributes

  • adapter : interface to the Brick Runner (details in section Brick Adapter )
  • parameters : optional dictionary of Brick parameters (details in section Brick parameters )

Note: Your Brick class must initialize the attributes of BrickBase during its
initialization (see listing above).

Your Brick class can implement the following methods of BrickBase:

  • setup : Upon loading the Brick in the BrickRunner the setup-method is run once
    and can be used to e.g. open connections that will be held persistent
  • teardown : When unloading the Brick from the BrickRunner the teardown-method
    is run once, implement it to e.g. close connections opened during setup
  • process : The Bricks Flow Packet processing logic (mandatory)

The function process has one argument, input, which represents the incoming
Flow Packet’s payload and is of type UjoMap.

2. The Brick contains a function do_brick_processing (deprecated)

Instead of deriving a class Brick form Brick base, the Brick content script
can define a function called do_brick_processing called by the Brick Runner.
This way of writing Bricks is deprecated and will not be supported in future versions.

def do_brick_processing(adapter, parameters, input):
    ... do something useful ...

The function do_brick_processing has three arguments:

  1. adapter : interface to the Brick Runner (details below -> Brick Adapter)
  2. parameters : optional dictionary of Brick parameters (details below -> Brick parameters )
  3. input : Incoming Flow Packet payload of type UjoMap

Brick Adapter

The Brick Adapter provides an interface to the Brick Runner. It is an
adapter class with the following attributes and methods:

Attributes

  • stop_processing : a callback function you can implement to define a termination logic,
    which is called by the Brick Runner in case of a termination signal
  • terminated : a flag that signals, if the Brick shall stop working

Methods

The adapter implements the method, emit_new_packet, that is used to send Flow
Packets to the output queue of the Brick Runner. The method can be called one or
multiple times and takes two arguments, value and port:

adapter.emit_new_packet(value, port)

The mandatory argument value is the output data of the Brick, which forms the
flow packets’ payload and the optional argument, port [default=’A’] , is the
output port the flow packet is using. Packet payloads need to be provided in Ujo format.

Return value of process and do_brick_processing

If your Brick only sends one output Flow Packet, you can return its payload upon exiting
the function. If you want to specify the output port used by the packet, you can
do so by returning a tuple:

return (payload, port)

Brick parameters

Both ways of writing a Brick allow you to define parameters for you Brick
that can be set from a default config file or via the flow configuration.
Default parameters have to be listed in a YAML configuration file, “config.yml”,
that is located in the Brick module path.
Parameters need to be provided as dictionaries, i.e. key: value pairs. If a file
“config.yml” is available in the Brick module path, default parameters are read
in automatically during the setup of the Brick Runner and reset according to the
configuration of the flow.

Brick types

There are several kinds of how a Brick can operate, for example:

Inlet

The only Brick type that ignores the input, because inlets are at the
beginning of the flows and won’t get input data - input will always be
empty. An inlet sources data from the outside world into the flow.
It will generate one or more Flow Packets from an external source
and sends them into the flow.

General Brick

This Brick type typically transforms the input into one or more output
Flow Packets.

Filter

A filter Brick typically forwards the input data to the output only on matching
the condition of the filter.

Selector

A selector Brick typically forwards the input data to one of the multiple
outputs (ports) depending of given conditions.

Outlet

An outlet terminates the processing of data through a flow by outputting it to
the outside world. The output can be, for instance, to a file or to a database.
Outlets do not send or return any further Flow Packets.