If you are new to Ballerina, first you need to go to the ballerina.io and learn the basic moves before you learn the advance stuff!
Ballerina has a powerfull model for parallel programing. It has the concept of workers where you can delegate work to parallel running executions. Apart from workers, resources in ballerina service mode can run parallely based on incoming parallel requests.
When it comes to communication between concurrent processes, one option is to use the worker interactions capabilities in ballerina. But this is possible only between closely residing workers. It is not possible to use worker interactions model to communicate between resources or if the workers are not in the same function.
The ballerina channels has been introduced to overcome above limitations in communication between concurrent processes.
Channel is a constrained type in ballerina. Which means a datatype should be tied up with a channel. So that, the given channel only holds that constrained type values. In latest ballerina release 0.982.0, channels only supports basic types, xml and json values. Other types also will be supported in the future.
Also a channel can only be defined as a top level node. This limitation is introduced by considering the visual aspects. Every ballerina program should be visualize using sequence diagrams. By limiting the channel to a top level node, it can be visualized as a vertical line in a sequence diagram. Following is how you define a json channel. ‘jsonChannel’ is the identifier of the channel.
After defining the channel it can be referred from anywhere within it’s lexical scope. We can interact with a channel by sending messages or receiving messages from a channel.
When sending a message to a channel, we can specify a key. Then the receivers of this channel with given key can fetch those messages. If a key is not specified, it is considered as a null key. So that only the null key receivers can receive those messages.
Message receivers also can specify a key, then only a message sent to that channel with given key is received. A receiver with a null key also allowed to receive messages sent without a key.
Once a channel is defined it is unique for that package. You can do channel interactions from anywhare that channel is lexically visible.
When a message send statement is reached it sent to a receiver if exist. If not message is saved and the execution continues. If there are multiple receivers on the same key, exactly one receiver will be received the message.
When a message receive statement is reached if there is an already arrived message, it fetches the message and the execution continues. If there is no such message for the given key in the channel, the execution will be halted until a message is available. The execution will be resumed once the expected message is available on the channel.
Usages of channels
Channels can be used for inter worker communications and synchronizing workers. Following is a sample code for worker interactions using channels.
In the above code we have defined a channel constrained to xml with identifier ‘xmlChn’. Worker w1 wait for a message with the given key from the xmlChn channel. After receiving it, it waits for a message with a null key. In the worker w2 a message with a key is sent. A null key message has been sent from the worker w3. Even though above workers are in the same function, it is not a requirement. As long as the channel is reachable according to lexical scoping, it is possible to interact with that channel.
Channels can be used for message correlation as well. In order to message correlation, there should be a way to communicate between resources in ballerina. Channels provide a common pipe for different resources to communicate. This is a very useful capability for workflow related scenarios.
As you could see in the above sample, the ‘receive’ resource is waiting for a message from the channel. Only way it could continue the execution is once the ‘send’ resource send a message to the channel with the expected key. So we can correlate requests to the send and receive reaoirces by deriving the key from the request payloads or a header value etc. Ballerina developer has the freedom to decide on which entity the correlation should be done.
Configuring the channels DB
When a message has been sent to a channel, if there is no receiver available, we have to somehow persist this received message. By default ballerina uses an in-memory H2 database for persisting channel messages. But this is not a good solution because if the program crashes, the in memory messages also will be lost. It is possible to configure a database of your choice for channels through the ballerina config API. Following is the expected TOML format for channels config. You can use any JDBC config parameters here.
When you configure a DB for channel messages, you need a create a table named “messages” with following table structure. Well, you need to set the length of the msgKey and value columns according to your requirements. These are the fields that hold the channel key value and the channel message.
Hope this is all you need to play with Ballerina channels! Happy dancing!