Chapter 91. Master Component

Abstract

The Master component provides a way to ensure that only a single consumer in a cluster consumes from a given endpoint; with automatic failover if that JVM dies. This feature can be useful if you need to consume from a legacy back-end that doesn't support concurrent consumption or, due to commercial or stability reasons, you can have only a single connection to the back-end at any point in time.

Dependencies

The Master component can only be used in the context of a fabric-enabled Red Hat JBoss Fuse container. You must ensure that the fabric-camel feature is installed.
In the context of Fabric, you install a feature by adding it to the relevant profile. For example, if you are using a profile called my-master-profile, you would add the fabric-camel feature by entering the following console command:
karaf@root> fabric:profile-edit --features fabric-camel my-master-profile

URI format

A Master endpoint can only be used as a consumer endpoint. It has the following URI format:
master:ClusterID:EndpointURI[?Options]
Where the URI, EndpointURI, is published in the fabric registry and associated with the ClusterId cluster.

URI options

The Master component itself does not support any URI options. Any options on the URI are, therefore, applied to the specified consumer endpoint, EndpointURI.

How to use the Master component

The Master component is useful in cases where you need to poll messages from an endpoint, but you are only allowed to make one connection to that endpoint. In this case, you can use the Master component to define a failover cluster of consumer endpoints. Each Master endpoint in the cluster is capable of consuming messages from the given endpoint, but only one of the Master endpoints is active at any time (the master), while the other Master endpoints are waiting (the slaves).
For example, to set up a cluster of Master endpoints that can consume from the seda:bar endpoint, you would proceed as follows:
  1. Define the Master endpoints with the following URI (where each endpoint in the cluster uses exactly the same URI):
    master:mysedalock:seda:bar
    Each of the Master endpoints in the cluster tries to get the mysedalock lock (implemented as a key in the Zookeeper registry). The Master endpoint that succeeds in getting the lock becomes active (the master) and starts consuming messages from the seda:bar endpoint. The other Master endpoints enter a waiting state and continue to try the lock (the slaves).
  2. You must remember to include the fabric-camel feature in the profile that deploys a Master endpoint.
  3. In Blueprint XML, you can define a Master endpoint at the start of a Camel route, as follows:
    <?xml version="1.0" encoding="UTF-8"?>
    <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        ...
        <camelContext id="camel" xmlns="http://camel.apache.org/schema/blueprint">
            <route>
                <from uri="master:mysedalock:seda:bar"/>
                ...
            </route>
        </camelContext>
        ...
    </blueprint>

Example of a master-slave cluster polling a JMS ActiveMQ broker

For example, a typical way to use the Master component is to create a cluster of exclusive consumers for consuming messages from a JMS queue. Only one of the Master endpoints consumes from the queue at any time, and if that Master endpoint goes down, one of the other Master endpoints takes over (becomes the new master). In this example, we create a cluster of two Camel routes, where each route starts with a Master endpoint that is capable of consuming from the specified queue, FABRIC.DEMO.

Steps to create a cluster that polls messages from an ActiveMQ broker

