zmq send with NOBLOCK raise Resource temporarily unavailable

schemacs picture schemacs · Feb 17, 2014 · Viewed 14.8k times · Source

This code will raise Resource temporarily unavailable when call with NOBLOCK:

context = zmq.Context()
sender = context.socket(zmq.PUSH)
sender.bind('tcp://*:15556')
sender.send('KeEpAliv', zmq.NOBLOCK)  # this line will throw exception
#sender.send('KeEpAliv')  # this line will ok

After read the docs, I found no hints for this. but docs for recv explained this flag.

Answer

Code Painters picture Code Painters · Feb 25, 2014

Python wrappers raise zmq.error.Again if the underlying C API returns EAGAIN.

Now, you should follow to zmq_send documentation, which states:

ZMQ_NOBLOCK
Specifies that the operation should be performed in non-blocking mode. If the message cannot be queued on the socket, the zmq_send() function shall fail with errno set to EAGAIN.

Also, in the errors section:

EAGAIN
Non-blocking mode was requested and the message cannot be sent at the moment.

Now, why is it not possible to send any message? On the page describing PUSH/PULL sockets we can read the following about the PUSH socket:

SHALL create this queue when a peer connects to it. If this peer disconnects, the PUSH socket SHALL destroy its queue and SHALL discard any messages it contains.

Before any peer connects to your socket, there's nowhere to send the messages, and there's no queue. Thus only 2 things are possible:

  • if you call send() in blocking mode, it blocks until a peer connects
  • if you call send() in non-blocking mode, it raises zmq.error.Again to inform you, that there's nothing that could be done with the message and you should try again later.

Note, that you can also get this exception if queues for each of the connected peers are full (PUSH socket creates a separate queue for each connected peer).