Ballerina for microservices
With its visionary design and cutting-edge features, Ballerina empowers developers to create robust, scalable, and easily maintainable microservices architectures.
The Ballerina programming language effortlessly facilitates the construction and seamless deployment of microservices, making the process remarkably straightforward for developers.
![Position Ballerina](/images/msa-intro.png)
Purposefully crafted for microservices integration
Ballerina is specifically engineered to thrive in the domain of distributed systems. Every facet of Ballerina, from its syntax to its constructs and abstractions, is thoughtfully designed to streamline the integration, development, deployment, and management of microservices.
configurable int port = 8080;
type Album readonly & record {|
string id;
string title;
string artist;
decimal price;
|};
service / on new http:Listener(port) {
resource function get albums() returns Album[] {
return albums.toArray();
}
resource function get albums/[string id]() returns Album|http:NotFound {
Album? album = albums[id];
if album is () {
return http:NOT_FOUND;
} else {
return album;
}
}
resource function post albums(@http:Payload Album album) returns Album {
albums.add(album);
return album;
}
}
Robust data persistence
Ballerina's data persistence capabilities streamline microservices development by providing a simple, language-native approach to different data stores. With built-in connectors, Ballerina facilitates seamless communication with various data sources, reducing integration complexities. Also the bal persist CLI tool allows users to use the defined data model to generate client API to access the data in the given data store. This type-safe client API ensures data consistency and error handling, enhancing reliability. Ballerina's data orchestration features enable efficient data transformations and manipulation, crucial for microservices processing diverse data formats. Ballerina's robust data persistence capabilities empower microservices to efficiently manage and interact with data, simplifying development and ensuring data integrity in complex distributed systems.
![Robust data persistence](/images/bal-persist-diagram.png)
Native support for concurrency
Ballerina combines the benefits of static typing and native support for concurrency. By catching errors early during development, the language ensures greater reliability and stability in microservices systems. Additionally, Ballerina's concurrency support enables developers to handle concurrent operations efficiently, improving the performance and responsiveness of their microservices.
import ballerina/http;
type Person record {|
string name;
boolean employed;
|};
type Summary record {|
int count;
int average;
|};
int[] tasks = [1, 4, 5, 2, 7, 4];
service on new http:Listener(8080) {
resource function post person\-tasks(Person[] members) returns Summary {
return process(members, tasks);
}
}
function process(Person[] members, int[] tasks) returns Summary {
worker w1 {
Person[] employedMembers = from Person p in members where p.employed select p;
int count = employedMembers.length();
count -> w2;
count -> function;
}
worker w2 {
int total = int:sum(...tasks);
int employedCount = <- w1;
int avg = employedCount == 0 ? 0 : total / employedCount;
avg -> function;
}
int count = <- w1;
int average = <- w2;
return {count, average};
}
Type-safe
Ballerina emphasizes type safety in inter-service communication. This enables compile-time checks, reducing errors and enhancing code quality. Additionally, it simplifies maintenance and acts as clear documentation for microservices. As a result, services interact seamlessly with precise data types, preventing data mismatches and ensuring robust communication between microservices in a type-safe manner, improving reliability and maintainability of the microservices architecture.
import ballerina/http;
type UserRecord record {
string userId;
string username;
int age;
};
// In-memory store for user data
map<UserRecord> userStore = {};
// HTTP service to manage users
service / on new http:Listener(8080) {
// UserRecord record type guarantees that the payload sent to user endpoint with a POST
// method is always of shape UserRecord
resource function post user(UserRecord user) returns json {
userStore[user.userId] = user;
json response = {"message": "User created successfully"};
return response;
}
// UserRecord record type guarantees that the response sent back to client with a GET
// method is always of shape UserRecord
resource function get user(string userId) returns UserRecord? {
UserRecord? user = userStore[userId];
return user;
}
}
Designed for failure
By incorporating proven patterns and best practices, Ballerina equips you with the tools to proactively address failure scenarios, ensuring system stability and minimizing downtime and offering a revolutionary approach to microservices development that is inherently designed for failure
with its built-in fault-tolerance mechanisms and circuit-breaking capabilities.
type Album readonly & record {
string title;
string artist;
};
public function main() returns error? {
http:Client albumClient = check new ("localhost:9090",
circuitBreaker = {
// The failure calculation window measures how long the circuit breaker keeps the
// statistics for the operations.
rollingWindow: {
// The period is in seconds for which the failure threshold is calculated.
timeWindow: 10,
// The granularity (in seconds) at which the time window slides.
// The rolling window is divided into buckets and slides by these increments.
bucketSize: 2,
// The minimum number of requests in the rolling window that trips the circuit.
requestVolumeThreshold: 0
},
// The threshold for request failures. When this threshold exceeds, the circuit trips.
// This is the ratio between failures and total requests. The ratio is calculated using
// the requests received within the given rolling window.
failureThreshold: 0.2,
// The period (in seconds) to wait before attempting to make another request to the upstream service.
resetTime: 10,
// HTTP response status codes that are considered as failures
statusCodes: [400, 404, 500]
}
);
Album[] payload = check albumClient->/albums;
io:println(payload);
}
Harnessing Ballerina's test framework for success
Ballerina's test framework is a powerful asset for microservices development, ensuring top-notch quality and reliability. With support for unit, integration, and functional testing, developers can cover all critical aspects of their microservices. The framework seamlessly integrates with Ballerina, eliminating complexity and enabling easy execution within the development environment.
// Sends an email to the specified email addresses
// and returns an error if found.
function sendNotification(string[] emailIds) returns error? {
email:Message msg = {
'from: "builder@abc.com",
subject: "Error Alert ...",
to: emailIds,
body: ""
};
return smtpClient -> sendMessage(msg);
}
@test:Config { }
function testSendNotification() {
smtpClient = test:mock(email:SmtpClient);
// Stubs the `send` method of the `mockSmtpClient` to do nothing.
// This is used for functions with an optional or no return type.
test:prepare(smtpClient).when("sendMessage").doNothing();
string[] emailIds = ["user1@test.com", "user2@test.com"];
error? err = sendNotification(emailIds);
test:assertEquals(err, ());
}
Network-awareness for seamless integration
Microservices communicate extensively over networks, making integration a crucial aspect of their design. Ballerina shines in this area with its built-in network awareness. It seamlessly integrates with various protocols (HTTP, gRPC, and more) and data formats (JSON, XML) commonly used in microservices architectures.
![Network-awareness for seamless integration](/images/network-awareness.png)
Powerful integration capabilities
Unlocking the power of seamless integration, Ballerina shines with its exceptional capability to connect and interact with a vast array of external systems and services. With an extensive range of connectors at its disposal, Ballerina effortlessly integrates with databases, message brokers, web services, and more.
public type Order readonly & record {
int orderId;
string productName;
decimal price;
boolean isValid;
};
listener kafka:Listener orderListener = new (kafka:DEFAULT_URL, {
groupId: "order-group-id",
topics: "order-topic"
});
service on orderListener {
remote function onConsumerRecord(Order[] orders) returns error? {
// The set of orders received by the service are processed one by one.
check from Order 'order in orders
where 'order.isValid
do {
log:printInfo(string `Received valid order for ${'order.productName}`);
};
}
}
Ballerina's native HTTP/2 support
Revolutionize your microservices architecture with Ballerina's cutting-edge native support for HTTP/2. Say goodbye to latency and embrace lightning-fast communication between your services through the power of multiplexing. Experience optimal resource utilization and bandwidth efficiency with advanced features such as server push and stream prioritization.
![Ballerina's native HTTP/2 support](/images/http2-ballerina.png)
Ballerina and GraalVM fuel microservices with lightning-fast performance
With this duo, your microservices will reach new heights of efficiency and responsiveness, leaving competitors in the dust. Ballerina's seamless integration with GraalVM harnesses the power of just-in-time compilation and native image generation, resulting in optimized execution and unparalleled performance. Stay ahead of the game with Ballerina and GraalVM, and experience microservices performance like never before.
![Ballerina and GraalVM fuel microservices with lightning-fast performance](/images/graalvm-ballerina.png)
Blend of top-down and bottom-up development
Ballerina revolutionizes microservices development by offering unparalleled support for both top-down and bottom-up approaches. Developers can effortlessly design their microservices architecture with Ballerina's intuitive syntax and design tools, allowing for clear architectural vision and easier collaboration. Alternatively, they can build individual microservices with precision and speed, seamlessly integrating them into a cohesive architecture.
![Blend of top-down and bottom-up development](/images/architecture-view.png)
Accelerating DevOps agility
Ballerina promotes DevOps practices by offering seamless integration with popular container platforms like Docker and Kubernetes. It supports containerization and provides native support for deployment on container orchestration platforms, facilitating efficient scaling and management of microservices.
![Accelerating DevOps agility](/images/devops-agility.png)
Ballerina enables seamless monitoring of microservices
Ballerina's tracing capabilities go beyond basic monitoring. With seamless integration with popular tracing frameworks like Jaeger and OpenTelemetry, developers can effortlessly instrument their microservices with tracing spans, enabling end-to-end tracing and analysis of complex transaction flows.
![Ballerina enables seamless monitoring of microservices](/images/screenshots-collage-final-image-transparent-v5.png)