async def async_request(self, command, args=None, timeout=None, req_meta=None): """Send an asynchronous request using asyncio. Has the same arguments and return values as ``serial_request``. """ timeout = (float(timeout) * 1000 if timeout else None) or self.timeout if not args: args = {} # Note: we are using CurveZMQ to secure the messages (see # self.curve_auth, self.socket.curve_...key etc.). We have set up # public-key cryptography on the ZMQ messaging and sockets, so # there is no need to encrypt messages ourselves before sending. # send message msg = {'command': command, 'args': args} msg.update(self.header) # add the request metadata if req_meta: msg['meta'].update(req_meta) LOG.debug('zmq:send %s', msg) message = encode_(msg) self.socket.send_string(message) # receive response if self.poller.poll(timeout): res = await self.socket.recv() else: if callable(self.timeout_handler): self.timeout_handler() raise ClientTimeout( 'Timeout waiting for server response.' ' This could be due to network or server issues.' ' Check the workflow log.') if msg['command'] in PB_METHOD_MAP: response = {'data': res} else: response = decode_(res.decode()) LOG.debug('zmq:recv %s', response) try: return response['data'] except KeyError: error = response['error'] raise ClientError(error['message'], error.get('traceback'))
def _listener(self): """The server main loop, listen for and serve requests.""" while True: # process any commands passed to the listener by its parent process if self.queue.qsize(): command = self.queue.get() if command == 'STOP': break raise ValueError('Unknown command "%s"' % command) try: # wait RECV_TIMEOUT for a message msg = self.socket.recv_string() except zmq.error.Again: # timeout, continue with the loop, this allows the listener # thread to stop continue except zmq.error.ZMQError as exc: LOG.exception('unexpected error: %s', exc) continue # attempt to decode the message, authenticating the user in the # process try: message = decode_(msg) except Exception as exc: # purposefully catch generic exception # failed to decode message, possibly resulting from failed # authentication LOG.exception('failed to decode message: "%s"', exc) else: # success case - serve the request res = self._receiver(message) if message['command'] in PB_METHOD_MAP: response = res['data'] else: response = encode_(res).encode() # send back the string to bytes response self.socket.send(response) # Note: we are using CurveZMQ to secure the messages (see # self.curve_auth, self.socket.curve_...key etc.). We have set up # public-key cryptography on the ZMQ messaging and sockets, so # there is no need to encrypt messages ourselves before sending. sleep(0) # yield control to other threads