def _runSends(self, timeout=None, stop_on_available=False): numsends = 0 endtime = ExpirationTimer(toTimeDeltaOrNone(timeout)) for endt in unexpired(endtime): while self._pendingSends: numsends += 1 if self.procLimit and numsends > self.procLimit: raise RuntimeError('Too many sends') self._realizeWakeups() with self._private_lock: try: nextmsg = self._pendingSends.pop(0) except IndexError: pass else: self._runSingleSend(nextmsg) if stop_on_available and \ any([not isInternalActorSystemMessage(M) for M in getattr(stop_on_available.instance, 'responses', [])]): return if endt.remaining(forever=-1) == -1: return next_wakeup = self._next_wakeup() if next_wakeup is None or next_wakeup > endt: return time.sleep( max(0, timePeriodSeconds(next_wakeup.view().remaining()))) self._realizeWakeups()
def shutdown(self): thesplog('ActorSystem shutdown requested.', level=logging.INFO) time_to_quit = ExpirationTimer(MAX_SYSTEM_SHUTDOWN_DELAY) txwatch = self._tx_to_admin(SystemShutdown()) for remaining_time in unexpired(time_to_quit): response = self._run_transport(remaining_time.remaining()) if txwatch.failed: thesplog('Could not send shutdown request to Admin' '; aborting but not necessarily stopped', level=logging.WARNING) return if isinstance(response, ReceiveEnvelope): if isinstance(response.message, SystemShutdownCompleted): break else: thesplog('Expected shutdown completed message, got: %s', response.message, level=logging.WARNING) elif isinstance(response, (Thespian__Run_Expired, Thespian__Run_Terminated, Thespian__Run_Expired)): break else: thesplog('No response to Admin shutdown request; Actor system not completely shutdown', level=logging.ERROR) self.transport.close() thesplog('ActorSystem shutdown complete.')
def ask(self, anActor, msg, timeout): txwatch = self._tx_to_actor(anActor, msg) # KWQ: pass timeout on tx?? askLimit = ExpirationTimer(toTimeDeltaOrNone(timeout)) for remTime in unexpired(askLimit): response = self._run_transport(remTime.remaining()) if txwatch.failed: if txwatch.failure in [SendStatus.DeadTarget, SendStatus.Failed, SendStatus.NotSent]: # Silent failure; not all transports can indicate # this, so for conformity the Dead Letter handler is # the intended method of handling this issue. return None raise ActorSystemFailure('Transmit of ask message to %s failed (%s)'%( str(anActor), str(txwatch.failure))) if not isinstance(response, ReceiveEnvelope): # Timed out or other failure, give up. break # Do not send miscellaneous ActorSystemMessages to the # caller that it might not recognize. If one of those was # recieved, loop to get another response. if not isInternalActorSystemMessage(response.message): return response.message return None
def tell(self, anActor, msg): attemptLimit = ExpirationTimer(MAX_TELL_PERIOD) # transport may not use sockets, but this helps error handling # in case it does. import socket for attempt in range(5000): try: txwatch = self._tx_to_actor(anActor, msg) for attemptTime in unexpired(attemptLimit): if not self._run_transport(attemptTime.remaining(), txonly=True): # all transmits completed return if txwatch.failed: raise ActorSystemFailure( 'Error sending to %s: %s' % (str(anActor), str(txwatch.failure))) raise ActorSystemRequestTimeout( 'Unable to send to %s within %s' % (str(anActor), str(MAX_TELL_PERIOD))) except socket.error as ex: import errno if errno.EMFILE == ex.errno: import time time.sleep(0.1) else: raise
def listen(self, timeout): fulltime = ExpirationTimer(timeout) for ft in unexpired(fulltime): try: response = self.my_instance.get(ft.remainingSeconds()) except Queue.Empty: break if not isInternalActorSystemMessage(response): return response return None
def unloadActorSource(self, sourceHash): loadLimit = ExpirationTimer(MAX_LOAD_SOURCE_DELAY) txwatch = self._tx_to_admin(ValidateSource(sourceHash, None)) for load_time in unexpired(loadLimit): if not self._run_transport(load_time.remaining(), txonly=True): return # all transmits completed if txwatch.failed: raise ActorSystemFailure( 'Error sending source unload to Admin: %s' % str(txwatch.failure)) raise ActorSystemRequestTimeout('Unload source timeout: ' + str(loadLimit))
def updateCapability(self, capabilityName, capabilityValue=None): attemptLimit = ExpirationTimer(MAX_CAPABILITY_UPDATE_DELAY) txwatch = self._tx_to_admin(CapabilityUpdate(capabilityName, capabilityValue)) for remaining_time in unexpired(attemptLimit): if not self._run_transport(remaining_time.remaining(), txonly=True): return # all transmits completed if txwatch.failed: raise ActorSystemFailure( 'Error sending capability updates to Admin: %s' % str(txwatch.failure)) raise ActorSystemRequestTimeout( 'Unable to confirm capability update in %s' % str(MAX_CAPABILITY_UPDATE_DELAY))
def loadActorSource(self, fname): loadLimit = ExpirationTimer(MAX_LOAD_SOURCE_DELAY) f = fname if hasattr(fname, 'read') else open(fname, 'rb') try: d = f.read() import hashlib hval = hashlib.md5(d).hexdigest() txwatch = self._tx_to_admin( ValidateSource(hval, d, getattr(f, 'name', str(fname) if hasattr(fname, 'read') else fname))) for load_time in unexpired(loadLimit): if not self._run_transport(load_time.remaining(), txonly=True): # All transmits completed return hval if txwatch.failed: raise ActorSystemFailure( 'Error sending source load to Admin: %s' % str(txwatch.failure)) raise ActorSystemRequestTimeout('Load source timeout: ' + str(loadLimit)) finally: f.close()
def drainTransmits(self): drainLimit = ExpirationTimer(MAX_SHUTDOWN_DRAIN_PERIOD) for drain_remaining_time in unexpired(drainLimit): if not self.transport.run(TransmitOnly, drain_remaining_time.remaining()): break # no transmits left