/failover-vaadin

A Vaadin Add-on which automatically performs browser-side fail-over. If the connection to the primary server is lost, the browser will automatically redirect itself to a fallback/spare server of your choosing.

Primary LanguageJava

Build Status Published on Vaadin  Directory Stars on Vaadin Directory

FailOver Vaadin Add-On

A Vaadin Add-on which automatically performs browser-side fail-over. If the connection to the primary server is lost, the browser will automatically redirect itself to a fallback/spare server of your choosing.

To demonstrate, check out this FailOver Vaadin Add-On Video on Youtube. The video shows launching of four independent Jetty instances in Docker on four different ports, 8080-8083.

The main idea behind this add-on is explained in the Client-side Fail-over blogpost.

Advantages:

  • No single point of failure. Well, the browser is the single-point-of-failure, but that's user's responsibility ;)
  • Incredibly easy setup - just add Maven dependency on this add-on and recompile your widgetset.
  • No server-side clustering needed
  • Servers are totally independent one from another, and may even use a mixture of server kinds, different versions of application, ...

Disadvantages:

  • Session is lost
  • If the main server dies, new clients cannot connect.
  • If the main server dies and user presses F5 in the browser, she will just get "Connection Refused". This could be remedied by offline mode

Features:

  • Supports multiple fallback servers to reconnect to, either in round-robin or random-robin.
  • Prior reconnecting the URL is pinged first, whether the spare server is actually alive.
  • A simple load-balancer, by selecting a random server from the list instead of always choosing the primary one.
  • The user must initiate the failover process manually. This way she will understand that the server has crashed and that she may lose some data (that is, the session).

Future improvements:

  • Offline mode of the bootstrap page, which will connect to the spare server even in case when the primary server is down.

Quickly Test It Out

  1. Clone this project and open it on your IDE
  2. Run mvn -C clean install to compile the widgetset.
  3. Find the Server class and run its main method. It will start first server on localhost:9991
  4. Find the Server2 class and run its main method. It will start second server on localhost:9992
  5. Browse the first server at localhost:9991.
  6. Kill the Server class.
  7. Press the "Click Me" button. Then, press the "Try Spare Servers" button. The browser should automatically find and open the second server.

Integrating With Your App

Add the following to your pom.xml:

<dependency>
    <groupId>org.vaadin.addons.failover</groupId>
    <artifactId>failover-vaadin</artifactId>
    <version>0.1.2</version>
</dependency>

You'll need to add a Vaadin Add-on repository as well, please see FailOver AddOn on Vaadin Directory on how to do that.

Then, add the following code to your UI's init() method:

@Widgetset("AppWidgetset")
public class MyUI extends UI {

    @Override
    protected void init(VaadinRequest vaadinRequest) {
        final List<String> urls = Arrays.asList("http://localhost:8080", "http://localhost:8081", "http://localhost:8082", "http://localhost:8083");
        final FailoverReconnectExtension failoverExtension = FailoverReconnectExtension.addTo(this);
        failoverExtension.setUrls(urls);
        failoverExtension.setPingImagePath("/VAADIN/themes/valo/img/app-icon.png");
        getReconnectDialogConfiguration().setDialogText("Can't connect to the server. The network may be down, or the server has crashed. Press the 'Try Spare Servers' button to try to connect to fallback server.");
        ...
    }
}

You will now have to configure your app to allow to ping it properly from JavaScript. Please read on.

Important - Ping in JavaScript

Prior failing over to a server, we actually need to know whether the server is actually alive. Thus, JavaScript needs to ping the server. However, that's not easy to do. There are two viable workaround solutions, both with drawbacks:

The image ping

The easiest way is to use the image element to load arbitrary image from the server. If that succeeds, the server is online. If that fails, the server is down. The problem is that if the target image is 404 not found or it is not an image (but, say, a CSS), the image loading will fail.

When employing this solution, just drop any png image e.g. to your theme, then make sure that:

  1. the image exists, and
  2. it is actually an image

To activate this ping type, just call

failoverExtension.setPingImagePath("/VAADIN/themes/valo/img/app-icon.png");

This example code expects that you're using the Valo theme and you have the app-icon.png image located in your src/main/resources/VAADIN/themes/valo/img folder. If not, please place an image into your theme folder and update the ping image path accordingly.

For example, when you launch the Server example class, the ping image is located at http://localhost:9991/VAADIN/themes/valo/img/app-icon.png and is loaded from the src/test/resources/VAADIN/themes/valo/img/app-icon.png.

The Ajax/XMLHttpRequest ping

The idea is to open a http request to the target server. If the server responds in any way, it is alive.

The problem is that browser disallows to connect to another site because of Cross-Origin resource sharing.

When employing this type of ping, don't call the setPingImagePath method to activate the Ajax ping. Then, make sure that:

  • you have CORS configured correctly in your webapp. If the CORS is misconfigured, the ping will incorrectly report the server being down.

You can follow the following tutorial to set up CORS in your webapp: https://vaadin.com/blog/-/blogs/using-cors-with-vaadin

Add-on Development instructions

This is a Vaadin add-on project created with in.virit:vaadin-gwt-addon archetype. The project supports GWT based extensions for Vaadin.

  1. Import to your favourite IDE
  2. Run main method of the Server class to launch embedded web server that lists all your test UIs at http://localhost:9991
  3. Code and test
  • create UI's for various use cases for your add-ons, see examples. These can also work as usage examples for your add-on users.
  • create browser level and integration tests under src/test/java/
  • Browser level tests are executed manually from IDE (JUnit case) or with Maven profile "browsertests" (mvn verify -Pbrowsertests). If you have a setup for solidly working Selenium driver(s), consider enabling that profile by default.
  1. Test also in real world projects, on good real integration test is to create a separate demo project using vaadin-archetype-application, build a snapshot release ("mvn install") of the add-on and use the snapshot build in it. Note, that you can save this demo project next to your add-on project and save it to same GIT(or some else SCM) repository, just keep them separated for perfect testing.

GWT related stuff

  • To recompile test widgetset, issue mvn vaadin:compile, if you think the widgetset changes are not picked up by Vaadin plugin, do a mvn clean package or try with parameter mvn vaadin:compile -Dgwt.compiler.force=true
  • To use superdevmode, issue "mvn vaadin:run-codeserver" and then just open superdevmode like with any other project

Creating releases

  1. Push your changes to e.g. Github
  2. Update pom.xml to contain proper SCM coordinates (first time only)
  3. Use Maven release plugin (mvn release:prepare; mvn release:perform)
  4. Upload the ZIP file generated to target/checkout/target directory to https://vaadin.com/directory service (and/or optionally publish your add-on to Maven central)