Exemplo n.º 1
0
 def testNonZeroRemaining(self):
     et = ExpirationTimer(timedelta(milliseconds=10))
     ct = currentTime()
     assert timedelta(days=0) < et.view(ct).remaining()
     assert timedelta(milliseconds=11) > et.view(ct).remaining()
     sleep(et.view().remainingSeconds())
     assert timedelta(days=0) == et.view().remaining()
Exemplo n.º 2
0
    def run(self):
        # Main loop for convention management.  Wraps the lower-level
        # transport with a stop at the next needed convention
        # registration period to re-register.
        transport_continue = True
        try:
            while not getattr(self, 'shutdown_completed', False) and \
                  not isinstance(transport_continue, Thespian__Run_Terminated):
                ct = currentTime()
                delay = min(
                    self._cstate.convention_inattention_delay(ct),
                    ExpirationTimer(None).view(ct)
                    if self._hysteresisSender.delay.expired() else
                    self._hysteresisSender.delay)
                # n.b. delay does not account for soon-to-expire
                # pingValids, but since delay will not be longer than
                # a CONVENTION_REREGISTRATION_PERIOD, the worst case
                # is a doubling of a pingValid period (which should be fine).
                transport_continue = self.transport.run(
                    self.handleIncoming, delay.remaining())

                # Check Convention status based on the elapsed time
                self._performIO(self._cstate.check_convention())

                self._hysteresisSender.checkSends()
                self._remove_expired_sources()

        except Exception as ex:
            import traceback
            thesplog('ActorAdmin uncaught exception: %s',
                     traceback.format_exc(),
                     level=logging.ERROR,
                     exc_info=True)
        thesplog('Admin time to die', level=logging.DEBUG)
Exemplo n.º 3
0
 def _realizeWakeups(self):
     "Find any expired wakeups and queue them to the send processing queue"
     ct = currentTime()
     for target_addr, expired, payload in self._pop_expired_wakeups(ct):
         with self._private_lock:
             self._pendingSends.append(
                 PendingSend(target_addr,
                             WakeupMessage(expired.view(ct).duration, payload),
                             target_addr))
Exemplo n.º 4
0
 def _remove_expired_sources(self):
     rmvlist = []
     ct = currentTime()
     for each in self._sources:
         if not self._sources[each].source_valid and \
            self._sources[each].load_expires.view(ct).expired():
             rmvlist.append(each)
     for each in rmvlist:
         self._cancel_pending_actors(self._sources[each].pending_actors)
         del self._sources[each]
Exemplo n.º 5
0
 def _realizeWakeups(self):
     "Find any expired wakeups and queue them to the send processing queue"
     with self._wakeup_lock:
         ct = currentTime()
         starting_len = len(self._activeWakeups)
         while self._pendingWakeups and self._pendingWakeups[0][0].view(
                 ct).expired():
             timer, payload = self._pendingWakeups.pop(0)
             self._activeWakeups.append(
                 ReceiveEnvelope(self.myAddress,
                                 WakeupMessage(timer.duration, payload)))
     return starting_len != len(self._activeWakeups)
