Vert.x AMQP Service allows AMQP 1.0 applications and Vert.x applications to communicate with each other by acting as a router+bridge which,

  • Routes between the AMQP and Vert.x address spaces.

  • Translates between the message formats.

It facilitates reliable communication via message passing, while maintaining QoS by allowing control of the message flow in both directions.

Supported interaction patterns include request-reply and publish-subscribe.

vertx amqp

Key Features:

  • Expose Vert.x Services to AMQP client applications.

  • Expose AMQP Services to Vert.x client applications.

  • Static and dynamic configuration of routes between the two address spaces.

  • Allow different levels of reliability [unreliable (default) | at-least-once].

  • Facilitate flow control (in both directions) to maintain Quality of Service.

  • Management & Statistics(via AMQP 1.0 management protocol & hawt.io pluging - future release).

Prerequisites.

This documentation assumes that you are familiar with Vert.x, basic messaging concepts & AMQP 1.0 concepts. The AMQP examples require Apache QPid Proton installed.

Deploying AMQP Service.

The first step is to deploy the AMQP Service (bridge) as a standalone service or programmatically.

Deploy it as a standalone service

Assuming the Vert.x AMQP Service jar and it’s dependencies are located within the lib directory of the vert.x installation

vertx run service:io.vertx.vertx-amqp-service -cluster
Important

If you run it standalone, you need to make sure the cluster option is used. Please refer to the main vert.x manual on how to configure clustering.

Deploy it programmatically

JsonObject config = new JsonObject().put("amqp.inbound-host", "10.10.52.86");
config.put("amqp.inbound-port", 5672);
DeploymentOptions options = new DeploymentOptions().setConfig(config);

vertx.deployVerticle("service:io.vertx.vertx-amqp-service", options, res -> {
    if (res.succeeded())
    {
        // Deployed ok
    }
    else
    {
        // Failed to deploy
    }
});

Running your first example

Lets start with a simple request-reply example involving a Vert.x app and an AMQP app. We will first run the examples before going through the concepts and the code.

AMQP Client → Vert.x Service

vertx service amqp client
  • Step 1. Start the Vert.x-AMQP-Service.

vertx run service:io.vertx.vertx-amqp-service -cluster
Important

Wait until you see the following message before you proceed with Step 2.

AmqpService is now available via the address : vertx.service-amqp
Succeeded in deploying verticle
  • Step 2. Run the HelloServiceVerticle as follows.
    The above class is located in src/examples/request-reply/java folder within the source tree.

vertx run HelloServiceVerticle.java -cluster
Important

Wait until you see the following message before you proceed with Step 3.

Succeeded in deploying verticle
  • Step 3. Run the AMQP Client as follows.

  • You need Apache QPid Proton installed and the PYTHON_PATH set properly before executing the AMQP examples. See Running the AMQP examples. for more information.

  • The scripts are located under src/amqp-examples.

  • Use -h or --help to get list of all options.

./client.py

If you plan to use a 3rd party intermediary for setting up the reply-to destination.

./client.py --response_addr <ip>:<port>/<dest-name>

How it all works

  • If you take a closer look at the AMQP client and the Vert.x Service you would see that it is no different from an ordinary AMQP app or Vert.x app. i.e no extra code is required on either side for basic communication

  • The AMQP Client creates a request message with a reply-to address set and sends to the Vert.x-AMQP-Service.

self.sender = event.container.create_sender(self.service_addr)
...
event.sender.send(Message(reply_to=self.reply_to, body=request));
  • The Vert.x-AMQP-Service then translates the message into the json format and puts it into the Vert.x event-bus

  • By default the AMQP Target is used as the event-bus address. You could configure a different mapping. See Configuring Vert.x AMQP Service. for more details.

  • The Vert.x Service (HelloServiceVerticle) listens on this address and receives this message.

vertx.eventBus().consumer("hello-service-vertx", this);
  • Once received, it prepares the response (in this case appends hello to the request msg and uppercase the string) and replies on the message.

  • The reply is received by the Vert.x-AMQP-Service which then forwards it to the AMQP client.

Vert.x Client → AMQP Service

amqp service vertx client
  • Step 1. Start the Vert.x-AMQP-Service.

    • Start the Vert.x AMQP Service with the correct configuration. For this example some config is required.

    • The config required for this example is located in src/examples/request-reply folder within the source tree.

