Singleton Service Pattern

Learn the Singleton Service design pattern and its usage.

Intent

This pattern is to ensure that only a single instance of a service can be active at a time.The Singleton Service pattern is also known as the HA Singleton in the clustered JBoss EAP.

Context and problem

We have seen how the Service Instance pattern can help us improve a service’s performance and availability. The system has increased throughput and availability by running multiple instances of the same service and having a request dispatcher capable of load balancing the requests to all available service instances. The system’s availability also increases because if an instance of the service becomes unavailable, the request dispatcher detects this and forwards future requests to running instances. There are certain use cases where only one instance of a service is allowed to run at a time. For example, if we have a scheduled job (a trigger-based service) and run multiple instances of the same job, every instance would trigger at the scheduled intervals rather than having only one trigger fired as expected by the business.

Another example would be if the service performs polling on certain resources (a file system or database), and we want to ensure that only a single instance, and maybe even a single thread performs the polling and processing. In all these plus similar situations, we need some control over how many instances (usually, only one) of a particular service are active at a time, regardless of how many instances have been started. The Service Instance pattern still can be useful to achieve high availability in these cases, but there is an extra capacity needed to ensure that only one instance of a service is active at a given moment.

Forces and solution

The Service Instance pattern creates an active/active topology where all service instances are active and share the system load. We need an active/passive (or master/slave) topology where only one instance is active and all the other instances are passive. We can control the service instances through a distributed lock in a distributed system. Whenever a service instance is started, it will try to acquire the lock, and if it succeeds, the service will become active. Any subsequent service that fails to acquire the lock will continuously wait and try to get it if the currently active service releases it. Many existing frameworks widely use this mechanism to achieve high availability and resilience. For example, Apache ActiveMQ can run in a master/slave topology where the data source is the distributed lock. The first ActiveMQ instance that starts up acquires the lock and becomes the master, and other instances become slaves and wait for the lock to be released. Apache Karaf can also run master/slave topology with a shared lock to achieve high availability.

Mechanics

Camel does not have any mechanism at the framework level for clustering, high availability, or singleton instances (yet). As such, clustering with singleton services has to be done in one of two possible layers: container (or process) or Camel route (through a component or RoutePolicy).

  • Container/process-based Camel singletons: As the name suggests, this mechanism relies on the actual container or the container managing process to ensure that only a single instance of the Camel application is running. The Camel code is unaware that it is intended and will run as a single instance. This perspective is similar to having a POJO created as a singleton from the managing container (such as the spring framework).

Get hands-on with 1200+ tech skills courses.