Exemplo n.º 6
0
def _common_formatStatus(tofd, response, childActorTag, showAddress=str):
    tofd.write('  |%s Actors [%d]:\n' %
               (childActorTag, len(response.childActors)))
    for A in response.childActors:
        tofd.write('    @ %s\n' % (showAddress(A)))
    if response.governer:
        tofd.write('  |Rate Governer: %s\n' % (str(response.governer)))
    tofd.write('  |Pending Messages [%d]:\n' % len(response.pendingMessages))
    for F, T, M in response.pendingMessages:
        tofd.write('    %s --> %s:  %s\n' %
                   (showAddress(F), showAddress(T), M))
    tofd.write('  |Received Messages [%d]:\n' % len(response.receivedMessages))
    for F, T, M in response.receivedMessages:
        tofd.write('    %s <-- %s:  %s\n' %
                   (showAddress(T), showAddress(F), M))

    # pendingWakeups is a dict with datetime keys and a list of
    # ReceiveEnvelope(WakeupMessage) values in older Thespian versions
    # (3.5.2 and earlier), changed to a list of (address,
    # ExpirationTimer) in newer versions.  The following maintains
    # compatibility for both.
    tofd.write('  |Pending Wakeups [%d]:\n' % len(response.pendingWakeups))
    from thespian.system.timing import currentTime
    from datetime import datetime
    now = datetime.now()
    ct = currentTime()
    pw = [(('' if V.sender == getattr(response, 'actorAddress', None)
            else '--> %s : ' % V.sender),
           '%s  (in %s  @  %s)' % (V.message.delayPeriod, str(A - now), str(A)))
          for A in response.pendingWakeups
          for V in response.pendingWakeups[A]] \
         if isinstance(response.pendingWakeups, dict) else \
            [(('' if A == getattr(response, 'actorAddress', None)
               else '--> %s : ' % A),
              '%s  (in %s @ %s)' % (W.view(ct).duration, W.view(ct).remaining(),
                                       str(now + W.view(ct).remaining())))
             for (A,W) in response.pendingWakeups]
    for each in pw:
        tofd.write('    %s%s\n' % each)

    tofd.write('  |Pending Address Resolution [%d]:\n' %
               (len(response._pendingAddrCnts)))
    for A in response._pendingAddrCnts:
        tofd.write('    %s: %s\n' % (A, response._pendingAddrCnts[A]))
    if response.miscKeyVals:
        miscKeys = list(response.miscKeyVals.keys())
        miscKeys.sort()
        # Adjust all output for the longest value... up to 40 characters max
        maxValLen = min(40,
                        max(map(len, map(str, response.miscKeyVals.values()))))
        for K in miscKeys:
            tofd.write('  |> %%%ds - %%s\n' % maxValLen %
                       (str(response.miscKeyVals[K]), K))
Exemplo n.º 7
0
 def check_convention(self):
     ct = currentTime()
     rmsgs = []
     if self._has_been_activated:
         rmsgs = foldl(lambda x, y: x + y,
                       [self._check_preregistered_ping(ct, member)
                        for member in self._conventionMembers.values()],
                       self._convention_leader_checks(ct)
                       if self.isConventionLeader() or
                       not self.conventionLeaderAddr else
                       self._convention_member_checks(ct))
     if self._conventionRegistration.view(ct).expired():
         self._conventionRegistration = ExpirationTimer(CONVENTION_REREGISTRATION_PERIOD)
     return rmsgs
Exemplo n.º 8
0
 def delay(self, current_time=None):
     ct = current_time or currentTime()
     qt = self._quitTime.view(ct)
     if getattr(self, '_awaitingTXSlot', False):
         if qt.expired():
             return timedelta(seconds=0)
         return max(timedelta(milliseconds=10), (qt.remaining()) / 2)
     return max(
         timedelta(seconds=0),
         min(
             qt.remaining(),
             getattr(self, '_retryTime',
                     self._quitTime).view(ct).remaining(),
             getattr(self, '_pauseUntil',
                     self._quitTime).view(ct).remaining()))
