user9204389
user9204389

Reputation:

ZeroMQ 'Restart' if no reply was recieved

I have a python program which sends height data from my client to my server program. My server program will not be always running so if I don't recieve a response I would like it to try again.

So far what I have is that if a response (from the server) is not given in 20 Seconds it causes an exception and recalls my input. It works fine until I try it a second time.

Here is my code:

import zmq
from time import sleep

global radius
context = zmq.Context()
print("Remote Deployment Application")
print("Lightweight ZMQ Communication")
print("Connecting to Desk Ctrl Service")
socket = context.socket(zmq.REQ)
socket.connect("tcp://192.168.1.9:5555")
socket.setsockopt(zmq.RCVTIMEO, 30000)
socket.setsockopt(zmq.LINGER, 0) 


#  Do 10 requests,waiting each time for a response
def __init__(self, height):
        self.height = height

def start():
    global height
    height = input("Enter in request: ")
    SendHeightVal()


def SendHeightVal():
    global userinput
    global height
    print("Sent Request. Awaiting Reply.")
    so_bytes = height.encode()
    socket.send(so_bytes)
    so_bytes = 0
    try:
       message = socket.recv()
    except:
        print("Something went wrong. No response from server!")
        message = None       
        start()    
    print(message)
    start()

Here is the error:

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "client.py", line 44, in <module>
    start()
  File "client.py", line 22, in start
    SendHeightVal()
  File "client.py", line 37, in SendHeightVal
    start()
  File "client.py", line 22, in start
    SendHeightVal()
  File "client.py", line 30, in SendHeightVal
    socket.send(so_bytes)
  File "/usr/local/lib/python3.6/site-packages/zmq/sugar/socket.py", line 391, in send
    return super(Socket, self).send(data, flags=flags, copy=copy, track=track)
  File "zmq/backend/cython/socket.pyx", line 727, in zmq.backend.cython.socket.Socket.send
  File "zmq/backend/cython/socket.pyx", line 774, in zmq.backend.cython.socket.Socket.send
  File "zmq/backend/cython/socket.pyx", line 249, in zmq.backend.cython.socket._send_copy
  File "zmq/backend/cython/socket.pyx", line 244, in zmq.backend.cython.socket._send_copy
  File "zmq/backend/cython/checkrc.pxd", line 25, in zmq.backend.cython.checkrc._check_rc
zmq.error.ZMQError: Operation cannot be accomplished in current state

Upvotes: 2

Views: 1802

Answers (2)

user3666197
user3666197

Reputation: 1

Let's start with a simple inventory of mandatory features:

[agent-A] sends height data from my client to my server program. My server program [agent-B] will not be always running so if I don't receive a response I would like it [agent-A] to try again.

For this, the REQ/REP hard-wired two-step of
[A].send()-[B].recv()-[B].send()-[A].recv()-[A].send()-[B].recv()-... is not the promising or safe choice.

1 ) always set zmq.LINGER = 0 to avoid zombies & hangups ( +1 for doing that )

2 ) if need not keep all [A]-side data delivered, may enjoy zmq.IMMEDIATE to deliver only to live [B] and zmq.CONFLATE to deliver only the most "fresh" values the [A]-side did .send()

3 ) if need in a need to keep all [A]-side data delivered, will have to either re-factor the strategy of sending on [A]-side become robust to missing [B]-side, so as to avoid blind and just optimistic data-pumping into the Context()-instance controlled, but rather expensive and quite limited resources, or carefully plan and pre-allocate due capacities, so as to remain able to internally store all of them till the [B]-comes ( or not ) somewhere unsure in the future or the [A]-side dropping or blocking or exceptions will be unavoidable.

4 ) never expect the built-in trivial ( primitive ) archetypes to match your production needs, these come as a sort of LEGO-building blocks for some smarter, problem-specific distributed signalling and messaging infrastructure, not as a magic wand to solve all properties ( principally unknown and undefined at the time of these primitive-tools implementation ), so more engineering efforts will come, as one moves outside of school-book examples into designing robust distributed systems. Here could be a way using a composition of { PUSH/PULL + PULL/PUSH | PAIR/PAIR | XREQ/XREP } plus heart-beating watchdog and re-discovery of remote agent(s). Some other archetypes may get later added for N+1 fault resilience or performance boosting with workload balancers or remote-console or latency motivated off-site remote-logging - if needed, all depending on hell many details that are beyond the initial post or a few SLOCs.

5 ) always handle exceptions, even if "masters" tell you one need not do that. Why? In any problem cease to be a just-local issue, so unhandled exceptions, fallen into a silent death of some agent will result in global impacts of missing such agent ( many ) others do rely on and may easily got blocked without any local-reason visible to 'em.

6 ) in production domain, there will be more efforts needed for protecting any smart infrastructure from remote-failures and also DoS-alike events, that impact local-Context() SPOF, so the architecture design is both very interesting and quite demanding domain.

Upvotes: 1

epinal
epinal

Reputation: 1465

Check this, you will find this:

socket zmq.REQ will block on send unless it has successfully received a reply back.

Which means that you cannot send another request until receiving an answer. ZMQ has different messaging patterns the one you are using Client / Server zmq.REQ / zmq.REP.

Any attempt to send another message to the socket (zmq.REQ/zmq.REP), without having received a reply/request will result in an error:

....
socket.send ("Hello")
socket.send ("Hello1")
....

Error: zmq.core.error.ZMQError: Operation cannot be accomplished in current state

That's why your are getting the exception:

zmq.error.ZMQError: Operation cannot be accomplished in current state

Upvotes: 0

Related Questions