import ballerina/http;
import ballerina/lang.runtime;

// Create an endpoint with port 8080 for the mock backend services.
listener http:Listener backendEP = new (8080);

// Define the failover client endpoint to call the backend services.
http:FailoverClient foBackendEP = check new ({

    timeout: 5,
    failoverCodes: [501, 502, 503],
    interval: 5,
    // Define a set of HTTP Clients that are targeted for failover.
    targets: [
            {url: "http://nonexistentEP/mock1"},
            {url: "http://localhost:8080/echo"},
            {url: "http://localhost:8080/mock"}
        ]
});

service /fo on new http:Listener(9090) {

    resource function 'default .()
            returns http:Response|http:InternalServerError {
        var backendResponse = foBackendEP->get("/");

        // If `backendResponse` is an `http:Response`, it is sent back to the
        // client. If `backendResponse` is an `http:ClientError`, an internal
        // server error is returned to the client.
        if (backendResponse is http:Response) {
            return backendResponse;
        } else {
            return {body: backendResponse.message()};
        }

    }
}

// Define the sample service to mock connection timeouts and service outages.
service /echo on backendEP {

    resource function 'default .() returns string {
        // Delay the response for 30 seconds to mimic network level delays.
        runtime:sleep(30);

        return "echo Resource is invoked";
    }
}

// Define the sample service to mock a healthy service.
service /mock on backendEP {

    resource function 'default .() returns string {
        return "Mock Resource is Invoked.";
    }
}

Failover

Ballerina users can configure multiple HTTP clients in a given failover group. If one of the HTTP clients (dependencies) fails, Ballerina automatically fails over to another endpoint.

For more information on the underlying module, see the HTTP module.

import ballerina/http;
import ballerina/lang.runtime;
listener http:Listener backendEP = new (8080);

Create an endpoint with port 8080 for the mock backend services.

http:FailoverClient foBackendEP = check new ({

Define the failover client endpoint to call the backend services.

    timeout: 5,
    failoverCodes: [501, 502, 503],
    interval: 5,
    targets: [
            {url: "http://nonexistentEP/mock1"},
            {url: "http://localhost:8080/echo"},
            {url: "http://localhost:8080/mock"}
        ]
});

Define a set of HTTP Clients that are targeted for failover.

service /fo on new http:Listener(9090) {
    resource function 'default .()
            returns http:Response|http:InternalServerError {
        var backendResponse = foBackendEP->get("/");
        if (backendResponse is http:Response) {
            return backendResponse;
        } else {
            return {body: backendResponse.message()};
        }

If backendResponse is an http:Response, it is sent back to the client. If backendResponse is an http:ClientError, an internal server error is returned to the client.

    }
}
service /echo on backendEP {

Define the sample service to mock connection timeouts and service outages.

    resource function 'default .() returns string {
        runtime:sleep(30);

Delay the response for 30 seconds to mimic network level delays.

        return "echo Resource is invoked";
    }
}
service /mock on backendEP {

Define the sample service to mock a healthy service.

    resource function 'default .() returns string {
        return "Mock Resource is Invoked.";
    }
}
# To start the services, navigate to the directory that contains the
# `.bal` file and use the `bal run` command below.
bal run http_failover.bal
[ballerina/http] started HTTP/WS listener 0.0.0.0:8080
[ballerina/http] started HTTP/WS listener 0.0.0.0:9090
# To invoke the Failover Service, use the cURL command below.
curl -v http://localhost:9090/fo
# The `FailoverClient` endpoint is configured with three target services.The first two targets are configured to mimic
# failure backends. If one target service goes down, the failover client automatically calls the other targets.
# Once you invoke the Failover demo service, the Failover client fails over the request to the configured
# target endpoints. In this example, the third target is configured to give a successful response and the following
# response is given when the failover demo service is invoked.
# Server response:
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 9090 (#0)
> GET /fo HTTP/1.1
> Host: localhost:9090
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< content-type: text/plain
< date: Wed, 4 Sep 2019 15:29:37 +0530
< server: ballerina/1.0.0-beta
< content-length: 25
<
* Connection #0 to host localhost left intact
Mock Resource is Invoked.
# Invoke the Failover Service again using the cURL command below.
curl -v http://localhost:9090/fo
# At this point, Ballerina failover client already knows that leading endpoints (in this case the first two targets)
# failed in the last invocation and it got the successful response from the third target. So the failover client
# resumes the failover from the last successful target. In this case it is the third target and the client will get
# the immediate response for subsequent calls.
# Server response:
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 9090 (#0)
> GET /fo HTTP/1.1
> Host: localhost:9090
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< content-type: text/plain
< date: Wed, 4 Sep 2019 15:29:41 +0530
< server: ballerina/1.0.0-beta
< content-length: 25
<
* Connection #0 to host localhost left intact
Mock Resource is Invoked.