vertx run service:io.vertx.vertx-amqp-service -conf ./request-reply.json -cluster
Important

Wait until you see the following message before you proceed with Step 2.

AmqpService is now available via the address : vertx.service-amqp
Succeeded in deploying verticle
  • Step 2. Run the AMQP Service as follows.

  • You need Apache QPid Proton installed and the PYTHON_PATH set properly before executing the AMQP examples. See Running the AMQP examples. for more information.

  • The scripts are located under src/amqp-examples.

  • Use -h or --help to get list of all options.

./hello-service.py
  • Step 3. Run the ClientVerticle as follows.
    The above class is located in src/examples/request-reply/java folder within the source tree.

vertx run ClientVerticle.java -cluster

How it all works

  • If you take a closer look at the AMQP Service and the Vert.x Client you would see that it is no different from an ordinary AMQP app or Vert.x app. i.e no extra code is required on either side for basic communication. A little bit of configuration is required though.

  • The Vert.x clients creates a request message and sends it to the Vert.x event-bus using 'hello-service-amqp' as the address. It also registers a reply-to handler.

JsonObject requestMsg = new JsonObject();
requestMsg.put("body", "rajith muditha attapattu");
vertx.eventBus().send("hello-service-amqp", requestMsg, this);
  • The Vert.x-AMQP-Service is configured to listen on the Vert.x event-bus for any messages sent to 'hello-service-amqp' and then forward it to the correct AMQP endpoint.
    The reply-to address in the AMQP message is set to point to the Vert.x-AMQP-Service and it keeps a mapping to the Vert.x reply-to.

"vertx.handlers" : ["hello-service-amqp"]
"vertx.routing-outbound" : {
           "routes" :{
                    "hello-service-amqp" : "amqp://localhost:5672/hello-service-amqp"
                     }

        }
  • The AMQP Service receives the request, appends hello, upper case the string and sends it to reply-to address.

sender = self.container.create_sender(event.message.reply_to)
greeting = 'HELLO ' + request.upper()
delivery = sender.send(Message(body=unicode(greeting)))
  • The Vert.x-AMQP-Service which receives the response, looks up the mapping and forwards it to the ClientVerticle via the event-bus.

How routing works

The Vert.x-AMQP-Service acts as a router between the AMQP and Vert.x space. This section provides insight into how the routing works and how it can be configured at deploy time and runtime.

Inbound Routing

When a message is received by the Vert.x-AMQP-Service from an AMQP peer

  • It checks to see if the Vert.x-AMQP-Service knows about the 'incoming AMQP link' associated with the message.

  • If it has an association to a Vert.x address, the message will be forwarded to this Vert.x address via the event bus.
    These associations are created,

  • If there is no known association, it will use the chosen message-property to lookup the routing table. (see Configuring Vert.x AMQP Service.)

  • If the value of that message-property matches a Vert.x address, the message will be forwarded to that address via the event-bus.

  • If there is no match the message will be sent on the event-bus using one of the following.

    • If a default-inbound-address (a.k.a dead-letter address) is specified (via 'vertx.default-inbound-address'), it will be sent to that address.

    • If no default address is specified, it will use the 'target' field for the given link as the address.

Outbound Routing

When a message is received by the Vert.x-AMQP-Service from a Verticle via the event-bus

  • It checks if the Vert.x address the message was sent to, have a known association with an 'outgoing AMQP link'.

  • If such an association is found, the message will be dispatched via that AMQP link.
    These associations are created,

  • If no such association is found, it looks for a message-property in the following order and use the value of it to look up the routing table.

    1. If 'vertx.routing-key' is specified it will use the value of it as the lookup key (overrides everything below).

    2. If not specified & a custom property is specified via routing-property-type=CUSTOM & routing-property-name=<property-name>. It will look for it in the following order,

      1. Look for that property as a top-level property within the json message.

      2. Look for that property within the 'properties' section within the json message.

      3. Look for that property within the 'application-properties' section within the json message.

    3. If not specified it will simply use the Vert.x address the message was sent to as the lookup key.

  • If the routing table has no matching entry, it will send the message to the default outbound address (dead-letter queue) configured via 'amqp.default-outbound-address'.

Configuring Vert.x AMQP Service.

Static configuration is specified via a json file at deployment time. Please check the examples above for sample configuration files.

Note

Please note all configuration is optional.

