Skip to content

New feature tutorial and sample for Message Replay #45

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion NOTICE
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
This product includes software originally developed by Solace Corporation
Copyright 2016-2017 Solace Corporation
Copyright 2016-2019 Solace Corporation
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ This repository contains:
- [Event Monitor](https://github.com/SolaceSamples/solace-samples-javascript/tree/master/src/features/EventMonitor): Learn how to monitor message router generated events.
- [GuaranteedRequestor/Replier](https://github.com/SolaceSamples/solace-samples-javascript/tree/master/src/features): Learn how to set up guaranteed request/reply messaging.
- [NoLocal Pub-Sub](https://github.com/SolaceSamples/solace-samples-javascript/tree/master/src/features/NoLocalPubSub): Learn how to prevent messages published on a session or consumer received on that same session or consumer.
- [Message Replay](https://github.com/SolaceSamples/solace-samples-javascript/tree/master/src/features/MessageReplay): Learn how to initiate and process the replay of previously published messages, as well as deal with an externally initiated replay.

## Checking out

Expand Down
12 changes: 9 additions & 3 deletions _config.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Site settings
title: Solace Samples Javascript
title: Solace Samples JavaScript
summary: These tutorials get you up to speed sending and receiving messages with Solace technology.
baseurl: "/solace-samples-javascript"
repository: https://github.com/SolaceSamples/solace-samples-javascript
Expand All @@ -8,15 +8,21 @@ repository: https://github.com/SolaceSamples/solace-samples-javascript

# Links
advanced-samples: //github.com/SolaceSamples/solace-samples-javascript/tree/master/src/advanced-samples
links-community: //dev.solace.com/community/
links-downloads: //dev.solace.com/downloads/
links-community: //dev.solace.com/community/
links-get-started-javascript: //dev.solace.com/get-started/javascript-tutorials/
links-solaceCloud-setup: //cloud.solace.com/create-messaging-service/
links-tech-other: //dev.solace.com/tech/#other
links-solaceCloud-setup: //cloud.solace.com/create-messaging-service/
docs-core-concepts: //docs.solace.com/Features/Core-Concepts.htm
docs-session-events: //docs.solace.com/Solace-Messaging-APIs/Creating-Client-Sessions-1.htm#Handle-Sess-Events
docs-api-reference: //docs.solace.com/API-Developer-Online-Ref-Documentation/js/index.html
docs-semp: //docs.solace.com/SEMP/Using-SEMP-to-Manage-and-Monitor-Routers.htm
docs-topic-mapping: //docs.solace.com/Features/Core-Concepts.htm#topic-queue-mapping
docs-dte: //docs.solace.com/Features/Endpoints.htm
docs-active-flow-indication: //docs.solace.com/Solace-PubSub-Messaging-APIs/Developer-Guide/Creating-Flows.htm#Active-Flow-Indication
docs-psplus-manager: //docs.solace.com/Solace-PubSub-Manager/PubSub-Manager-Overview.htm
docs-semp-api: //docs.solace.com/SEMP/Using-SEMP.htm
docs-endpoints: //docs.solace.com/Messaging-Basics/Endpoints.htm#Endpoints
docs-api-errorresponse-subcode-ex: //docs.solace.com/API-Developer-Online-Ref-Documentation/js/solace.ErrorSubcode.html
docs-replay-use-cases: //docs.solace.com/Features/Message-Replay.htm#Applicat
docs-replay-cli-config: //docs.solace.com/Configuring-and-Managing/Msg-Replay-Config.htm
Binary file added _docs/assets/images/config-replay-log.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _docs/assets/images/initiate-replay.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
180 changes: 180 additions & 0 deletions _docs/feature_MessageReplay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
---
layout: features
title: Message Replay
summary: Learn how to make use of Message Replay via the Solace JavaScript client library
links:
- label: MessageReplay.html
link: /blob/master/src/features/MessageReplay/MessageReplay.html
- label: MessageReplay.js
link: /blob/master/src/features/MessageReplay/MessageReplay.js
---

In this introduction we show you how a client can initiate and process the replay of previously published messages, as well as deal with an externally initiated replay.

## Feature Overview

During normal publishing, guaranteed messages will be removed from the message broker's [queue or topic endpoint]({{ site.docs-endpoints }}) once the consumer acknowledges their receipt or successful processing. When Message Replay is initiated for an endpoint, the message broker will re-publish a requested subset of previously published and logged messages, which enables the client to process these messages again.

Message Replay can be used if a client needs to catch up with missed messages as well as for several other [use cases]({{ site.docs-replay-use-cases }}).

Message Replay for an endpoint can be initiated programmatically from an API client connected to an exclusive endpoint, or administratively from the message broker. After the replay is done, the connected client will keep getting live messages delivered.

It's important to note that when initiating replay, the message broker will disconnect all connected client flows, active or not. A new flow needs to be started for a client wishing to receive replayed and subsequent messages. The only exception is that in the client initiated case the flow initiating the replay will not be disconnected.

## Prerequisite

A replay log must be created on the message broker for the Message VPN using [Message Replay CLI configuration]({{ site.docs-replay-cli-config }}) or using [Solace PubSub+ Manager]({{ site.docs-psplus-manager }}) administration console. Another option for configuration is to use the [SEMP API]({{ site.docs-semp-api }}).

NOTE: Message Replay is supported on Solace PubSub+ 3530 and 3560 appliances running release 9.1 and greater, and on the Solace PubSub+ software message broker running release 9.1 and greater. Solace JavaScript API version 10.2.1 or later is required.

![alt text]({{ site.baseurl }}/assets/images/config-replay-log.png "Configuring Replay Log using Solace PubSub+ Manager")
<br>

## Code

### Checking for Message Replay capability

Message Replay must be supported on the message broker, so this should be the first thing the code checks:

```javascript
if (!consumer.session.isCapable(solace.CapabilityType.MESSAGE_REPLAY)) {
consumer.log('Message Replay is not supported on this message broker, disconnecting...');
try {
consumer.session.disconnect();
} catch (error) {
consumer.log(error.toString());
}
}
```

### Initiating replay

First, a `replayStartLocation` object needs to be created to specify the desired subset of messages in the replay log.

There are two options:
* use `createReplayStartLocationBeginning()` to replay all logged messages
* use `createReplayStartLocationDate(Date date)` to replay all logged messages received starting from a specified `date`. Note the different possible formats in the example including how to specify the time zone.

Note: The `date` can’t be earlier than the date the replay log was created, otherwise replay will fail.

```javascript
consumer.replayStartLocation = solace.SolclientFactory.createReplayStartLocationBeginning();
/***************************************************************
* Alternative replay start specifications to try instead of
* createReplayStartLocationBeginning().
*/
/* Milliseconds after the Jan 1st of 1970 UTC+0: */
// consumer.replayStartLocation = solace.SolclientFactory.createReplayStartLocationDate(
// new Date(1554331492));

/* RFC3339 UTC date with timezone offset 0: */
// consumer.replayStartLocation = solace.SolclientFactory.createReplayStartLocationDate(
// new Date(Date.parse('2019-04-03T18:48:00Z')));

/* RFC3339 date with timezone: */
// consumer.replayStartLocation = solace.SolclientFactory.createReplayStartLocationDate(
// new Date(Date.parse('2019-04-03T18:48:00-05:00')));
```

Indicate that replay is requested by setting a non-null `replayStartLocation` in `solace.MessageConsumerProperties`, which is then passed to `createMessageConsumer()` as a parameter.

The target endpoint (`queueDescriptor`) for replay is also set in `ConsumerFlowProperties` below, which is the normal way of setting an endpoint for a consumer flow.

```javascript
consumer.replayStartLocation = solace.SolclientFactory.createReplayStartLocationBeginning();
:
// Create a message consumer
consumer.messageConsumer = consumer.session.createMessageConsumer({
// solace.MessageConsumerProperties
queueDescriptor: { name: consumer.queueName, type: solace.QueueType.QUEUE },
acknowledgeMode: solace.MessageConsumerAcknowledgeMode.CLIENT, // Enabling Client ack
replayStartLocation: consumer.replayStartLocation,
});
:
consumer.messageConsumer.connect();
```

### Replay-related events

If a replay-related event occurs, the consumer flow is disconnected and a `solace.MessageConsumerEventName.DOWN_ERROR` event is generated with a specific Subcode, which can be processed in an event handler.

Some of the important Subcodes:
* REPLAY_STARTED - a replay has been administratively started from the message broker; the consumer flow is being disconnected.
* REPLAY_START_TIME_NOT_AVAILABLE - the requested replay start date is before when the replay log was created or in the future, which is not allowed
* REPLAY_FAILED - indicates that an unexpected error has happened during replay

For the definition of additional replay-related Subcodes refer to `solace.ErrorSubcode` in the [JavaScript API Reference]({{ site.docs-api-errorresponse-subcode-ex }}) (search for REPLAY).

Here we will define the event handler to process events with some more example Subcodes.

```javascript
consumer.messageConsumer.on(solace.MessageConsumerEventName.DOWN_ERROR, function (details) {
consumer.consuming = false;
consumer.log('Received "DOWN_ERROR" event - details: ' + details);
switch(details.subcode) {
case solace.ErrorSubcode.REPLAY_STARTED:
:
break;
case solace.ErrorSubcode.REPLAY_START_TIME_NOT_AVAILABLE:
:
break;
// Additional events example, may add specific handler code under each:
case solace.ErrorSubcode.REPLAY_FAILED:
case solace.ErrorSubcode.REPLAY_CANCELLED:
case solace.ErrorSubcode.REPLAY_LOG_MODIFIED:
case solace.ErrorSubcode.REPLAY_MESSAGE_UNAVAILABLE:
case solace.ErrorSubcode.REPLAY_MESSAGE_REJECTED:
break;
default:
consumer.log('=== An error happened, the message consumer is down ===');
}
```

In this example two specific Subcodes are handled:

* REPLAY_STARTED is handled by creating a new flow with no client-initiated message replay.
* REPLAY_START_TIME_NOT_AVAILABLE is handled by adjusting `replayStartLocation` to replay all logged messages.

```
case solace.ErrorSubcode.REPLAY_STARTED:
consumer.log('Router initiating replay, reconnecting flow to receive messages.');
consumer.replayStartLocation = null; // Client-initiated replay is not neeeded here
consumer.createFlow();
break;
case solace.ErrorSubcode.REPLAY_START_TIME_NOT_AVAILABLE:
consumer.log('Replay log does not cover requested time period, reconnecting flow for full log instead.');
consumer.replayStartLocation = solace.SolclientFactory.createReplayStartLocationBeginning();
consumer.createFlow();
break;
```

## Running the Sample

Follow the instructions to [check out and run the samples]({{ site.repository }}/blob/master/README.md#checking-out ).

Before running this sample, be sure that Message Replay is enabled in the Message VPN. Also, create an exclusive queue with the name "tutorial/queue" and messages must have been published to the replay log for this queue:

* Use the "QueueProducer" sample from `src/basic-samples/QueueProducer` in your cloned repo to create and publish one message to the queue. To start, simply load `QueueConsumer.html` into you browser.
* Use the "QueueConsumer" sample from `src/basic-samples/QueueConsumer` to drain the queue so that replay is performed on an empty queue and observed by this sample. Both samples are from the [Persistence with Queues]({{ site.baseurl }}/persistence-with-queues) tutorial and they are using "tutorial/queue" by default. Note: after draining, disconnect the "QueueConsumer" from the queue because there can be only one consumer flow active on an exclusive queue at any time and the replay sample will need to connect a new one.

At this point the replay log has one message.

You can now run this sample and observe the following, particularly the "messageId"s listed.

1. First, use "MessageReplay" from `src/features/MessageReplay` for a client initiated replay. All messages are requested and replayed from the replay log.
2. After replay the application is able to receive live messages. Try it by publishing a new message using the "QueueProducer" sample. Note that this message will also be added to the replay log.
3. Now start a replay from the message broker. The "MessageReplay" flow event handler monitors for a replay start event. When the message broker initiates a replay, the flow will see a DOWN_ERROR event with cause REPLAY_STARTED. This means an administrator has initiated a replay, and the application must destroy and re-create the flow to receive the replayed messages.
This will replay all logged messages including the live one published in step 2.

![alt text]({{ site.baseurl }}/assets/images/initiate-replay.png "Initiating Replay using Solace PubSub+ Manager")
<br>

## Learn More

<ul>
{% for item in page.links %}
<li>Related Source Code: <a href="{{ site.repository }}{{ item.link }}" target="_blank">{{ item.label }}</a></li>
{% endfor %}
<li><a href="https://docs.solace.com/Features/Message-Replay.htm" target="_blank">Solace Feature Documentation</a></li>
</ul>

1 change: 1 addition & 0 deletions _docs/tutorials.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@
features:
- feature_ActiveConsumerIndication
- feature_DTEConsumer
- feature_MessageReplay
162 changes: 162 additions & 0 deletions src/features/MessageReplay/MessageReplay.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
<!DOCTYPE html>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->

<!--
Solace Web Messaging API for JavaScript
Message Replay tutorial - Queue Consumer
Demonstrates the use of Message Replay from the API client
-->

<html lang="en">

<head>
<title>Solace Web Messaging API for JavaScript, Message Replay tutorial</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge;" />
<meta charset="utf-8"/>

<link rel="stylesheet" type="text/css" href="../../resources/css/pure.css"></link>
<link rel="stylesheet" type="text/css" href="../../resources/css/samples.css"></link>

<!-- Load Solace Web Messaging API for JavaScript -->
<script src="../../../lib/solclient-debug.js"></script>

<!-- Load the Message Replay -->
<script src="MessageReplay.js"></script>

<!-- Execute the Message Replay tutorial -->
<script>
var subscriberWithReplay = null;
window.onload = function () {
// Initialize factory with the most recent API defaults
var factoryProps = new solace.SolclientFactoryProperties();
factoryProps.profile = solace.SolclientFactoryProfiles.version10;
solace.SolclientFactory.init(factoryProps);

// enable logging to JavaScript console at WARN level
// NOTICE: works only with "solclientjs-debug.js"
solace.SolclientFactory.setLogLevel(solace.LogLevel.WARN);

// create the consumer, specifying name of the queue
subscriberWithReplay = new QueueConsumer('tutorial/queue');
// assign buttons to the subscriber functions
document.getElementById("connect").addEventListener("click", subscriberWithReplay.connect);
document.getElementById("disconnect").addEventListener("click", subscriberWithReplay.disconnect);
document.getElementById("startreplay").addEventListener("click", subscriberWithReplay.startReplay);
document.getElementById("stopconsume").addEventListener("click", subscriberWithReplay.stopConsume);
};
function iframeloaded(){
if (subscriberWithReplay) {
subscriberWithReplay.connectToSolace();
}
};
</script>
<style>
.warning {
padding: 5px;
border: 1px solid black;
background-color: #ff8;
}
.ie11 {
/* Hide instructions that only apply to IE11/Edge */
display: none;
}
@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
.ie11 {
/* Show instructions in IE11. If you're trying this sample from the local filesystem,
it's easy to miss the prompt at the bottom of the window. */
display: block !important;
}
}
</style>
</head>

<body>
<!-- used to prompt selection of client certificate -->
<iframe id="iframe" src="" onload="iframeloaded()" hidden></iframe>

<div class="banner">
<div class="banner-interior">
<span class="logo">
<a href="http://dev.solace.com/">
<img src="../../resources/images/solace-logo-white.png"/>
</a>
</span>
<div class="banner-heading">
Solace Web Messaging API for JavaScript
</div>
</div>
</div>

<div class="doc-body">
<h2>Message Replay tutorial</h2>
<!--[if IE]>
<div class="ie9 warning" style="padding: 5px; border: 1px solid black; background-color: #ff8;">
IE9 only: If you are running this sample from the local filesystem, click the "Allow blocked content" button
in the popup below to enable JavaScript.
</div>
<![endif]-->
<div class="ie11 warning">
IE 11 only: If you are running this sample from the local filesystem, click the "Allow blocked content" button
in the popup below to enable JavaScript.
</div>

<form class="pure-form pure-form-aligned">
<fieldset>

<div class="pure-control-group">
<label for="hosturl">Solace router host url</label>
<input id="hosturl" type="text" placeholder="<protocol://host[:port]>">
</div>

<div class="pure-control-group">
<label for="message-vpn">Message-vpn</label>
<input id="message-vpn" type="text" placeholder="Message VPN" value="default">
</div>

<div class="pure-control-group">
<label for="username">Username</label>
<input id="username" type="text" placeholder="Username">
</div>

<div class="pure-control-group">
<label for="password">Password</label>
<input id="password" type="password" placeholder="Password">
</div>

</fieldset>
<p>
<button type="button" class="pure-button pure-button-primary" id="connect">Connect</button>
<button type="button" class="pure-button button-error" id="disconnect">Disconnect</button>
</p>
<p>
<button type="button" class="pure-button pure-button-primary" id="startreplay">Initiate message replay</button>
<button type="button" class="pure-button button-error" id="stopconsume">Stop consuming</button>
</p>

<textarea id="log" rows="20" cols="90" autofocus></textarea>

</form>

</div>

</body>

</html>

Loading