Service Discovery

So, we have a nice service-oriented broker, but we have no way of knowing whether a particular service is available or not. We know when a request fails, but we don’t know why. It would be useful to be able to ask the broker questions like, “Is the echo service running?” The most obvious way to implement this would be to modify our MDP/Client protocol to add commands to ask such questions. But MDP/Client has the great charm of being simple. Adding service discovery to it would make it as complex as the MDP/Worker protocol.

Another option is to do what email servers do, and ask that undeliverable requests be returned. This can work well in an asynchronous world, but it also adds complexity. We need ways to distinguish returned requests from replies and to handle these properly.

Let’s try to use what we’ve already built, building on top of MDP instead of modifying it. Service discovery is, itself, a service. It might indeed be one of several management services, such as “disable service X,” “provide statistics,” and so on. What we want is a general, extensible solution that doesn’t affect the protocol or existing applications.

There’s a small RFC that layers this on top of MDP: the Majordomo Management Interface (MMI). We already implemented it in the broker, though unless you read the whole thing you probably missed that. I’ll explain how it works in the broker:

  • When a client requests a service that starts with mmi., instead of routing this request to a worker, we handle it internally.

  • We handle just one service in our broker, which is mmi.service, the service discovery service.

  • The payload for the request is the name of an external service (a real one, provided by a worker).

  • The broker returns “200” (OK) or “404” (Not found), depending on whether there are workers registered for that service or not.

Example 4-52 shows how we use the service discovery in an application.

Example 4-52. Service discovery over Majordomo (mmiecho.c)

//
//  MMI echo query example
//

//  Lets us build this source without creating a library
#include "mdcliapi.c"

int main (int argc, char *argv [])
{
    int verbose = (argc > 1 && streq (argv [1], "-v"));
    mdcli_t *session = mdcli_new ("tcp://localhost:5555", verbose);

    //  This is the service we want to look up
    zmsg_t *request = zmsg_new ();
    zmsg_addstr (request, "echo");

    //  This is the service to which we send our request
    zmsg_t *reply = mdcli_send (session, "mmi.service", &request);

    if (reply) {
        char *reply_code = zframe_strdup (zmsg_first (reply));
        printf ("Lookup echo service: %s\n", reply_code);
        free (reply_code);
        zmsg_destroy (&reply);
    }
    else
        printf ("E: no response from broker, make sure it's running\n");

    mdcli_destroy (&session);
    return 0;
}

Try this with and without a worker running, and you should see the little program report “200” or “404” accordingly.

The implementation of MMI in our example broker is flimsy. For example, if a worker disappears, services remain “present.” In practice, a broker should remove services that have no workers after some configurable timeout.

Get ZeroMQ now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.