Table 1. Config Options
Option Default Description

address

vertx.service-amqp

The address for sending messages (method calls) to the Vert.x AMQP Service

amqp.inbound-host

localhost

Specifies the host ip for inbound AMQP connections.

amqp.inbound-port

5673

Specifies the port for inbound AMQP connections

amqp.default-outbound-address

amqp://localhost:5672/vertx

dead-letter-queue for unmatched outbound message.

vertx.default-handler-address

vertx.service-amqp.bridge

The default address for sending messages (content) to the Vert.x AMQP Service to be routed into the AMQP space.

vertx.handlers

[]

A list of additional Vert.x event-bus addresses the AMQP Service should listen on.

vertx.default-inbound-address

NULL

dead-letter-address for unmatched inbound message.

vertx.routing-outbound

{}

A map configuring outbound routing, including routes. See 'Table 2. vertx.routing-outbound'.

vertx.routing-inbound

{}

Table 2. vertx.routing-outbound
Option Default Description

routing-property-name

Vert.x event-bus address

If specified the router will look for that property within the outbound JSON message in the following order.

1. As a top-level property.
2. If a 'properties' map is specified, within that map.
3. If an 'application_properties' map is specified, within that map.

routes

{}

A map containing entries that map a 'routing-key' (as extracted above) to an AMQP endpoint address. See # <1>

<1> Outbound routes example.
"routes" :{
             "hello-service-amqp" : "amqp://localhost:5672/hello-service-amqp"
             "fortune-cookie-service" :  "amqp://localhost:7772/fortune-cookie-service"
           }
Table 3. vertx.routing-inbound
Option Default Description

routing-property-type

ADDRESS

One of [ADDRESS, SUBJECT, CUSTOM].

If CUSTOM is selected, then you need to specify 'routing-property-name'

routing-property-name

mandatory

Looks for this property within the Application Properties in an AMQP message.

routes

{}

A map containing entries that map a 'routing-key' (as extracted above) to an a Vert.x address. See # <2>

<2> Inbound routes example.
"routes" :{
            "amqp://localhost:5673/foo.*" : "foo-all",
            "amqp://localhost:5673/foo.bar*" : "foo-bar"
          }

AmqpService Interface

The AmqpService interface allows a Vert.x application to interact with the Vert.x-AMQP-Service (bridge) and leverage some of the important features of AMQP. Please refer to the API documentation for more information.

AmqpService access via Proxy.

AmqpService service = AmqpService.createEventBusProxy(vertx, "vertx.service-amqp");
AmqpService service = AmqpService.createEventBusProxy(vertx, "vertx.service-amqp");
OutgoingLinkOptions options = new OutgoingLinkOptions();
options.setReliability(ReliabilityMode.AT_LEAST_ONCE); (4)
service.establishOutgoingLink("amqp://localhost:6672/my-queue", (1)
        "my-pub-queue", (2)
        "my-pub-notifications", (3)
        options, (4)
        result -> {
            if (result.succeeded())
            {
                outgoingLinkRef = result.result(); (5)
                // Link successfully established.
            }
            else
            {
                // handle error
            }
        });

//.....

service.cancelOutgoingLink(outgoingLinkRef, result->{}); (6)
  1. The AMQP Endpoint address to which you want to send messages.

  2. The event-bus address which would be mapped to the above link. The Verticle would be sending messages to this event-bus address.

  3. The event-bus address to which notifications about the incoming link is sent. Ex. Errors, Delivery Status, credit availability. The application should register a handler with the event-bus to receive these updates.

  4. Uses the options object to specify the desired level of reliability. Default is UNRELIABLE.

  5. The AsyncResult contains a ref (string) to the mapping created. This is required when changing behavior or canceling the link and it' association.

  6. The outgoing link is closed and the mapping btw it and the event-bus address is removed.

AmqpService service = AmqpService.createEventBusProxy(vertx, "vertx.service-amqp");
IncomingLinkOptions options = new IncomingLinkOptions();
options.setReliability(ReliabilityMode.AT_LEAST_ONCE); (4)
options.setPrefetch(10); (5)
service.establishIncomingLink("amqp://localhost:6672/my-queue", (1)
        "my-sub-queue",  (2)
        "my-sub-notifications", (3)
        options,
        result -> {
            if (result.succeeded())
            {
                incomingLinkRef = result.result(); (6)
            }
            else
            {
                //handle error
            }
        });

