Push to a client?
sb10 opened this issue · 13 comments
I currently have a server listening on a port doing req/rep (as per #187).
How can I now (effectively or actually) "push" information to a client, making use of the same port?
Basically a client will make a request as normal, but it could be 10s of minutes before the result is ready and I reply.
I'd rather avoid just making the timeout really long on the req socket.
I'd like to avoid the client polling the server every x mins to ask if that result is ready yet.
What are my options?
So, the problem is that req tends to want a timeout, so it can detect a lost message. Are you using req in cooked mode? If so, you will have to bump up the socket timeout, otherwise you will have no way of identifying whether the message was lost, work is being done, etc...
For really long long jobs like this, you might want to use a higher level notion of what "job" is, and either poll that, or create a notification channel in parallel (like a PUB/SUB socket, where the PUB is the server and the SUB is the client).
So for example:
Client sends: REQ (PostJob)
Server: sends: REP (Job ID is xxxx, expected completion in X minutes)
Then client can poll for completion (new request "GetJobStatus") periodically (based on the expected work time, perhaps).
The client can also have a socket open to the server's pub, where the server posts job completion IDs. Use this with the polling logic above, so that you won't miss messages, but can use this to wake up the client as soon as the job is ready, instead of waiting for the polling interval.
Note that if you use a single PUB socket on the server (rather than one per client), then every client will see job all job IDs that are complete. The SUB can filter these, but the completion status will still get delivered to every client.
Another approach would be to have the client start up a REP socket in parallel with the REQ, and have some kind of negotiation between the client and server so that the server learns where to send job completion indications (which REQ socket it will use.)
It may be worth examining whether a new pattern is called for here. As it stands, you don't want to use unaugmented REQ/REP for jobs with very very long timeouts.
@gdamore, this calls for a router/dealer pattern in mangos. any plans to implement it?
The problem is that the OP wants to have really long jobs without using a really long timeout on the reply.
I don't think this is really the problem. it is only what OP came up with based on what REQ/REP gives you and the fact that it works the way it works. that said, synchronous.
having a ROUTER and DEALER, OP could make real push notifications to the client, since the client would be a DEALER connecting to the ROUTER (server). the router knows its identity and can send async msgs. that would be a real push (client wouldn't have to open any ports to listen on a socket).
the problem of OP arises due to the way REQ/REP works. it does not allow you the above. (a req always connects, a rep always listens). but you can't rep without having a req before.
I think ZMQ would have the same problems.
Again, the problem is not with timeouts or waiting for long running jobs. that's only the symptom.
you can have a look at the majordomo pattern of zmq https://rfc.zeromq.org/spec:7/MDP/. it basically makes use of what I've described above (using ROUTER/DEALER sockets).
think of ROUTER/DEALER as zmq's XREQ/XREP (which actually is the logic behind router/dealer in zmq with some additional sugar). if OPs server was able to send msgs in an async fashion (which would be an XREP), he wouldn't have the need to wait for a reply on the client side that long, so no high timeouts, no long polling would be needed at all.
Yes true. What I mean by that is more the way one would use this pattern in a client-server application. If the client is the one who's logic is to initiate a request and expects something back, the pattern would be to use a req socket which dials to a server, sending the request and waiting for a response. And the other way goes for the server. Now given OPs requirement one would also need to open a port on the client to be able to accept requests from the server if the server was to push back delayed notifications about processed jobs. the initial connection would be from the server. Given that a rep only happens after a req, the client would have to maintain a second socket or implement a second logic for dealing with this part of the communication.
The main thing I am talking about here is sync vs async actually. A router/dealer is exactly for this kind of stuff. No need to wait for a reply after sending a request. And the same goes for a reply. OP wouldnt need to have a request before sending out a reply. And with this he would be able to notify the client about completed jobs anytime he wants.
Thanks gdamore for the suggestions. I'll see if I can make sense of that and implement something that works. I don't know what "cooked" mode means.
I'll note that omani does seem to have understood what I need, and router/dealer sounds useful.
BTW, the http://tim.dysinger.net/posts/2013-09-16-getting-started-with-nanomsg.html link in the README.md no longer works, and it would be nice to get a single page friendly explanation of all the possible patterns without having to try and understand the comments in the examples and generalise those out to all the ways those patterns could be used. (I couldn't find such a thing on the nanomsg website either.)
Oh, as per #187 I have to use raw mode, so I guess not "cooked".
I think your suggestion boils down to "poll the server", which was what I was hoping to avoid. Adding in Pub/Sub on the side would be an improvement, but it is possible for the server to do Pub as well over the same socket as it is using for Rep? The issue is, I really don't want to use another port for this.
Likewise, I can't have the client use a new socket, so I don't think I can implement your alternative idea of the client starting a Rep?
With mangos, you can use different URLs and websocket to avoid consuming another port. There is no other way at present to multiplex different SP protocols on the same port.
The other thing that folks should look at is the nn_device() API. This has functionality that is similar to router/dealer in ZMQ. It doesn't really solve the problem, I think, in that the originating socket (the REQ socket) is still going to want to have a timeout I don't think router/dealer are intended to work around this requirement. Of course, if you don't want the automatic timeout and "one outstanding request at a time" semantic of a cooked REQ socket, then you need to use a raw mode REQ socket. In that case you own the problem of dealing with retries, matching replies to requests, etc.
Unfortunately I don't see a good solution to address the needs described here, while still offering the simple send/recv semantic of a socket. One can build a different API with better/richer semantics -- like an RPC client that supports multiple outstanding requests with independent timeouts -- on top of raw mode sockets, and I've done that multiple times. I think its probably time for us to do this -- it seems like there is a real use case for this here. But this would be a new project that builds upon nanomsg/nng/mangos with a different API. (Like an RPC API.)
Thanks. Can you offer some code example where you "use different URLs and websocket to avoid consuming another port"?
have a look into https://github.com/go-mangos/mangos/tree/master/examples/websocket. you can see several different sockets being handled by a multiplexer.
So can we close this issue now?