Thursday, July 23, 2015

Over-the-air runtime updates of the IoT gateways

This is the repost of my article originally published at the DZone - Over-the-Air Runtime Updates of the IoT Gateways.

The Internet Of Things gateways are usually installed on the devices designed to run for a longer periods of time without the downtime. The is common requirement for the gateway to keep the uninterrupted processing of the messages collected from the field, even when configuration changes have to be applied to the device. While in the Java world the OSGi technology has been commonly identified with the hot redeploy features, I would like to tell you more about the possibilities that Apache Camel running outside the OSGi environment can bring into this topic.


Adding new components at runtime


Apache Camel relies on the components to provide the connectors which can be used to consume messages from the various endpoints (as well as send the messages to the endpoints). For example the gateway based on the Apache Camel could use Paho MQTT component to consume the control commands from the data center and at the same time use the Netty component to communicate with the backed REST services.



Now imagine that at some point we decided to add Salesforce component to our Gateway, so the copy of the message we sent to the backend REST service can be also sent directly to our Salesforce account.



Can we somehow dynamically add the jar containing the Salesforce component to all our production gateway devices deployed into the field? Since the gateways are constantly processing the messages from the sensors, we would like to avoid any restarts of the devices.



Dynamic updates using Camel Grape endpoints


Camel 2.16 comes with new Groovy-based Grape component. Grape is the part of the Groovy language - it is the library that can download the other libraries and add them to the classpath of the current JVM. Grape component downloads jar libraries from the file repositories (including Maven repos) and add these jars dynamically to the application classpath. As soon as the library is downloaded, the Camel can take advantage of new components and data formats provided by these jar files. For example the following Camel route will download and install Camel Saleforce component:
from("direct:start").
  to("grape:org.apache.camel/camel-salesforce/2.15.2");

After the Saleforce jar has been loaded, you can use it in the Camel routes. All that without the restart of the gateway application:

ProducerTemplate template = camelContext.createProducerTemplate();
template.sendBody("direct:dynamicEndpoint", "salesforce:createSObject");
...
from("direct:dynamicEndpoint").
  recipientList().body();



Over-the-air updates


How can we dynamically update many gateways at once using over-the-air technology? As gateways usually run in the environment with the unreliable network connection, I recommend that gateway should listen to the MQTT messages sent from the data center. MQTT client is capable of handling the unstable network connectivity. MQTT client installed on the gateway should connect to the given "update" topic (let's refer to it as over-the-air topic). Whenever we would like to load the component dynamically, we can simply use MQTT over-the-air topic and send the Maven coordinates of the artifact we want to be downloaded to the devices. We can use Camel Paho component for that purpose:
// This code is executed on the data center side.
ProducerTemplate template = camelContext.createProducerTemplate();
// Tell all our devices connected to the over-the-air MQTT topic 
// to download Camel Salesforce connector.
template.sendBody("paho:over-the-air", "org.apache.camel/camel-salesforce/2.15.2");

The following Camel route deployed on the gateway field devices can be used to receive the update requests from the MQTT broker and send them to the Grape component:
from("paho:over-the-air").
  to("grape:over-the-air");

That's all what you need to fetch and load the new library into all of your gateway devices.


Dealing with the download failures


You may be wondering what happens when the Grape component can't download the requested artifact, for example because of the network problems, so common the field environments. The is the moment when Camel and its Camel error handler redelivery policy jumps in. You can easily tell Camel what retry strategy should be used to eventually fetch and load the required dependency. All you have to do is to use a bit of the Camel DSL:
errorHandler(defaultErrorHandler().maximumRedeliveries(10).useExponentialBackOff());

Using this approach you can be sure that Camel will be keep trying to download the requested library. Usually after certain number of attempts to download the artifact, you would like to send back the error MQTT message back to the data center, so your operations team can be notified about the upgrade problems at the given device.


Loading patches on the gateway restart


The another natural question is if the patches loaded by the Grape component will be persisted after the gateway restart. Yes, Camel Grape component keeps track of the patches it loaded (by default the list of the deployed patches is stored in the device file system using plain text file). If you would like to tell Camel to load the installed patches, add the GrapeEndpoint.loadPatches method call into your route definition:
import static org.apache.camel.component.grape.GrapeEndpoint.loadPatches;
...
camelContext.addRoutes(new RouteBuilder() {
  @Override
  public void configure() throws Exception {
    loadPatches(camelContext);
  }
});


Listing patches installed on the gateway


You might be also interested in listing the patches installed on the particular gateway device. The following route demonstrates how to connect embedded HTTP server based on the Netty with the Grape component...

import static org.apache.camel.component.grape.GrapeEndpoint.loadPatches;
...
camelContext.addRoutes(new RouteBuilder() {
  @Override
  public void configure() throws Exception {
    loadPatches(camelContext);

    from("netty4-http:http://0.0.0.0:80/patches").
      setHeader(GrapeConstants.GRAPE_COMMAND, GrapeCommand.listPatches).
      to("grape:listPatches");
  }
});


...so you can open the following URL in the web browser and see the list of the installed artifacts:

$ curl http://your.gateway.com/patches
org.apache.camel/camel-salesforce/2.15.2
org.apache.camel/camel-ftp/2.15.2


Summary


As you can see, Camel in the conjunction with Groovy class loading capabilities provides hot updates features extremely useful for the IoT systems. Camel ability to provide runtime updates over-the-air is an interesting alternative for the OSGi deployments. With the Camel Grape component you can take advantage of the dynamic class loading while keeping all the benefits of the flat classpath.

7 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Awesome post, really clear explanations and great to see Camel being used for amazing things.

    To run this sort of example, what are the dependencies required to be on the IoT device besides Camel and related jars?
    is it only a JRE?
    (and obviously maven if you are building from source.)

    ReplyDelete
    Replies
    1. Hi Nicolas,

      Actually camel-grape jar is really enough. Maven will pull all the others transitive dependencies, like camel-core. How cool is that? :)

      Cheers!

      Delete
    2. Very cool and what about if running in non-dev/production mode (i.e. without maven)?

      Delete
    3. Maybe i was just over thinking it as the term IoT is so broad, the main hardware targeted atm is the raspberry pi and other similar devices right?

      Delete
    4. We target anything that runs Linux :) . But so far I have tested this on the Raspberry Pi.

      Regarding the production mode - keep in mind that in production you will probably expose some kind of the corporate Nexus instance that could be used by the external clients to get your artifacts (after the proper authorization).

      Delete
  3. This comment has been removed by the author.

    ReplyDelete