//.....

service.cancelIncomingLink(incomingLinkRef, result->{}); (7)
  1. The AMQP Endpoint address from which you want to receive messages (subscription).

  2. The event-bus address which would be mapped to the above link. The Verticle would be reiving messages via this event-bus address.

  3. The event-bus address to which notifications about the incoming link is sent. Ex. Errors. The application should register a handler with the event-bus to receive these updates.

  4. Uses the options object to specify the desired level of reliability. Default is UNRELIABLE.

  5. The amount of messages to prefetch. Defaults to "1".
    If set to a value > 0, the Vert.x-AMQP-Service will automatically fetch more messages when a certain number of messages are marked as either accepted, rejected or released. The Vert.x-AMQP-Service will determine the optimum threshold for when the fetch happens and how much to fetch.
    If set to "0", the vert.x application will need to explicitly request messages using AmqpService#fetch(String, int, io.vertx.core.Handler).

  6. The AsyncResult contains a ref (string) to the mapping created. This is required when changing behavior or canceling the link and it' association.

  7. The incoming link is closed and the mapping btw it and the event-bus address is removed.

Sending Messages

Sending a message reliably.

Messages are sent asynchronously and delivery confirmations are sent to the notification address.

JsonObject msg = new JsonObject();
msg.put("body", "rajith");
String msgRef = "msg-ref".concat(String.valueOf(counter++));
msg.put(AmqpService.OUTGOING_MSG_REF, msgRef); (1)
vertx.eventBus().publish("my-pub-queue", msg); (2)

// ....

vertx.eventBus().<JsonObject>consumer("my-pub-notifications", noticeMsg -> { (3)
    NotificationType type = NotificationHelper.getType(noticeMsg.body()); (4)
    if (type == NotificationType.DELIVERY_STATE)
    {
        DeliveryTracker tracker = NotificationHelper.getDeliveryTracker(noticeMsg.body());
        System.out.println("Delivery State : " + tracker.getMessageRef());  (1)
        System.out.println("Delivery State : " + tracker.getDeliveryState()); (5)
        System.out.println("Message State : " + tracker.getMessageState());   (6)
    }
});
  1. Set a unique reference. The application then uses this ref to correlate a delivery confirmation to a sent message.

  2. Sending the message via the event-bus.

  3. Subscribing to the event-bus to receive notifications.

  4. Use NotificationHelper class to parse the notification message.

  5. Retrieve the delivery state. Whether it’s SETTLED, or in doubt (UNKNOWN, LINK_FAILURE) due to some error.

  6. Retrieve the message state. One of ACCEPTED, REJECTED or RELEASED.

Respecting flow control when sending.

This allows the receiving application (AMQP app) to be in control of many message it can receive at any given time.

vertx.eventBus().<JsonObject>consumer("my-pub-notifications", msg -> { (1)
    NotificationType type = NotificationHelper.getType(msg.body()); (2)
    if (type == NotificationType.LINK_CREDIT)
    {
        int msgsWeCanSend = NotificationHelper.getCredits(msg.body()); (3)
    }
});
  1. Subscribing to the event-bus to receive notifications.

  2. Use NotificationHelper class to parse the notification message.

  3. Use NotificationHelper.getCredits() method to retrieve the credits given by the receiving app.

Setting AMQP message properties when sending.

JsonObject msg = new JsonObject();
msg.put("body", "rajith"); (1)

JsonObject properties = new JsonObject();
msg.put("properties", properties); (2)
properties.put("subject", "<message-subject>"); (3)
properties.put("reply-to", "<reply-to-address>"); (4)
properties.put("message_id", "<message_id>"); (5)
properties.put("correlation_id", "<correlation_id>"); (6)

JsonObject appProps = new JsonObject();
msg.put("application-properties", appProps); (7)
appProps.put("key_1", "val_1"); (8)
appProps.put("key_n", "val_n"); (8)
  1. Use "body" to set the message content.

  2. The message-translator will look for "properties" and inspect it to look for the items below that will be mapped to fields in AMQP Properties.

  3. The "subject" will be mapped AMQP Property subject.

  4. The "reply-to" will be mapped AMQP Property reply-to.

  5. The "message-id" will be mapped AMQP Property message-id.

  6. The "correlation-id" will be mapped AMQP Property correlation-id.

  7. The message-translator will look for "application-properties" and copy all the contents into the AMQP application-properties.

  8. Application defined Key-Value pairs, that will be copied into AMQP application-properties.

