Create a Singleton in a Cluster on WildFly 10

Using a Singleton Service in a cluster is not something completely new concept. In JBoss 6 you could use a SingletonService to decorate a Service such that the service will only ever be started on one node in a cluster at any given time. WildFly 10 brings again to life this service with a fully configurable subsystem which allows fine tuning of the Singleton Service:

<subsystem xmlns="urn:jboss:domain:singleton:1.0">
    <singleton-policies default="default">
        <singleton-policy name="default" cache-container="server">
            <simple-election-policy/>
        </singleton-policy>
    </singleton-policies>
</subsystem>

What is configurable in the subsystem is first of all the policy. Out of the box the singleton subsystem uses the default policy which creates a circular list of cluster members, starting from the oldest, which are in turn elected to host the singleton application. If you prefer rather a random policy, you can at any time vary it from the CLI with:

/subsystem=singleton/singleton-policy=foo/election-policy=random:add()

The other important thing is the cache-container which must reference a valid cache from the Infinispan subsystem. If you are using the standard configuration, the default "server" cache will be used.

Creating a Singleton application

In order to activate the Singleton Service you need to provide an XML configuration file named singleton-deployment.xml to be placed in the META-INF folder of your JAR/WAR archive:

src
└── main
    ├── resources
    │   ├── META-INF
    │   │   └── singleton-deployment.xml
    └── webapp
        └── index.jsp

 Here is a minimalist singleton-deployment.xml:

<singleton-deployment xmlns="urn:jboss:singleton-deployment:1.0"/>

Once that the XML file is picked up, the application will be deployed in your cluster just on the elected provider. You can see it from your logs that the application web.war deployed in the cluster made of server-one and server-two has been activated on server-two, which will act as master:

[Server:server-two] 12:17:35,310 INFO  [org.wildfly.clustering.server] (notification-thread--p4-t1) WFLYCLSV0003: master:server-two elected as the singleton provider of the jboss.deployment.unit."web.war".FIRST_MODULE_USE service
[Server:server-two] 12:17:35,332 INFO  [org.wildfly.clustering.server] (notification-thread--p4-t1) WFLYCLSV0001: This node will now operate as the singleton provider of the jboss.deployment.unit."web.war".FIRST_MODULE_USE service

You can test your application which is not just available on server-two (say on port 8180):

$ curl http://localhost:8180/web/index.jsp
Hello world!

Now, as we stop server-two, a new master will be elected:

/host=master/server-config=server-two:stop

As a result, the application is available now on server-one (offset 0):

You can test your application which is not just available on server-two (say on port 8180):

$ curl http://localhost:8080/web/index.jsp
Hello world!

Practical usages of the Singleton Service

One practical usage of the Singleton Service is the EJB Timer which can be easily configured to run on a single node in the cluster so that you get Timer notifications just from a node in a cluster, which however provides High Availability of the timer, in case the node shuts down.

For example, see the following Timer EJB taken from: https://github.com/wfink/jboss-eap-playground/tree/master/eap7ClusterHASingletonDeployment/ejb

@Stateless
public class SimpleBean implements SimpleRemote {
    private static final Logger log = Logger.getLogger(SimpleBean.class);

    @Resource
    SessionContext context;

    private String getJBossNodeName() {
        return System.getProperty("jboss.node.name");
    }

    @Schedule(hour="*", minute="*", second="*/10", persistent=false)
    public void showRunning() {
        log.infof("Timer is active @%s", getJBossNodeName());
    }

    @Override
    public void invoke(String text) {
        log.infof("Bean invocation @%s: %s", getJBossNodeName(), text);
    }
}

All you need to turn this Timer EJB in a Singleton Timer is the singleton-deployment.xml to be placed in the META-INF folder of your JAR and you're done.

Follow us on Twitter