Improving REQ sockets in ZMQ 4

I contributed two new socket options to libzmq 4.0: ZMQ_REQ_CORRELATE and ZMQ_REQ_RELAXED. They simplify usage of REQ sockets in situations where you would have had to reset the whole socket or switch to a DEALER socket with earlier versions. More specifically, you can now send a new request on a REQ socket when you’ve given up on getting a response for the preceding request.

ZMQ defines several socket types that can be used to implement different messaging patterns. REQ sockets provide the basic “send a request, wait for the response, send the next request, …” pattern and are used frequently. In practice things break though and you’re not guaranteed to actually get a response to a request. The old REQ sockets strictly enforce the send/recv/send/recv/… cycle and have to be completely reset when a timeout is detected.

This is unintuitive and people have commented on it in several times.

With ZMQ_REQ_RELAXED enabled, calling send() while waiting for a reply becomes valid. It will give up on the old request and send a new one.

When enabling ZMQ_REQ_RELAXED, always enable ZMQ_REQ_CORRELATE as well. It ensures the receive call only reports the reply to the latest request. Otherwise, if the old reply comes in after all, you might receive that and think it’s the reply for the later request.

The new option only changes the behavior for send() in a state where it would previously have returned an EFSM error. It is safe to enable it in nearly all cases. libzmq wants to make it as easy as possible for users to migrate to new versions, however, so it is not enabled by default.

Contributing to libzmq has been simple and rewarding. They use a interesting “merge first, review later” process which sounds problematic – but which seems to work for them and definitely made me feel welcome as a contributor.