Receiving Messages

Fetching messages explicitly when prefetch is disabled.

service.fetch(incomingLinkRef, (1)
        10, (2)
        result -> {
            if (result.succeeded())
            {
                // operation successfull.
            }
            else
            {
                //handle error
            }
        });
  1. The link reference obtain when setting up the link.

  2. The number of messages to fetch.

Receiving messages reliably.

service.accept(msg.getString(AmqpService.INCOMING_MSG_REF), result -> { (1)
    if (result.failed())
    {
        // handle error
    }
});
  1. Accepting the message by passing the 'INCOMING_MSG_REF' The Vert.x-AMQP-Service uses this ref to lookup the correct AMQP message and accepts it.
    Simillary you could reject & release messages.

Retrieving AMQP message properties when receiving.

JsonObject msg = new JsonObject();
msg.getJsonObject("body"); (1)

JsonObject properties = msg.getJsonObject("properties"); (2)
if (properties != null)
{
    properties.getString("subject", "<message-subject>"); (3)
    properties.getString("reply-to", "<reply-to-address>"); (4)
    properties.getString("message_id", "<message_id>"); (5)
    properties.getString("correlation_id", "<correlation_id>"); (6)
}

JsonObject appProps = msg.getJsonObject("application-properties"); (7)
if (appProps != null)
{
    // retrieve key value pairs.
}
  1. Use "body" to get the message content.

  2. The message-translator will retieve fields in AMQP Properties to place it under "properties" section of the json message as stated below

  3. The AMQP Property subject will be mapped to "subject".

  4. The AMQP Property reply-to will be mapped to "reply-to".

  5. The AMQP Property message-id will be mapped to "message-id".

  6. The AMQP Property correlation-id will be mapped "correlation-id".

  7. The message-translator will copy any entries within AMQP application-properties into "application-properties" section of the json message.

Exposing a Vert.x Service via AMQP.

The first example we looked at exposed a Vert.x service by simply mapping an event-bus address to an AMQP endpoint. The AMQP endpoint was managed by the Vert.x-AMQP-Service (bridge) and forwarded any requests to the Vert.x event-bus address.

However the communication was unreliable and flow control was not within the explicit control of the Vert.x application. The focus there was simplicity and no AMQP specifc interface or code was used.

Lets now look at how a service could register with the Vert.x-AMQP-Service to gain more control on how it want to interact with AMQP clients.

Registering a Service.

AmqpService service = AmqpService.createEventBusProxy(vertx, "vertx.service-amqp");
ServiceOptions options = new ServiceOptions();
options.setInitialCapacity(1); (3)
service.registerService(
        "fortune-cookie-service", (1)
        "notice-address", (2)
        options, (3)
        result -> {
            if (result.succeeded())
            {
                // Service was registered successfully.
            }
            else
            {
                // handle error
            }
        });

//.....

service.unregisterService("fortune-cookie-service", result -> {
    if (result.failed())
    {
        // error
    }
});
  1. The event-bus address used when registering the service. The service will be listening on this address via the event-bus for requests.

  2. Notification address to receive various notifications, including errors.

  3. Sets the initial capacity (no of requests allowed) for a new client wanting to use the service. The default is '0', which means the service needs to explicity grant credits via the "issueCredits" methods (see below) for a client to be able send requests.

  4. De-registering the service from Vert.x-AMQP-Service.

Managing clients

This sections shows you how to, * Identify a client uniquely * How to control the flow of requests by managing request credits.

vertx.eventBus().<JsonObject>consumer("notice-address", msg -> { (1)
    NotificationType type = NotificationHelper.getType(msg.body()); (2)
    if (type == NotificationType.INCOMING_LINK_OPENED)
    {
        String linkRef = NotificationHelper.getLinkRef(msg.body()); (3)
        service.issueCredits(linkRef, 1, result -> {   (4)
        });
    }
});
  1. Subscribing to the event-bus to receive notifications.

  2. Use NotificationHelper class to parse the notification message.

  3. Use NotificationHelper.getLinkRef() method to retrieve the link-ref that uniquely identifies the client.

  4. Use service.issueCredits(<link-ref>, <request-credits>) to allow the client to send a request(s). In this example, the Verticle issues an initial request credit when a new link (client) is opened. Subsequently you could use service.issueCredits(<link-ref>, <request-credits>) to issue further credits any time the Verticle (Vert.x Service) deems necessary.