To create a master-slave cluster that polls messages from an ActiveMQ broker, based on the Master component, perform the following steps:
  1. If you do not already have a fabric, enter the following console command to create one:
    JBossFuse:karaf@root> fabric:create --new-user AdminUser --new-user-password AdminPass
      --zookeeper-password ZooPass --wait-for-provisioning
    The --new-user and --new-user-password options specify the credentials for a new administrator user. The Zookeeper password is used to protect sensitive data in the Fabric registry service (all of the nodes under /fabric).
    Note
    If you use a VPN (virtual private network) on your local machine, it is advisable to log off VPN before you create the fabric and to stay logged off while you are using the local container. A local Fabric Server is permanently associated with a fixed IP address or hostname. If VPN is enabled when you create the fabric, the underlying Java runtime is liable to detect and use the VPN hostname instead of your permanent local hostname. This can also be an issue with multi-homed machines. To be absolutely sure about the hostname, you could specify the IP address explicitly—see chapter "Creating a New Fabric" in "Fabric Guide".
  2. For this example, you must have access to a running instance of an Apache ActiveMQ broker and you must know the IP port of the broker's OpenWire connector. For example, you might get access to an ActiveMQ broker in one of the following ways:
    • You just created the fabric on a clean installation of JBoss Fuse (after a cold restart). In this case, the root container ought to include the jboss-fuse-full profile by default. You can check whether this is the case by entering the fabric:container-list console command, as follows:
      JBossFuse:karaf@root> fabric:container-list 
      [id]    [version] [connected] [profiles]                                         [provision status]
      root*   1.0       true        fabric, fabric-ensemble-0000-1, jboss-fuse-full    success
      By default, the jboss-fuse-full profile instantiates an ActiveMQ broker that listens on port 61616. You can use this broker for the current example.
    • If no broker is running in the root container (or any other container), you can quickly install a broker into a new fabric child container, broker1, by entering the following fabric command at the console prompt:
      JBossFuse:karaf@root> fabric:container-create-child --profile mq-default root broker1
      In this case, you can use the browser-based Fuse Management Console to discover the IP port of the OpenWire connector on the broker.
  3. Create the master-example profile, which will be used to deploy a simple Apache Camel route that uses the Master component. Enter the following console command to create the profile:
    JBossFuse:karaf@root> fabric:profile-create --parents default master-example
  4. Add the requisite Karaf features to the master-example profile. Enter the following console commands:
    fabric:profile-edit --features fabric-camel master-example
    fabric:profile-edit --features activemq-camel master-example
  5. Define the simple Camel route as a resource in the master-example profile. Invoke the built-in text editor to create a new camel.xml resource, as follows:
    fabric:profile-edit --resource camel.xml master-example
    Copy and paste the following content into the built-in text editor:
    <?xml version="1.0" encoding="UTF-8"?>
    <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    
        <camelContext id="camel" xmlns="http://camel.apache.org/schema/blueprint">
            <route id="fabric-server">
                <from uri="master:lockhandle:activemq:queue:FABRIC.DEMO"/>
                <log message="Message received : ${body}"/>
            </route>
        </camelContext>
    
        <bean id="activemq"
              class="org.apache.activemq.camel.component.ActiveMQComponent">
            <property name="brokerURL" value="tcp://localhost:OpenWirePort"/>
            <property name="userName" value="UserName"/>
            <property name="password" value="Password"/>
        </bean>
    
    </blueprint>
    Remember to customize the route configuration by replacing OpenWirePort with the port number of the OpenWire connector on the broker, and by replacing UserName and Password by any valid JAAS credentials on the container (for example, you could substitute the AdminUser and AdminPass credentials created in Step 1 of these instructions).
    To save and exit from the text editor, type Ctrl-S, Ctrl-X.
  6. Configure the master-example profile to deploy the camel.xml resource as an OSGi bundle. Enter the following console command to create a new entry in the master-example agent properties:
    fabric:profile-edit --bundles blueprint:profile:camel.xml master-example
    Note
    The blueprint: prefix tells Fabric to deploy the specified resource as a Blueprint XML file, and the profile: prefix tells Fabric where to find the resource (that is, in the current version of the current profile).
  7. Create two new child containers, so that you can deploy the master-example profile as a cluster (one master and one slave). Enter the following console command:
    fabric:container-create-child root child 2
  8. Now deploy both the master-example profile and the mq-client profile to each of the child containers, as follows:
    fabric:container-change-profile child1 master-example mq-client
    fabric:container-change-profile child2 master-example mq-client
  9. If you now send some messages to the FABRIC.DEMO queue on the broker, the messages are consumed by one (and only one) of the deployed master endpoints. For example, you can easily create and send messages to the broker using the browser-based Fuse Management console.
  10. If you stop the container that hosts the current master (initially, the child1 container), the slave will be promoted to be the new master (in the child2 container) and will start consuming messages from the FABRIC.DEMO queue. For example, assuming that child2 contains the current master, you can stop it by entering the following console command:
    fabric:container-stop child2

OSGi bundle plug-in configuration

When defining an OSGi bundle that uses Master endpoints, the Import-Package bundle header must be configured to import the following Java packages:
io.fabric8.zookeeper
For example, assuming that you use Maven to build your application, Example 91.1, “Maven Bundle Plug-In Configuration” shows how you can configure the Maven bundle plug-in to import the required packages.

Example 91.1. Maven Bundle Plug-In Configuration

<project ... >
  ...
  <build>
    <defaultGoal>install</defaultGoal>
    <plugins>
      ...
      <plugin>
        <groupId>org.apache.felix</groupId>
        <artifactId>maven-bundle-plugin</artifactId>
        <extensions>true</extensions>
        <configuration>
          <instructions>
            <Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
            <Import-Package>
              io.fabric8.zookeeper,
              *
            </Import-Package>
          </instructions>
        </configuration>
      </plugin>
    </plugins>
  </build>
  ...
</project>