[[Singleton_MSC_services]]
= Singleton MSC services

ifdef::env-github[]
:tip-caption: :bulb:
:note-caption: :information_source:
:important-caption: :heavy_exclamation_mark:
:caution-caption: :fire:
:warning-caption: :warning:
endif::[]

The singleton service facility exposes a mechanism for installing an MSC service such that the service only starts on a single member of a cluster at a time.
If the member providing the singleton service is shutdown or crashes, the facility automatically elects a new primary provider and starts the service on that node.
In general, a singleton election happens in response to any change of membership, where the membership is defined as the set of cluster nodes on which the given service was installed.

[[installing-an-msc-service-using-an-existing-singleton-policy]]
== Installing an MSC service using an existing singleton policy

While singleton MSC services have been around since AS7, WildFly adds the ability to leverage the singleton subsystem to create singleton MSC services from existing singleton policies.

The singleton subsystem exposes capabilities for each singleton policy it defines. 

These policies, encapsulated by the `org.wildfly.clustering.singleton.service.SingletonPolicy` interface, can be referenced via the following capability name:
"org.wildfly.clustering.singleton.policy" + _policy-name_

You can reference the default singleton policy of the server via the name:
"org.wildfly.clustering.singleton.default-policy"
e.g.

[source,java,options="nowrap"]
----
public class MyServiceActivator implements ServiceActivator {
    @Override
    public void activate(ServiceActivatorContext context) {
        ServiceName name = ServiceName.parse("my.service.name");
        // Use default singleton policy
        Supplier<SingletonPolicy> policy = new ActiveServiceSupplier<>(context.getServiceTarget(), ServiceName.parse(SingletonDefaultRequirement.SINGLETON_POLICY.getName()));
        ServiceBuilder<?> builder = policy.get().createSingletonServiceConfigurator(name).build(context.getServiceTarget());
        Service service = new MyService();
        builder.setInstance(service).install();
    }
}
----


[[singleton-msc-service-metrics]]
== Singleton MSC Service metrics ==

The singleton subsystem registers a set of runtime metrics for each singleton MSC service installed via a given singleton policy.

is-primary:: Indicates whether the node on which the operation was performed is the primary provider of the given singleton service
primary-provider:: Identifies the node currently operating as the primary provider for the given singleton service
providers:: Identifies the set of nodes on which the given singleton service is installed.

e.g.

----
/subsystem=singleton/singleton-policy=foo/service=my.service.name:read-attribute(name=primary-provider)
----


[[installing-an-msc-service-using-dynamic-singleton-policy]]
== Installing an MSC service using dynamic singleton policy

Alternatively, you can configure a singleton policy dynamically, which is particularly useful if you want to use a custom singleton election policy.
`org.wildfly.clustering.singleton.service.SingletonPolicy` is a generalization of the `org.wildfly.clustering.singleton.service.SingletonServiceConfiguratorFactory` interface,
which includes support for specifying an election policy, an election listener, and, optionally, a quorum.

The SingletonElectionPolicy is responsible for electing a member to operate as the primary singleton service provider following any change in the set of singleton service providers.
Following the election of a new primary singleton service provider, any registered SingletonElectionListener is triggered on every member of the cluster.

The 'SingletonServiceConfiguratorFactory' capability may be referenced using the following capability name:
"org.wildfly.clustering.cache.singleton-service-configurator-factory" + _container-name_ + "." + _cache-name_

You can reference a 'SingletonServiceConfiguratorFactory' using the default cache of a given cache container via the name:
"org.wildfly.clustering.cache.default-singleton-service-configurator-factory" + _container-name_

e.g.

[source,java,options="nowrap"]
----
public class MySingletonElectionPolicy implements SingletonElectionPolicy {
    @Override
    public Node elect(List<Node> candidates) {
        // ...
        return ...;
    }
}

public class MySingletonElectionListener implements SingletonElectionListener {
    @Override
    public void elected(List<Node> candidates, Node primary) {
        // ...
    }
}

public class MyServiceActivator implements ServiceActivator {
    @Override
    public void activate(ServiceActivatorContext context) {
        String containerName = "foo";
        SingletonElectionPolicy policy = new MySingletonElectionPolicy();
        SingletonElectionListener listener = new MySingletonElectionListener();
        int quorum = 3;
        ServiceName name = ServiceName.parse("my.service.name");
        // Use a SingletonServiceConfiguratorFactory backed by default cache of "foo" container
        Supplier<SingletonServiceConfiguratorFactory> factory = new ActiveServiceSupplier<>(context.getServiceTarget(), ServiceName.parse(SingletonDefaultCacheRequirement.SINGLETON_SERVICE_CONFIGURATOR_FACTORY.resolve(containerName).getName()));
        ServiceBuilder<?> builder = factory.get().createSingletonServiceConfigurator(name)
                .electionListener(listener)
                .electionPolicy(policy)
                .requireQuorum(quorum)
                .build(context.getServiceTarget());
        Service service = new MyService();
        builder.setInstance(service).install();
    }
}
----
