Skip to content

Commit

Permalink
Merge pull request #870 from dhyams/relaxed_correlate_docs_866
Browse files Browse the repository at this point in the history
Relaxed/correlate socket option docs #866
  • Loading branch information
somdoron authored May 5, 2020
2 parents e32655a + fd24ada commit cc4dd5c
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 6 deletions.
6 changes: 4 additions & 2 deletions docs/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,12 @@ NetMQ comes with several options that will effect how things work.

Depending on the type of sockets you are using, or the topology you are attempting to create, you may find that you need to set some ZeroMQ options. In NetMQ this is done using the `NetMQSocket.Options` property.

Here is a listing of the available properties that you may set on a `NetMQSocket`. It is hard to say exactly which of these values you may need to set, as that obviously depends entirely on what you are trying to achieve. All I can do is list the options, and make you aware of them. So here they are:
Here is a listing of the available options that you may set on a `NetMQSocket`. It is hard to say exactly which of these values you may need to set, as that obviously depends entirely on what you are trying to achieve. All I can do is list the options, and make you aware of them. So here they are:

+ `Affinity`
+ `BackLog`
+ `CopyMessages`
+ `Correlate`
+ `DelayAttachOnConnect`
+ `Endian`
+ `GetLastEndpoint`
Expand All @@ -185,6 +186,7 @@ Here is a listing of the available properties that you may set on a `NetMQSocket
+ `ReceiveBuffer`
+ `ReconnectInterval`
+ `ReconnectIntervalMax`
+ `Relaxed`
+ `SendHighWaterMark`
+ `SendTimeout`
+ `SendBuffer`
Expand All @@ -194,4 +196,4 @@ Here is a listing of the available properties that you may set on a `NetMQSocket
+ `TcpKeepaliveInterval`
+ `XPubVerbose`

We will not be covering all of these here, but shall instead cover them in the areas where they are used. For now just be aware that if you have read something in the <a href="http://zguide.zeromq.org/page:all" target="_blank">ZeroMQ guide</a> that mentions some option, that this is most likely the place you will need to set it/read from it.
We will not be covering all of these here, but shall instead cover them in the areas where they are used. For now just be aware that if you have read something in the <a href="http://zguide.zeromq.org/page:all" target="_blank">ZeroMQ guide</a> that mentions some option, that this is most likely the place you will need to set it/read from it. Also, the socket options are described in the <a href="http://api.zeromq.org/master:zmq-setsockopt" target="_blank">zmq_setsockopt</a> documentation.
43 changes: 39 additions & 4 deletions docs/request-response.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Anyway we digress, this post is about Request/Response, so lets continue to look

Request / Response pattern is a configuration of two NetMQ sockets working harmoniously together. This combination of sockets are akin to what you might see when you make a web request. That is, you make a request and you expect a response.

`RequestSocket` and `ResponseSocket` are **synchronous**, **blocking**, and throw exceptions if you try to read messages in the wrong order.
`RequestSocket` and `ResponseSocket` are **synchronous**, **blocking**, and throw exceptions if you try to read messages in the wrong order (however; see below for socket options that allow relaxing of this strict rule).

The way you should work with connected `RequestSocket` and `ResponseSocket`s is as follows:

Expand All @@ -21,7 +21,7 @@ The way you should work with connected `RequestSocket` and `ResponseSocket`s is
3. The `ResponseSocket` sends the response message
4. The `RequestSocket` receives the message from the `ResponseSocket`

Believe it or not you have more than likely already seen this example on numerous occasions as it is the simplest to demonstrate.
Believe it or not, you have more than likely already seen this example on numerous occasions as it is the simplest to demonstrate.

Here is a small example where the `RequestSocket` and `ResponseSocket`s are both in the same process, but this could be easily split between two processes. We are keeping this as simple as possible for demonstration purposes.

Expand Down Expand Up @@ -50,7 +50,7 @@ When you run this demo code you should see something like this:

## Request/Response is blocking

As stated above `RequestSocket` and `ResponseSocket` are blocking, which means any unexpected send or receive calls to **WILL** result in exceptions. Here is an example of just such an exception.
As stated above `RequestSocket` and `ResponseSocket` are blocking, which means any unexpected send or receive calls to **WILL** result in exception being thrown. Here is an example of just such an exception.

In this example we try and call `Send()` twice from the `RequestSocket`

Expand All @@ -60,4 +60,39 @@ Or how about this example where we try and call `RecieveString()` twice, but the

![](Images/RequestResponse2Receives.png)

So be careful what you do with the Request/Response pattern, the devil is in the detail.
So be careful what you do with the Request/Response pattern; the devil is in the details.

## Relaxing the strict req/rep pattern

If you have set the Relaxed and Correlate options for your request socket, you can send
multiple times from a request socket before a response arrives.
When you get a response back, that response will be a reply to the last sent request. Please
note, however, that this does not absolve the ResponseSocket from servicing all of the requests
that have come in; the only difference is that on the Requesting side, you will "see" only
one of the responses; the one for the latest request.

This functionality is useful for situations in which the responder might unexpectedly disconnect,
as well as being able to reliably query to see if a response socket is available before sending
a real request. See the <a href="http://api.zeromq.org/master:zmq-setsockopt" target="_blank">documentation for the native ZMQ library</a> at for more details.

A small example follows:

``` csharp
using (var rep = new ResponseSocket())
using (var req = new RequestSocket())
{
var port = rep.BindRandomPort($"tcp://127.0.0.1");
req.Connect($"tcp://127.0.0.1:{port}");
req.Options.Correlate = correlate;
req.Options.Relaxed = true;

req.SendFrame("Request1");
req.SendFrame("Request2");

rep.SendFrame(rep.ReceiveFrameString());
rep.SendFrame(rep.ReceiveFrameString());

// the result here will be "Request2".
Console.WriteLine(req.ReceiveFrameString());
}
```
31 changes: 31 additions & 0 deletions src/NetMQ.Tests/ReqRepTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,37 @@ public void SingleResponderSendsCorrectMessagesToMultipleRequestors()
}
}

[Theory]
[InlineData(false)]
[InlineData(true)]
public void ReplyIsForLatestRequestIfRelaxedAndCorrelateEnabled(bool correlate)
{
using (var rep = new ResponseSocket())
using (var req = new RequestSocket())
{
var port = rep.BindRandomPort($"tcp://127.0.0.1");

req.Connect($"tcp://127.0.0.1:{port}");
req.Options.Correlate = correlate;
req.Options.Relaxed = true;

req.SendFrame("Request1");
req.SendFrame("Request2");

rep.SendFrame(rep.ReceiveFrameString());
rep.SendFrame(rep.ReceiveFrameString());

if (correlate)
{
Assert.Equal("Request2", req.ReceiveFrameString());
}
else
{
Assert.Equal("Request1", req.ReceiveFrameString());
}
}
}

internal void RouterBounce(ref RouterSocket router)
{
bool more;
Expand Down

0 comments on commit cc4dd5c

Please sign in to comment.