Attaching multiple services to the same listener in Ballerina

Maryam Ziyad
Ballerina Swan Lake Tech Blog
3 min readDec 31, 2023
Photo by Christin Hume on Unsplash

Listeners and service objects are used to provide services in Ballerina.

A service object is a special kind of object that has remote methods (RPC style) or resource methods (data-oriented style) for inbound network interactions. A service object can be attached to any number of listeners.

Listeners are the entities that receive network input and call the relevant remote or resource method of the relevant service object attached to the listener.

A service declaration can specify the listener(s) to which the service has to be attached to in one of the following ways.

1. Referring to a listener declared by a listener declaration

A listener declaration is a module-level declaration that initializes a listener object and registers it with the module.

// Listener declaration for an HTTP listener, listening on port `8080`.
listener http:Listener ln = new (8080);

This listener can be used in a service declaration to attach the service to the listener.

// Service declaration which attaches the service to listener `ln`,
// with `/intransit` as the attach point (base path).
service /intransit on ln {

}

2. Initializing the listener in-line

If the listener is only used in one service declaration and is not referred to elsewhere, it can be initialized in-line in the service declaration as follows. Similar to what happens with a module-level listener declaration, the initialized listener is registered with the module.

service /intransit on new http:Listener(8080) {

}

For each listener registered with the module. Ballerina calls the start method of the listener once the initialization phase of the module completes successfully, starting the listening phase to accept requests. The listening phase continues until the program exits on user input and before the program terminates the gracefulStop or immediateStop method is called on each of the registered listeners.

Attaching more than one service to the same listener

If there is a requirement to attach more than one service to the same listener, it is just a matter of defining the listener as a listener declaration (Approach 1) and referring to it in the different service declarations.

import ballerina/http;

// Listener declaration for an HTTP listener, listening on port `8080`.
listener http:Listener ln = new (8080);

enum Status {
QUEUED = "queued",
IN_TRANSIT = "in transit",
DELIVERED = "delivered"
}

type OrderStatus record {|
*http:Ok;
Status body;
|};

map<Status> orders = {};

// Service declaration which attaches the service to listener `ln`,
// with `/intransit` as the attach point (base path).
service /intransit on ln {
resource function get status/[string orderId]() returns OrderStatus|http:NotFound {
lock {
if orders.hasKey(orderId) {
return <OrderStatus> {body: orders.get(orderId)};
}
return <http:NotFound> {};
}
}
}

// Service declaration which attaches the service to listener `ln`,
// with `/health` as the attach point.
service /health on ln {
resource function get . () returns http:Ok => {};
}

This article is based on Ballerina Swan Lake but is expected to remain compatible with newer versions.

This was previously published on StackOverflow.

--

--