What I'm trying to accomplish is to implement reading a message from one of two sockets, wherever it arrives first. As far as I understand polling (zmq_poll) is the right thing to do (as demonstrated in mspoller in guide). Here I'll provide small pseudo-code snippet:
TimeSpan timeout = TimeSpan.FromMilliseconds(50);
using (var receiver1 = new ZSocket(ZContext.Current, ZSocketType.DEALER))
using (var receiver2 = new ZSocket(ZContext.Current, ZSocketType.PAIR))
{
receiver1.Bind("tcp://someaddress");
// Note that PAIR socket is inproc:
receiver2.Connect("inproc://otheraddress");
var poll = ZPollItem.CreateReceiver();
ZError error;
ZMessage msg;
while (true)
{
if (receiver1.PollIn(poll, out msg, out error, timeout))
{
// ...
}
if (receiver2.PollIn(poll, out msg, out error, timeout))
{
// ...
}
}
}
As you can see it is actually the same exact implementation as in mspoller in guide.
In my case receiver2 (PAIR socket) should receive a large number of messages. In fact I've created a test in which number of messages sent to it is always greater than the number of messages it is capable to receive (at least in demonstrated implementation).
I've run the test for 2 seconds, and I was very surprised with results:
Number of messages sent to receiver2: 180 (by "sent" I mean that they are handed out to another PAIR socket not shown in the previous snippet);
Number of messages received by receiver2: 21 ??? Only 21 messages in 2 seconds??? 10 messages per second???
Then I've tried to play with different timeout values and I've found out that it significantly influences the number of messages received. Duration (2 seconds) and number of messages sent (180) remain the same. The results are:
timeout value of 200 milliseconds - number of messages received drops to 10 (5 per second);
timeout value of 10 milliseconds - number of messages received rises to 120 (60 per second).
The results are telling me that polling simply does not work. If polling were working properly, as far as I understand the mechanism, timeout should not have any influence in this scenario. No matter if we set timeout to 1 hour or 5 milliseconds - since there are always messages to receive there's nothing to wait for, so the loop should work with the same speed.
My another big concern is the fact that even with very small timeout value receiver2 is not capable to receive all 180 messages. I'm struggling here to accomplish receiving rate of 100 messages per second, although I've selected ZeroMQ which should be very fast (benchmarks are mentioning numbers as 6 million messages per second).
So my question is obvious: am I doing something wrong here? Is there a better way to implement polling?
By browsing clrzmq4 code I've noticed that there's also possibility to call pollIn method on enumeration of sockets ZPollItems.cs, line 151, but I haven't found any example anywhere!
Can this be the right approach? Any documentation anywhere?
Thanks
I've found the problem / solution for this. Instead using PollIn method on each socket separately we should use PollIn method on array of sockets. Obviously the example from the guide is HUGELY MISLEADING. Here's the correct approach:
TimeSpan timeout = TimeSpan.FromMilliseconds(50);
using (var receiver1 = new ZSocket(ZContext.Current, ZSocketType.DEALER))
using (var receiver2 = new ZSocket(ZContext.Current, ZSocketType.PAIR))
{
receiver1.Bind("tcp://someaddress");
receiver2.Connect("inproc://otheraddress");
// We should "remember" the order of sockets within the array
// because order of messages in the received array will correspond to it.
ZSocket[] sockets = { receiver1, receiver2 };
// Note that we should use two ZPollItem instances:
ZPollItem[] pollItems = { ZPollItem.CreateReceiver(), ZPollItem.CreateReceiver() };
ZError error;
ZMessage[] msg;
while (true)
{
if (sockets.PollIn(pollItems, out msg, out error, timeout))
{
if (msg[0] != null)
{
// The first message gotten from receiver1
}
if (msg[1] != null)
{
// The second message gotten from receiver2
}
}
}
}
Now receiver2 reaches 15,000 received messages per second, no matter timeout value, and no matter number of messages received by receiver1.
UPDATE: Folks from clrzmq4 have acknowledged this issue, so probably the example will be corrected soon.
Related
I'm trying to cache http calls in the service so all subsequent calls returns same response. This is fairly easy with shareReplay:
data = this.http.get(url).pipe(
shareReplay(1)
);
But it doesn't work in case of backend / network errors. ShareReplay spams the backend with requests in case of any error when this Observable is bound to the view through async pipe.
I tried with retryWhen etc but the solution I got is untestable:
data = this.http.get(url).pipe(
retryWhen(errors => errors.pipe(delay(10000))),
shareReplay(1)
);
fakeAsync tests fails with "1 timer(s) still in the queue" error because delay timer has no end condition. I also don't want to have some hanging endless timer in the background - it should stop with the last subscription.
The behavior I would like:
Multicast - make only one subscription to source even with many subscribers.
Do not count refs for successful queries - reuse same result when subscriber count goes to 0 and back to 1.
In case of error - retry every 10 seconds but only if there are any subscribers.
My 2 cents:
This code is for rxjs > 6.4 (here V6.6)
To use a shared observable, you need to return the same observable for all the subscribers (or you will create an observable which has nothing to share)
Multicasting can be done using shareReplay and you can replay the last emitted value (even after the last subscriber to have unsubscribed) using the {refCount: false} option.
As long as there is no subscription, the observable does nothing. You will not have any fetch on the server before the first subscriber.
beware:
If refCount is false, the source will not be
unsubscribed meaning that the inner ReplaySubject will still be
subscribed to the source (and potentially run for ever).
Also:
A successfully completed source will stay cached in the shareReplayed
observable forever, but an errored source can be retried.
The problem is using shareReplay, you have to choose between:
Always getting the last value even if the refCount went back to 0 and having possible never ending retries in case of error (remember shareReplay with refCount to false never unsubscribes)
Or keeping the default refCount:true which mean you won't have the second "first subscriber" cache benefit. Conversely the retry will also stop if no subscriber is there.
Here is a dummy example:
class MyServiceClass {
private data;
// assuming you are injecting the http service
constructor(private http: HttpService){
this.data = this.buildData("http://some/data")
}
// use this accessor to get the unique (shared) instance of data observable.
public getData(){
return this.data;
}
private buildData(url: string){
return this.http.get(url).pipe(
retryWhen(errors => errors.pipe(delay(10000))),
shareReplay({refCount: false})
);
}
}
Now in my opinion, to fix the flow you should prevent your retry to run forever, adding for instance a maximum number of retries
I'm using the Select2 select boxes in my Django project. The ajax calls it makes can be fairly time-consuming if you've only entered a character or two in the query box, but go quicker if you've entered several characters. So what I'm seeing is you'll start typing a query, and it will make 4 or 5 ajax calls, but the final one returns and the results display. It looks fine on the screen, but meanwhile, the server is still churning away on the earlier queries. I've increased the "delay" parameter to 500 ms, but it's still a bit of a problem.
Is there a way to have the AJAX handler on the server detect that this is a new request from the same client as one that is currently processing, and tell the older one to exit immediately? It appears from reading other answers here that merely calling .abort() on the client side doesn't stop the query running on the server side.
If they are DB queries that are taking up time, then basically nothing will stop them besides stopping the database server, which is of course not tangible. If it is computation in nested loops for example, then you could use cache to detect whether another request has been submitted from the same user. Basically:
from django.core.cache import cache
def view(request):
start_time = timestamp # timezone.now() etc.
cache.set(request.session.session_key + 'some_identifier', start_time)
for q in werty:
# Very expensive computation with millions of loops
if start_time != cache.get(request.session.session_key + 'some_identifier'):
break
else:
# Continue the nasty computations
else:
cache.delete(request.session.session_key + 'some_identifier')
But the Django part aside - what I would do: in JS add a condition that when the search word is less than 3 chars, then it waits 0.5s (or less, whatever you like) before searching. And if another char is added then search right away.
I.e.
var timeout;
function srch(param) {
timeout = false;
if (param.length < 3) {
timeout = true;
setTimeout(function () {
if (timeout) {
$.ajax({blah: blah});
}
}, 500);
} else {
$.ajax({blah: blah});
}
}
I used the tcp protocol to deal the request the client, I found a phenomenon which is some of the content is missing while using the function of 'send'. the code is as fellow:
_stprintf(cData,"[%s]",send_back);
memset(send_back,0,sizeof(cData));
int send_count;
if((send_count=send(service_sock,cData,_tcslen(cData),0))!=SOCKET_ERROR){
fwrite(cData,sizeof(char),_tcslen(cData),hFile);
fflush(hFile);
g_log->print_log("%c%c%c%c",cData[0],cData[1],cData[2],cData[send_count-1]);
g_log->print_log("buffer len is :%d , send %d bytes",_tcslen(cData),send_count);
fclose(hFile);
memset(cData,0,sizeof(cData));
return true;
}
the send function is always successful, and the value of _tcslen(cData) is equal to send_count and the cData[send_count-1] is ']'.
But when I use the wireshark(a capture tool) to capture the packet which is send out by the socket, I found some content is always missing including the Character of ']'. the content is encapsulated by JSON protocol, so the ']' is important. the total size of every time send out is 8900 bytes. But when I change the request item one time (before is 100) to 50, there is nothing missed, the size of send back is about 4000 bytes.
I do not know why this happened.
from my log file, I am sure the array named 'cData' contain the total content, But why the the content from the packets captured by the wireshark is not complete?
Seeing that you're using TCP, it already looks wrong.
First off, TCP is stream protocol which is not suited for one time packets ( especially small ) but the benefits are far more greater than just use UDP instead.
Keep in mind that in case of TPC you are not in control you can only make sure that your requests are handled correctly, the actual communication is done by the Winsock library.
Always remember that the send functions len parameter is NOT a requirement it's a hint on how big is your buffer and how much you can send in one go, it may return less than you want to send, and this may depend on lot of factors how often it happens, lets say you use the loopback device it would probably never ever do this, meaning that send will actually send what you requested. In a real network it may send it on one go in about 90% or with even less probability.
You have to make sure you send as much as you want, i.e. check for the return value and call send again if it didn't send as much as you wanted and do the same on the other side with recv, call recv until you get as much data as you wanted. This method only works if you know exactly how much data you want to send over the network.
As for the loss off data, TCP, I would say almost always sends data, assuming that you checked the return value of send. If there is a network problem, like loss of data you would see the TCP retransmit packet.
For your way of sending data this is more suitable, this is to make sure you really send the amount of data you want :
xint xsend(SOCKET s,const char* buf,xint len)
{
xint lastSize;
xint result;
if (len==0 || s==(SOCKET)NULL || buf==(const char*)NULL)
return SOCKET_ERROR;
lastSize=0;
result=0;
do
{
result=send(s,buf+lastSize,len-lastSize,0);
if (result==0)
return 0;
if (result==SOCKET_ERROR)
return SOCKET_ERROR;
if (result==len)
return len;
if (result>len)
{
xlog(1,"xsend : socket sent too much data [ %i of %i ]",result,len);
return SOCKET_ERROR;
}
lastSize+=result;
if (lastSize>len)
{
xlog(1,"xsend : socket sent too much data ( overall ) [ %i of %i ]",result,len);
return SOCKET_ERROR;
}
if (lastSize==len)
return len;
}
while (1);
xlog(2,"failed to do xsend");
return SOCKET_ERROR;
}
This code is just a copy paste from one of my projects, xlog is simple logging function, you can figure it out.
In the Majordomo pattern, a section of code in the worker looks like this
mdwrk session ("tcp://localhost:5555", sourceStr.c_str(), verbose);
zmsg *reply = 0;
while (1) {
zmsg *request = session.recv (reply);
if (request == 0) {
break; // Worker was interrupted
}
//reply = request; // Echo is complex... :-)
reply = new zmsg(sourceStr.c_str());
}
To my worker, the request from the client is an order to be sent to an exchange. I am trying to wrap my head around how, after I send the order to the exchange, and I get a message back like, Insert, Pending, New, etc, I can stuff the contents of the FIX response, into zmsg *reply.
The FIX message comes back asynchrously, so I won't be able to say
reply = FIXResponse;
How is this resolved?
I think the Majordomo protocol is meant to handle synchronous requests and not really appropriate here.
Just came across one of your other questions, and see that you have multiple sources for these replies. You could PUSH them all into a single stable PULL socket? (And then republish if appropriate. If the volume is low, you could even get away with durable subscribers for reliability.)
I have Protocol Buffer for logging data.
message Message {
required double val1 = 1;
optional int val2 = 2;
}
message BigObject {
repeated Message message = 1;
}
I receive messages one per second. They stored in memory with my BigObject and they used for some tasks. But at the same time i want to store that messages in file for backup in case application crash. Simple writing BigObject every time will be waste of time. And I trying to find way to write only added messages since last write to file. Is there a way for that?
Protobuf is an appendable format, and your layout is ideal for this. Just open your file positioned at the end, and start with a new (empty) BigObject. Add/serialize just the new Message instance, and write to the file (from the end onwards).
Now, if you parse your file from the beginning you will get a single BigObject with all the Message instances (old and new).
You could actually do this by logging each individual Message as it arrives, as long as you wrap it in a BigObject each time, i.e. in pseudo-code
loop {
msg = await NextMessage();
wrapper = new BigObject();
wrapper.Messages.Add(msg);
file = OpenFileAtEnd();
wrapper.WriteTo(file);
file.Close();
}