Exemplo n.º 9
0
    def forward_pending_to_remote_system(self, childClass, envelope,
                                         sourceHash, acceptsCaps):
        alreadyTried = getattr(envelope.message, 'alreadyTried', [])
        ct = currentTime()
        if self.myAddress not in alreadyTried:
            # Don't send request back to this actor system: it cannot
            # handle it
            alreadyTried.append(self.myAddress)

        remoteCandidates = [
            K for K in self._conventionMembers.values()
            if not K.registryValid.view(ct).expired()
            and K.remoteAddress != envelope.sender  # source Admin
            and K.remoteAddress not in alreadyTried
            and acceptsCaps(K.remoteCapabilities)
        ]

        if not remoteCandidates:
            if self.isConventionLeader() or not self.conventionLeaderAddr:
                raise NoCompatibleSystemForActor(
                    childClass, 'No known ActorSystems can handle a %s for %s',
                    childClass, envelope.message.forActor)
            # Let the Convention Leader try to find an appropriate ActorSystem
            bestC = self.conventionLeaderAddr
        else:
            # distribute equally amongst candidates
            C = [(K.remoteAddress, len(K.hasRemoteActors))
                 for K in remoteCandidates]
            bestC = foldl(
                lambda best, possible: best
                if best[1] <= possible[1] else possible, C)[0]
            thesplog('Requesting creation of %s%s on remote admin %s',
                     envelope.message.actorClassName,
                     ' (%s)' % sourceHash if sourceHash else '', bestC)
        if bestC in alreadyTried:
            return []  # Have to give up, no-one can handle this

        # Don't send request to this remote again, it has already
        # been tried.  This would also be indicated by that system
        # performing the add of self.myAddress as below, but if
        # there is disagreement between the local and remote
        # addresses, this addition will prevent continual
        # bounceback.
        alreadyTried.append(bestC)
        envelope.message.alreadyTried = alreadyTried
        return [TransmitIntent(bestC, envelope.message)]
Exemplo n.º 10
0
    def _runWithExpiry(self, incomingHandler):
        if incomingHandler == TransmitOnly or \
           isinstance(incomingHandler, TransmitOnly):
            # transmits are not queued/multistage in this transport, no waiting
            return 0

        self._aborting_run = None

        while self._aborting_run is None:
            ct = currentTime()
            if self.run_time.view(ct).expired():
                break
            if self._checkChildren:
                self._checkChildren = False
                rcvdEnv = ReceiveEnvelope(self.myAddress, ChildMayHaveDied())
            elif self._shutdownSignalled:
                self._shutdownSignalled = False
                rcvdEnv = ReceiveEnvelope(self.myAddress, ActorExitRequest())
            elif self._rcvd:
                rcvdEnv = self._rcvd.pop()
            else:
                next_action_timeout = self.check_pending_actions(ct)
                try:
                    sresp, _ign1, _ign2 = select.select(
                        [self.socket.fileno()], [], [],
                        min(self.run_time,
                            next_action_timeout).view(ct).remainingSeconds())
                except (OSError, select.error) as se:
                    errnum = getattr(se, 'errno', se.args[0])
                    if err_select_retry(errnum):
                        thesplog('UDP select retry on %s',
                                 se,
                                 level=logging.DEBUG)
                        continue
                    thesplog('Error during UDP select: %s',
                             se,
                             level=logging.CRITICAL)
                    return Thespian__Run_Errored(se)
                except ValueError:
                    # self.run_time can expire between the while test
                    # and the use in the select statement.
                    continue

                if [] == sresp:
                    if [] == _ign1 and [] == _ign2:
                        # Timeout, give up
                        return Thespian__Run_Expired()
                    thesplog('Waiting for read event, but got %s %s',
                             _ign1,
                             _ign2,
                             level=logging.WARNING)
                    continue
                rawmsg, sender = self.socket.recvfrom(65535)
                if rawmsg == b'BuMP':
                    if self._checkChildren or self._shutdownSignalled:
                        continue
                    return Thespian__UpdateWork()
                else:
                    sendAddr = ActorAddress(
                        UDPv4ActorAddress(*sender, external=True))
                    try:
                        msg = serializer.loads(rawmsg)
                    except Exception:
                        continue
                rcvdEnv = ReceiveEnvelope(sendAddr, msg)
            if incomingHandler is None:
                return rcvdEnv
            r = Thespian__Run_HandlerResult(incomingHandler(rcvdEnv))
            if not r:
                # handler returned false-ish, indicating run() should exit
                return r

        if self._aborting_run is not None:
            return self._aborting_run

        return Thespian__Run_Expired()