I have nginx in front of 8 instances of Tornado, and for some requests (a handler for comments), I need Tornado to push messages on ZeroMQ. I am doing this at the end of the handler (just before I send the response to the client):
# here is body of handler for comments
context = zmq.Context()
port = "5252"
socket = context.socket(zmq.PUSH)
socket.bind("tcp://*:%s" % port)
print "Running server on port: ", port
socket.send("Commented")
# here I flush response to client
But this is hanging. Is this real way to push to ZeroMQ whenever the handler is executed?
Is this real way to push to ZeroMQ whenever the handler is executed?
No. Your code calls zmq.Context() every time the request handler is invoked. This is bad. It should be called exactly once - usually at the very beginning of your process, perhaps in some kind of init handler. You can safely share the context instance among any number of threads.
Same thing with socket creation and binding - this should be done once at startup. You must be more careful with the socket. If all your handlers (application, request etc) are executing in the same thread each time the handler is called, then you can use the same socket.
Another problem is the way your a "send"-ing to a PUSH socket. As described in http://api.zeromq.org/3-2:zmq-socket, a send to a PUSH socket may very well block in certain situations and you probably want to avoid that. Use the zmq.Poller with the POLLOUT flag (and a 0 timeout) to determine if the send would block. If not, then send right away. If so, you have to decide if you want to just drop the message or store it in your application to try again later.
Related
I open a single TCP connection to a gateway PC. My application will send messages to the gateway which will process the payload and pass on the message to another computer (based on payload) for processing.
For example, I send message A over the TCP connection which will be routed to computer A for response. But I may also need to send message B which goes to computer B.
Currently I simply use send(messageA) and then use recv() to wait for the response. The downside is that the recv() will block which means I can't send message B until something is received (and I can't do any other tasks).
I have read about the following options but am confused to the best for my use case.
Make the socket non-blocking. I send message A, call recv() (let's assume there is some delay in processing such that nothing is received immediately; so code moves on), move on to send message B and again call recv(). Now, it could be A or B that responds, which I can handle. But I need to call recv() again since only one response received so far; but what if computer A is down and never responds -- at some point I need to decide to stop calling recv(), right? On what basis would I do this?
Set a timeout on the socket. Again, send message A but assume computer A is down, so the code will wait for timeout before moving on which is wasted time.
Use select. Since I have only one socket and I don't think that helps here; plus, I understand select will block unless a timeout is set so no different, in this case, to the option above?
Use multithreading. Have one thread to process the main application and do the sending. And another thread that just calls recv() in an infinite loop (or a long timeout) that calls a callback whenever data is available. But then if the connection is closed from the main thread, will the recv thread cause an exception or hang?
I am really not sure what best practices are or the pitfalls of the options above. Which would be best option or is there another option?
(I'm using Python, in case it makes a difference).
I have Tornado websocket handler and I am sending messages from my browser ( I have override on_message,on_close,open).
In javascript on close I want to send some data to handler ( to clean some storages, I am sending some numbers in json like {'storage':22, 'time':96} ).
How in websocket handler in tornado to receive that closing message ?
I looked at close and on_close but there is no option to receive data.
If I understand what you're asking for correctly, it's impossible.
You want to make sure that when the connection is closed, and the browser calls the on_close function on your client-side JavaScript code, it can send some final data to the Tornado server.
But when the connection is closed, there's no way to send any more data. That's what it means to be closed.
What you need to do is create a "quit" or similar message, at the application level. When Tornado sends a "quit" message to the JS code, then it can send its final message; when Tornado receives that message, it can close the socket. (Of course this means you need to write your code to handle the case where that "graceful shutdown" never happens because, e.g., the client machine has been vaporized by a nuclear bomb.)
As far as I understand the basics of the client-server model, generally only client may initiate requests; server responds to them. Now I've run into a system where the server sends asynchronous messages back to the client via the same persistent TCP connection whenever it wants. So, a couple of questions:
Is it a right thing to do at all? It seems to really overcomplicate implementation of a client.
Are there any nice patterns/methodologies I could use to implement a client for such a system in Python? Changing the server is not an option.
Obviously, the client has to watch both the local request queue (i.e. requests to be sent to the server), and the incoming messages from the server. Launching two threads (Rx and Tx) per connection does not feel right to me. Using select() is a major PITA here. Do I miss something?
When dealing with asynchronous io in python I typically use a library such as gevent or eventlet. The objective of these libraries is allow for applications written in a synchronous to be multiplexed by a back-end reactor.
This basic example demonstrates the launching of two green threads/co-routines/fibers to handle either side of the TCP duplex. The send side of the duplex is listening on an asynchronous queue.
This is all performed within a single hardware thread. Both gevent && eventlet have more substantive examples in their documentation that what I have provided below.
If you run nc -l -p 8000 you will see "012" printed out. As soon netcat is exited, this code will be terminated.
from eventlet import connect, sleep, GreenPool
from eventlet.queue import Queue
def handle_i(sock, queue):
while True:
data = sock.recv(8)
if data:
print(data)
else:
queue.put(None) #<- signal send side of duplex to exit
break
def handle_o(sock, queue):
while True:
data = queue.get()
if data:
sock.send(data)
else:
break
queue = Queue()
sock = connect(('127.0.0.1', 8000))
gpool = GreenPool()
gpool.spawn(handle_i, sock, queue)
gpool.spawn(handle_o, sock, queue)
for i in range(0, 3):
queue.put(str(i))
sleep(1)
gpool.waitall() #<- waits until nc exits
I believe what you are trying to achieve is a bit similar to jsonp. While sending to the client, send through a callback method which you know of, that is existing in client.
like if you are sending "some data xyz", send it like server.send("callback('some data xyz')");. This suggestion is for javascript because it executes the returned code as if it were called through that method., and I believe you can port this theory to python with some difficulty. But I am not sure, though.
Yes this is very normal and Server can also send the messages to client after connection is made like in case of telnet server when you initiate a connection it sends you a message for the capability exchange and after that it asks you about your username & password.
You could very well use select() or if I were in your shoes I would have spawned a separate thread to receive the asynchronous messages from the server & would have left the main thread free to do further processing.
Is it possible to somehow cancel xmlrpc client request?
Let say that in one thread I have code like:
svr = xmlrpclib.ServerProxy('http://localhost:9092')
svr.DoSomethingWhichNeedTime()
I don't mean some kind of TimeOut... Sometimes from another thread I can get event to cancel my work. And then I need to cancel this request.
I know that I can do it with twisted but, is it possible to do it with standard xmlrpclib?
First of all, it must be implemented on server side, not in client (xmlrpclib). If you simply interrupt your HTTP request to XML-RPC server, it's not guaranteed that long process running on the server will be interrupted at all. So xmlrpclib just can't have this functionality.
If you want to implement this behaviour, you need to create two type of requests. A request of first type will tell your server to start some long process. It must be executed in background (in another thread or process), and your XML-RPC server must send the response ("Process started!") to the client immediately. When you want to stop the process, client must send another request that will tell your server to stop executing of process.
Yes, if you want to do really dirty hacks....
Basically the ServerProxy object keeps a handle to the underlying socket/http connection. If you reached into those internals and simply close() the socket your client code will blow up with an exception. If you handle those properly its your cancel.
You can do it a little more sane if you register your own transport class for the ServerProxy via the transport parameter and give it some cancel method that does what you want.
That won't stop the server from processing things, unless it reacts to closing the channel directly.
Python's logging handlers are great. Some of them, such as the SMTPHandler may take a long while to execute (contacting an SMTP server and all). Are they executed on a separate thread as to not block the main program?
SMTPHandler uses smtplib and when sending an email with this library, your process is blocked until it have been correctly sent, no thread created.
If you do not want to block your process when sending an email, you'll have to implement your own SMTPHandler and override the emit(self, record) method.
The less blocking handler is the SysLogHandler, because it is in general a local communication, and in UDP so the system doesn't wait for any acknowledgement from the destination.
No, you should spawn a separate process, as far as I know.