Messaging

Hydra supports inter-service communication in the following ways:

  • Discovery and direct use of the server's networking info (IP and Port).
  • Through the use of the makeAPIRequest method.
  • Using inter-service messaging.
  • Using service message queues.

Which approach you use depends on your application's requirements and the amount of extra work you're willing to do. Using Hydra's messaging methods abstracts the network layer functionality you might otherwise need to contend with. So it offers an easier and more reliable way of interacting with remote services.

Discovery and direct use of the service's networking info is straightforward:

let apiRoute = '/v1/email/send';
hydra.findService('emailer')
  .then((service) => {
    let url = `http://${service.ip}:${service.port}/${apiRoute}`;
    let options = {
      headers: {
        'content-type': 'application/json',
        'Accept': 'application/json; charset=UTF-8'
      },
      method: 'post'
    };
    options.body = emailObject;
    fetch(url, options)
    :
    :

Note: using the above approach should be preceded by a check to see whether the service is available using thegetServicePresencemethod. After all, we want to make sure the service is both registered, and currently available.

This is where using Hydra'smakeAPIRequestmethod ends up being easier and less error prone. ThemakeAPIRequestmethod accepts an object which contains the service's name along with other useful, but optional, information. The method automatically handles checking for service availability and can even push the message (request) to the service's message queue if the service is temporally unavailable. This is optional behavior and presumes that this is acceptable to the sender and that the remote service is capable of handling the request as a queued message.

let message = hydra.createUMFMessage({
  to: 'emailer:/v1/email/send',
  from: 'website:backend',
  body: {
    to: '[email protected]',
    from: '[email protected]',
    emailBody: 'Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium'
    fallbackToQueue: true
  }
});
hydra.makeAPIRequest(message)
  then()
:

Inter-service messaging

Using Hydra you can send messages between services and even route messages among a series of services. This is one of the features that theHydra-Routeroffers.

Built-in message channels

Every hydra service automatically listens to two built-in channels, where messages sent from other services arrive.

One channel listens to any message sent to a type of service, another channel listens for messages directed to a specific service instance. So a message sent to afile-processingservice would be received by all instances of that service. While a message sent to5585f53bd1171db38eafd79bf16e02f4@file-processingwould only be handled by the service instance with an ID of5585f53bd1171db38eafd79bf16e02f4.

To send a message to a service you can use thesendMessagecall.

let message = hydra.createUMFMessage({
  to: 'test-service:/',
  from: 'blue-service:/',
  body: {
    fileData: '{base64}'
  }
});
hydra.sendMessage(message);

The first parameter is the name of the service you want to send a message to, and the second parameter is a UMF formatted object containing a message.

When sendMessage is used, the message is sent to an available, randomly selected, service instance. If you need to specify a specific instance you can simply address a service using its unique service ID. This is shown in thetomessage field below.

let message = hydra.createUMFMessage({
  to: 'cef54f47984626c9efbf070c50bfad1b@test-service:/',
  from: 'blue-service:/',
  body: {
    fileData: '{base64}'
  }
});
hydra.sendMessage(message);

You can obtain a service's unique ID via thegetInstanceID()orgetServicePresence()methods.

If you need too, you can use thesendBroadcastMessagemethod to send a message to ALL the available instances of a service.

Warning: Although, you can usesendMessageto send and respond to messages - it's recommended that you usesendReplyMessagewhen replying. The reason for this is that sendReplyMessage uses the source message to properly fill out UMF fields required for robust messaging. This includes things like using the source mid, for, to, from UMF fields to formulate a reply message.

Your service can receive messages by adding a listener to your loaded hydra instance. The example below demonstrates how to also formulate a response if necessary.

hydra.registerService();
hydra.on('message', function(message) {
  // message will be a UMF formatted object
  console.log(`Received object message: ${msg.mid}: ${JSON.stringify(msg)}`);

  // to send a reply message here or elsewhere in your service use the `sendReplyMessage` call.
  hydra.sendReplyMessage(message, hydra.createUMFMessage({
    body: {
      // response items
    }
  }));
});

UMF messaging

In the prior example, we used a UMF style message, which is created by the HydracreateUMFMessagemethod. UMF is an acronym for Universal Message Format and is a light-weight messaging protocol designed for routable and queue-able messaging.

UMF allows you to optionally specify that a message should be sent to one service which in turn should send the message and/or additional results to another service. In this way, processes can be chained across services.

Let's demystify UMF a bit by looking at what thecreateUMFMessageactually does.

First, the method accepts a message object. In that object three fields are required:

{
  "to":'serviceName',
  "from": 'sending-entity-name',
  "body": {}
}

The createUMFMessage method takes that object and returns a new one with additional fields:

{
  "mid": "02d7e85b-5609-4179-b3af-fee60efc8ef0",
  "timestamp": "2016-03-28T15:40:05.820Z",
  "version": "UMF/1.2",
  "priority": "normal",
  "type": "msg",
  "to": "filewatcher",
  "from": "hydramcp",
  "body": {
    "actions": [
      "restart",
      "processBatch"
    ]
  }
}

The additional fields are defined by the UMF specification and aid Hydra, and other distributed systems in the handling of messages.

ThecreateUMFMessagehelper method helps ensure that we're starting with a properly formatted UMF compatible message which we can further extend.

For example, here we can change thepriorityandtypeof the message before passing it along to themakeAPIRequestmethod.

message.priority = 'high';
message.type = 'service:control';

It's important to note that we could have added thepriorityandtypefields to our original message that was passed tocreateUMFMessage. The method will use your supplied fields to overwrite the ones it creates by default. So it's important to not overwritemidortimestampin careless ways.

Note: For a detailed look at the UMF spec, visit:Universal Messaging Format

results matching ""

    No results matching ""