def mediate(self): """Main broker work happens here""" while True: try: items = self.poller.poll(self.HEARTBEAT_INTERVAL) except KeyboardInterrupt: break # Interrupted if items: sender, msg = serverish_recv(self.socket) if self.verbose: log.info("received message:") dump(msg) header = msg.pop(0) if (MDP.C_CLIENT == header): self.process_client(sender, msg) elif (MDP.W_WORKER == header): self.process_worker(sender, msg) else: log.error("invalid message:") dump(msg) self.purge_workers() self.send_heartbeats()
def recv(self): """Returns the reply message or None if there was no reply.""" try: items = self.poller.poll(self.timeout) except KeyboardInterrupt: return # interrupted if items: # if we got a reply, process it #msg = self.client.recv_multipart() msg = clientish_recv(self.client) if self.verbose: log.info("received reply:") dump(msg) # Don't try to handle errors, just assert noisily assert len(msg) >= 4 header = msg.pop(0) assert MDP.C_CLIENT == header service = msg.pop(0) return msg else: log.warn("permanent error, abandoning request")
def send(self, service, request): """Send request to broker """ if not isinstance(request, list): request = [request] # Prefix request with protocol frames # Frame 0: "MDPCxy" (six bytes, MDP/Client x.y) # Frame 1: Service name (printable string) request = [MDP.C_CLIENT, service] + request if self.verbose: log.warn("send request to '%s' service: ", service) dump(request) #self.client.send_multipart(request) clientish_send(self.client, request)
def process_worker(self, sender, msg): """Process message sent to us by a worker.""" assert len(msg) >= 1 # At least, command command = msg.pop(0) worker_ready = hash_sender(sender) in self.workers worker = self.require_worker(sender) if (MDP.W_READY == command): assert len(msg) >= 1 # At least, a service name service = msg.pop(0) # Not first command in session or Reserved service name if (worker_ready or service.startswith(self.INTERNAL_SERVICE_PREFIX)): self.delete_worker(worker, True) else: # Attach worker to service and mark as idle worker.service = self.require_service(service) self.worker_waiting(worker) elif (MDP.W_REPLY == command): if (worker_ready): # Remove & save client return envelope and insert the # protocol header and service name, then rewrap envelope. client = msg.pop(0) empty = msg.pop(0) # ? #msg = [client, b'', MDP.C_CLIENT, worker.service.name] + msg msg = [MDP.C_CLIENT, worker.service.name] + msg #self.socket.send_multipart(msg) serverish_send(self.socket, client, msg) self.worker_waiting(worker) else: self.delete_worker(worker, True) elif (MDP.W_HEARTBEAT == command): if (worker_ready): worker.expiry = time.time() + 1e-3 * self.HEARTBEAT_EXPIRY else: self.delete_worker(worker, True) elif (MDP.W_DISCONNECT == command): self.delete_worker(worker, False) else: log.error("invalid message:") dump(msg)
def send_to_broker(self, command, option=None, msg=None): """Send message to broker. If no msg is provided, creates one internally """ if msg is None: msg = [] elif not isinstance(msg, list): msg = [msg] if option: msg = [option] + msg #msg = [b'', MDP.W_WORKER, command] + msg msg = [MDP.W_WORKER, command] + msg if self.verbose: log.info("sending %s to broker", command) dump(msg) #self.worker.send_multipart(msg) clientish_send(self.worker, msg)
def send_to_worker(self, worker, command, option, msg=None): """Send message to worker. If message is provided, sends that message. """ if msg is None: msg = [] elif not isinstance(msg, list): msg = [msg] # Stack routing and protocol envelopes to start of message # and routing envelope if option is not None: msg = [option] + msg #msg = [worker.address, b'', MDP.W_WORKER, command] + msg msg = [MDP.W_WORKER, command] + msg if self.verbose: log.info("sending %r to worker", command) dump(msg) #self.socket.send_multipart(msg) serverish_send(self.socket, worker.address, msg)
def recv(self, reply=None): """Send reply, if any, to broker and wait for next request.""" # Format and send the reply if we were provided one assert reply is not None or not self.expect_reply if reply is not None: assert self.reply_to is not None reply = [self.reply_to, b''] + reply self.send_to_broker(MDP.W_REPLY, msg=reply) self.expect_reply = True while True: # Poll socket for a reply, with timeout try: items = self.poller.poll(self.timeout) except KeyboardInterrupt: break # Interrupted if items: #msg = self.worker.recv_multipart() msg = clientish_recv(self.worker) if self.verbose: log.info("received message from broker: ") dump(msg) self.liveness = self.HEARTBEAT_LIVENESS # Don't try to handle errors, just assert noisily assert len(msg) >= 2 header = msg.pop(0) assert header == MDP.W_WORKER command = msg.pop(0) if command == MDP.W_REQUEST: # We should pop and save as many addresses as there are # up to a null part, but for now, just save one... self.reply_to = msg.pop(0) # pop empty empty = msg.pop(0) assert empty == b'' return msg # We have a request to process elif command == MDP.W_HEARTBEAT: # Do nothing for heartbeats pass elif command == MDP.W_DISCONNECT: self.reconnect_to_broker() else : log.error("invalid input message: ") dump(msg) else: self.liveness -= 1 if self.liveness == 0: if self.verbose: log.warn("disconnected from broker - retrying...") try: time.sleep(1e-3*self.reconnect) except KeyboardInterrupt: break self.reconnect_to_broker() # Send HEARTBEAT if it's time if time.time() > self.heartbeat_at: self.send_to_broker(MDP.W_HEARTBEAT) self.heartbeat_at = time.time() + 1e-3*self.heartbeat log.warn("interrupt received, killing worker...") return None