Manage Routes

The following examples show how the routing tables can be manipulated at runtime via the AmqpService interface. For more info on how routing works, see How routing works

AmqpService service = AmqpService.createEventBusProxy(vertx, "vertx.service-amqp");
service.addInboundRoute("weather.us.*", "us-weather"); (1)
service.addInboundRoute("weather.us.bos.*", "bos-weather"); (1)

service.removeInboundRoute("weather.us.bos.*", "bos-weather"); (2)

service.addOutboundRoute("news.*", "amqp://localhost:5672/all-news"); (3)
service.addOutboundRoute("news.ca.*", "amqp://localhost:5672/can-news"); (3)

service.removeOutboundRoute("news.ca.*", "amqp://localhost:5672/can-news"); (4)
  1. Adds an entry to to the incoming routing table. The pattern is applied to the extracted routing-key and if matched, will be fowarded to the given Vert.x event-bus addresses.

  2. Removes the entry from the incoming routing table.

  3. Adds an entry to to the outgoing routing table. The pattern is applied to the extracted routing-key and if matched, will be fowarded to the given AMQP addresses.

  4. Removes the entry from the outgoing routing table.

Putting it all together.

Lets look at an example that puts the above concepts into use.

  • We will look at how the Vert.x app FortuneCookie-Service is able to service several AMQP Clients in a reliable manner, while being in control of the message flow at all times. This prevents the service from being overwhelmed with requests.

  • Next we look at how Vert.x client apps could access the AMQP app FortuneCookie-Service in a reliable manner, while respecting the flow control requirements imposed by the AMQP Service.

The diagram below describes the interaction pattern for both examples.

example1

AMQP Client → Vert.x Service

  • Step 1. Start the Vert.x-AMQP-Service.

vertx run service:io.vertx.vertx-amqp-service -cluster
Important

Wait until you see the following message before you proceed with Step 2.

AmqpService is now available via the address : vertx.service-amqp
Succeeded in deploying verticle
  • Step 2. Run the FortuneCookieServiceVerticle as follows.
    The above class is located in src/examples/fortunecookie/java folder within the source tree.

vertx run FortuneCookieServiceVerticle.java -cluster
Important

Wait until you see the following message before you proceed with Step 3.

Succeeded in deploying verticle
  • Step 3. Run the AMQP Client as follows.

  • You need Apache QPid Proton installed and the PYTHON_PATH set properly before executing the AMQP examples. See Running the AMQP examples. for more information.

  • The scripts are located under src/amqp-examples.

  • Use -h or --help to get list of all options.

./fortune-cookie-client.py

You could start additional clients and observe that the Vert.x service is in control at all times without being overwhelmed by additional clients.

Vert.x Client → AMQP Service

  • Step 1. Start the Vert.x-AMQP-Service.

vertx run service:io.vertx.vertx-amqp-service -cluster
Important

Wait until you see the following message before you proceed with Step 2.

AmqpService is now available via the address : vertx.service-amqp
Succeeded in deploying verticle
  • Step 3. Run the AMQP FortuneCookie Service as follows.

  • You need Apache QPid Proton installed and the PYTHON_PATH set properly before executing the AMQP examples. See Running the AMQP examples. for more information.

  • The scripts are located under src/amqp-examples.

  • Use -h or --help to get list of all options.

./fortune-cookie-service.py
  • Step 4. Run the FortuneCookieClientVerticle as follows.
    The above class is located in src/examples/fortunecookie/java folder within the source tree.

vertx run FortuneCookieClientVerticle.java -cluster

You could start additional clients (Verticles) and observe that the AMQP service is in control at all times without being overwhelmed by additional clients.

Running the AMQP examples.

The AMQP examples require Apache QPid Proton installed.

  • Setting up the env For ease of use, the AMQP examples are written using the Proton Python API. Use the links below to setup the environment.

  • Apache QPid Proton Install

  • Python Tutorial

  • Using a 3rd party AMQP intermediary The examples are using the Vert.x-AMQP-Service (bridge) as an intermediary when required. Ex. for setting up a temp destination for replies. But you could use a 3rd part AMQP service just as well. (Ex. Message Broker or Router)