def core_common_transmit(self, transmit_intent, from_addr):
        try:
            if self.isMyAddress(transmit_intent.targetAddr):
                if transmit_intent.message:
                    self._myInputQ.put( (from_addr, transmit_intent.serMsg),
                                        True,
                                        timePeriodSeconds(transmit_intent.delay()))
            else:
                tgtQ = self._queues.find(transmit_intent.targetAddr)
                if tgtQ:
                    tgtQ.put((from_addr, transmit_intent.serMsg), True,
                             timePeriodSeconds(transmit_intent.delay()))
                else:
                    # None means sent by parent, so don't send BACK to parent if unknown
                    topOrFromBelow = from_addr if self._parentQ else None
                    (self._parentQ or self._adminQ).put(
                        (topOrFromBelow, transmit_intent.serMsg),
                        True,
                        timePeriodSeconds(transmit_intent.delay()))

            transmit_intent.tx_done(SendStatus.Sent)
            return
        except Q.Full:
            pass
        transmit_intent.tx_done(SendStatus.DeadTarget if not isinstance(
            transmit_intent._message,
            (ChildActorExited, ActorExitRequest)) else SendStatus.Failed)
    def _scheduleTransmitActual(self, transmitIntent):
        try:
            if transmitIntent.targetAddr == self.myAddress:
                if transmitIntent.message:
                    self._myInputQ.put( (self._myQAddress, transmitIntent.serMsg), True,
                                        timePeriodSeconds(transmitIntent.delay()))
            else:
                tgtQ = self._queues.find(transmitIntent.targetAddr)
                if tgtQ:
                    tgtQ.put((self._myQAddress, transmitIntent.serMsg), True,
                             timePeriodSeconds(transmitIntent.delay()))
                else:
                    # None means sent by parent, so don't send BACK to parent if unknown
                    topOrFromBelow = self._myQAddress if self._parentQ else None
                    (self._parentQ or self._adminQ).put(
                        (topOrFromBelow, transmitIntent.serMsg),
                        True,
                        timePeriodSeconds(transmitIntent.delay()))

            transmitIntent.tx_done(SendStatus.Sent)
            return
        except Q.Full:
            pass
        transmitIntent.tx_done(SendStatus.DeadTarget if not isinstance(
            transmitIntent._message,
            (ChildActorExited, ActorExitRequest)) else SendStatus.Failed)
        thesplog('Q.Full %s to %s result %s', transmitIntent._message, transmitIntent.targetAddr, transmitIntent.result)
    def core_common_transmit(self, transmit_intent, from_addr):
        try:
            if self.isMyAddress(transmit_intent.targetAddr):
                if transmit_intent.message:
                    self._myInputQ.put(
                        (from_addr, transmit_intent.serMsg), True,
                        timePeriodSeconds(transmit_intent.delay()))
            else:
                tgtQ = self._queues.find(transmit_intent.targetAddr)
                if tgtQ:
                    tgtQ.put((from_addr, transmit_intent.serMsg), True,
                             timePeriodSeconds(transmit_intent.delay()))
                else:
                    # None means sent by parent, so don't send BACK to parent if unknown
                    topOrFromBelow = from_addr if self._parentQ else None
                    (self._parentQ or self._adminQ).put(
                        (topOrFromBelow, transmit_intent.serMsg), True,
                        timePeriodSeconds(transmit_intent.delay()))

            transmit_intent.tx_done(SendStatus.Sent)
            return
        except Q.Full:
            pass
        transmit_intent.tx_done(
            SendStatus.DeadTarget if not isinstance(transmit_intent._message, (
                ChildActorExited, ActorExitRequest)) else SendStatus.Failed)
Example #4
0
 def _runSends(self, timeout=None, stop_on_available=False):
     numsends = 0
     endtime = ((datetime.now() +
                 toTimeDeltaOrNone(timeout)) if timeout else None)
     while not endtime or datetime.now() < endtime:
         while self._pendingSends:
             numsends += 1
             if self.procLimit and numsends > self.procLimit:
                 raise RuntimeError('Too many sends')
             self._realizeWakeups()
             self._runSingleSend(self._pendingSends.pop(0))
             if stop_on_available and \
                any([not isInternalActorSystemMessage(M)
                     for M in getattr(stop_on_available.instance,
                                      'responses', [])]):
                 return
         if not endtime:
             return
         now = datetime.now()
         valid_wakeups = [(W - now) for W in self._wakeUps if W <= endtime]
         if not valid_wakeups:
             return
         import time
         time.sleep(max(0, timePeriodSeconds(min(valid_wakeups))))
         self._realizeWakeups()
Example #5
0
 def _runSends(self, timeout=None, stop_on_available=False):
     numsends = 0
     endtime = ExpirationTimer(toTimeDeltaOrNone(timeout))
     while not endtime.expired():
         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 endtime.remaining(forever=-1) == -1:
             return
         next_wakeup = self._next_wakeup()
         if next_wakeup is None or next_wakeup > endtime:
             return
         time.sleep(max(0, timePeriodSeconds(next_wakeup.remaining())))
         self._realizeWakeups()
Example #6
0
 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()
Example #7
0
 def testOverMax__expected_duration_is_21_seconds(self):
     # The rate limiter allows bursts.. the bigger cnt is the
     # closer to the actual limit the result will be, but the
     # longer the test will take.
     cnt = 300
     tt = send_at_rate(10, 100, cnt)
     print('send_at_rate(10, 100, %s) --> %s' % (cnt, str(tt)))
     actRate = cnt / timePeriodSeconds(tt)
     assert 15 > actRate  # add a little buffer for overage... just a little
Example #8
0
 def testOverMax__expected_duration_is_21_seconds(self):
     # The rate limiter allows bursts.. the bigger cnt is the
     # closer to the actual limit the result will be, but the
     # longer the test will take.
     cnt = 300
     tt = send_at_rate(10, 100, cnt)
     print('send_at_rate(10, 100, %s) --> %s'%(cnt, str(tt)))
     actRate = cnt / timePeriodSeconds(tt)
     assert 15 > actRate  # add a little buffer for overage... just a little
Example #9
0
    def eventRatePause(self):
        """This is the main method that should be called each time an event is
           to occur.  It will block internally until it is time for
           the next event to occur.
        """
        if not hasattr(self, '_curRate'):
            self._runningCount += 1

            # runningCount is the total # since the last time it was
            # zeroed, so it's not just wthin the last second, but it does
            # provide a threshold above which the actual rate should be
            # observed and possibly throttled.  This will begin to take an
            # interest in the actual rate when the runningCount reaches an
            # arbitrary 70% of the maximum rate.
            if self._runningCount < (self._maxRate * 0.70):
                return

            self._curRate = 0
            self._timeMark = datetime.now()
            self._goodMarks = 0
            return

        self._curRate += 1
        newT = datetime.now()
        deltaT = newT - self._timeMark

        if deltaT < timedelta(seconds=1):
            return

        rate = self._curRate / timePeriodSeconds(deltaT)

        if rate > self._maxRate:
            # Slow down a little
            delay(0.1)
            self._goodMarks = 0
            return

        self._goodMarks += 1
        if self._goodMarks > self._maxRate:
            delattr(self, '_curRate')
            self._runningCount = 0
            return
Example #10
0
    def eventRatePause(self):
        """This is the main method that should be called each time an event is
           to occur.  It will block internally until it is time for
           the next event to occur.
        """
        if not hasattr(self, '_curRate'):
            self._runningCount += 1

            # runningCount is the total # since the last time it was
            # zeroed, so it's not just wthin the last second, but it does
            # provide a threshold above which the actual rate should be
            # observed and possibly throttled.  This will begin to take an
            # interest in the actual rate when the runningCount reaches an
            # arbitrary 70% of the maximum rate.
            if self._runningCount < (self._maxRate * 0.70):
                return

            self._curRate = 0
            self._timeMark = Timer()
            self._goodMarks = 0
            return

        self._curRate += 1
        deltaT = self._timeMark.elapsed()

        if deltaT < timedelta(seconds=1):
            return

        rate = self._curRate / timePeriodSeconds(deltaT)

        if rate > self._maxRate:
            # Slow down a little
            delay(0.1)
            self._goodMarks = 0
            return

        self._goodMarks += 1
        if self._goodMarks > self._maxRate:
            delattr(self, '_curRate')
            self._runningCount = 0
            return
    def core_common_receive(self, incoming_handler, for_local_addr, run_time_f):
        """Core scheduling method; called by the current Actor process when
           idle to await new messages (or to do background
           processing).
        """
        if incoming_handler == TransmitOnly or \
           isinstance(incoming_handler, TransmitOnly):
            # transmits are not queued/multistage in this transport, no waiting
            return 0

        self._aborting_run = False

        while not run_time_f().expired() and not self._aborting_run:
            try:
                # Unfortunately, the Queue object is not signal-safe,
                # so a frequent wakeup is needed to check
                # _checkChildren and _shutdownSignalled.
                rcvd = self._myInputQ.get(True,
                                          min(run_time_f().remainingSeconds() or
                                              QUEUE_CHECK_PERIOD,
                                              QUEUE_CHECK_PERIOD))
            except Q.Empty:
                if not self._checkChildren and not self._shutdownSignalled:
                    # Probably a timeout, but let the while loop decide for sure
                    continue
                rcvd = 'BuMP'
            if rcvd == 'BuMP':
                relayAddr = sendAddr = destAddr = for_local_addr
                if self._checkChildren:
                    self._checkChildren = False
                    msg = ChildMayHaveDied()
                elif self._shutdownSignalled:
                    self._shutdownSignalled = False
                    msg = ActorExitRequest()
                else:
                    return Thespian__UpdateWork()
            else:
                relayAddr, (sendAddr, destAddr, msg) = rcvd
            if not self._queues.find(sendAddr):
                # We don't directly know about this sender, so
                # remember what path this arrived on to know where to
                # direct future messages for this sender.
                if relayAddr and self._queues.find(relayAddr) and \
                   not self._fwdvia.find(sendAddr):
                    # relayAddr might be None if it's our parent, which is OK because
                    # the default message forwarding is to the parent.  If it's not
                    # none, it should be in self._queues though!
                    self._fwdvia.add(sendAddr, relayAddr)
            if hasattr(self, '_addressMgr'):
                destAddr,msg = self._addressMgr.prepMessageSend(destAddr, msg)
            if destAddr is None:
                thesplog('Unexpected target inaccessibility for %s', msg,
                         level = logging.WARNING)
                raise CannotPickleAddress(destAddr)

            if msg is SendStatus.DeadTarget:
                thesplog('Faking message "sent" because target is dead and recursion avoided.')
                continue

            if self.isMyAddress(destAddr):
                if incoming_handler is None:
                    return ReceiveEnvelope(sendAddr, msg)
                r = incoming_handler(ReceiveEnvelope(sendAddr, msg))
                if not r:
                    return r  # handler returned False, indicating run() should exit
            else:
                # Note: the following code has implicit knowledge of serialize() and xmit
                putQValue = lambda relayer: (relayer, (sendAddr, destAddr, msg))
                deadQValue = lambda relayer: (relayer, (sendAddr,
                                                        self._adminAddr,
                                                        DeadEnvelope(destAddr, msg)))
                # Must forward this packet via a known forwarder or our parent.
                send_dead = False
                tgtQ = self._queues.find(destAddr)
                if tgtQ:
                    sendArgs = putQValue(for_local_addr), True
                if not tgtQ:
                    tgtA = self._fwdvia.find(destAddr)
                    if tgtA:
                        tgtQ = self._queues.find(tgtA)
                        sendArgs = putQValue(None),
                    else:
                        for each in self._deadaddrs:
                            if destAddr == each:
                                send_dead = True
                if tgtQ:
                    try:
                        tgtQ.put(*sendArgs,
                                 timeout=timePeriodSeconds(MAX_QUEUE_TRANSMIT_PERIOD))
                        continue
                    except Q.Full:
                        thesplog('Unable to send msg %s to dest %s; dead lettering',
                                 msg, destAddr)
                        send_dead = True
                if send_dead:
                    try:
                        (self._parentQ or self._adminQ).put(
                            deadQValue(for_local_addr if self._parentQ else None),
                            True,
                            timePeriodSeconds(MAX_QUEUE_TRANSMIT_PERIOD))
                    except Q.Full:
                        thesplog('Unable to send deadmsg %s to %s or admin; discarding',
                                 msg, destAddr)
                    continue

                # Not sure how to route this message yet.  It
                # could be a heretofore silent child of one of our
                # children, it could be our parent (whose address
                # we don't know), or it could be elsewhere in the
                # tree.
                #
                # Try sending it to the parent first.  If the
                # parent can't determine the routing, it will be
                # sent back down (relayAddr will be None in that
                # case) and it must be sprayed out to all children
                # in case the target lives somewhere beneath us.
                # Note that _parentQ will be None for top-level
                # actors, which send up to the Admin instead.
                #
                # As a special case, the external system is the
                # parent of the admin, but the admin is the
                # penultimate parent of all others, so this code
                # must keep the admin and the parent from playing
                # ping-pong with the message.  But... the message
                # might be directed to the external system, which
                # is the parent of the Admin, so we need to check
                # with it first.
                #   parentQ == None but adminQ good --> external
                #   parentQ and adminQ and myAddress == adminAddr --> Admin
                #   parentQ and adminQ and myAddress != adminADdr --> other Actor

                if relayAddr:
                    # Send message up to the parent to see if the
                    # parent knows how to forward it
                    try:
                        (self._parentQ or self._adminQ).put(
                            putQValue(for_local_addr if self._parentQ else None),
                            True,
                            timePeriodSeconds(MAX_QUEUE_TRANSMIT_PERIOD))
                    except Q.Full:
                        thesplog('Unable to send dead msg %s to %s or admin; discarding',
                                 msg, destAddr)
                else:
                    # Sent by parent or we are an external, so this
                    # may be some grandchild not currently known.
                    # Do the worst case and just send this message
                    # to ALL immediate children, hoping it will
                    # get there via some path.
                    for A,AQ in self._queues.items():
                        if A not in [self._adminAddr, str(self._adminAddr)]:
                            # None means sent by Parent, so don't
                            # send BACK to parent if unknown
                            try:
                                AQ.put(putQValue(None),
                                       True,
                                       timePeriodSeconds(MAX_QUEUE_TRANSMIT_PERIOD))
                            except Q.Full:
                                pass
        return None
Example #12
0
 def testSlow__expected_duration_is_20_seconds(self):
     cnt = 10
     tt = send_at_rate(10, 0.5, cnt)
     print('send_at_rate(10, 0.5, %s) --> %s'%(cnt, str(tt)))
     actRate = cnt / timePeriodSeconds(tt)
     assert 10 > actRate
Example #13
0

def unstable_test(asys, *unstable_bases):
    if asys.base_name in unstable_bases and \
       not pytest.config.getoption('unstable', default=False):
        pytest.skip("Test unstable for %s system base"%asys.base_name)


def actor_system_unsupported(asys, *unsupported_bases):
    if asys.base_name in unsupported_bases:
        pytest.skip("Functionality not supported for %s system base"%asys.base_name)


from thespian.system.timing import timePeriodSeconds
import time

inTestDelay = lambda period: time.sleep(timePeriodSeconds(period))


def delay_for_next_of_kin_notification(system):
    if system.base_name == 'multiprocQueueBase':
        # The multiprocQueueBase signal processor cannot interrupt a
        # sleeping Queue.get(), so for this base it is necessary to
        # wait for the timeout on the Queue.get() to allow it time to
        # notice and process the child exit.
        time.sleep(2.5)
    elif system.base_name == 'multiprocUDPBase':
        time.sleep(0.6)
    else:
        time.sleep(0.1)
Example #14
0
 def testNearMax__expected_duration_is_11_seconds(self):
     cnt = 100
     tt = send_at_rate(10, 9, cnt)
     print('send_at_rate(10, 9, %s) --> %s'%(cnt, str(tt)))
     actRate = cnt / timePeriodSeconds(tt)
     assert 10 > actRate
Example #15
0
        assert 10 > actRate

    def testOverMax__expected_duration_is_21_seconds(self):
        # The rate limiter allows bursts.. the bigger cnt is the
        # closer to the actual limit the result will be, but the
        # longer the test will take.
        cnt = 300
        tt = send_at_rate(10, 100, cnt)
        print('send_at_rate(10, 100, %s) --> %s' % (cnt, str(tt)))
        actRate = cnt / timePeriodSeconds(tt)
        assert 15 > actRate  # add a little buffer for overage... just a little

    def testSlow__expected_duration_is_20_seconds(self):
        cnt = 10
        tt = send_at_rate(10, 0.5, cnt)
        print('send_at_rate(10, 0.5, %s) --> %s' % (cnt, str(tt)))
        actRate = cnt / timePeriodSeconds(tt)
        assert 10 > actRate


if __name__ == "__main__":
    for ar in [5, 9, 0.2, 100]:
        #cnt = 10 * ar     # this way all return 10 s unless rate limited
        cnt = 1000 if ar > 10 else (
            50 if ar >= 1 else 5
        )  # this way see time taken for const # of inputs
        tt = send_at_rate(10, ar, cnt)
        actRate = cnt / timePeriodSeconds(tt)
        print('send_at_rate(10, %s, %s) --> %s, rate=%s' %
              (str(ar), str(cnt), str(tt), actRate))
Example #16
0
 def testNearMax__expected_duration_is_11_seconds(self):
     cnt = 100
     tt = send_at_rate(10, 9, cnt)
     print('send_at_rate(10, 9, %s) --> %s' % (cnt, str(tt)))
     actRate = cnt / timePeriodSeconds(tt)
     assert 10 > actRate
Example #17
0
        print('send_at_rate(10, 9, %s) --> %s'%(cnt, str(tt)))
        actRate = cnt / timePeriodSeconds(tt)
        assert 10 > actRate

    def testOverMax__expected_duration_is_21_seconds(self):
        # The rate limiter allows bursts.. the bigger cnt is the
        # closer to the actual limit the result will be, but the
        # longer the test will take.
        cnt = 300
        tt = send_at_rate(10, 100, cnt)
        print('send_at_rate(10, 100, %s) --> %s'%(cnt, str(tt)))
        actRate = cnt / timePeriodSeconds(tt)
        assert 15 > actRate  # add a little buffer for overage... just a little

    def testSlow__expected_duration_is_20_seconds(self):
        cnt = 10
        tt = send_at_rate(10, 0.5, cnt)
        print('send_at_rate(10, 0.5, %s) --> %s'%(cnt, str(tt)))
        actRate = cnt / timePeriodSeconds(tt)
        assert 10 > actRate


if __name__ == "__main__":
    for ar in [5, 9, 0.2, 100]:
        #cnt = 10 * ar     # this way all return 10 s unless rate limited
        cnt = 1000 if ar > 10 else (50 if ar >= 1 else 5)   # this way see time taken for const # of inputs
        tt = send_at_rate(10, ar, cnt)
        actRate = cnt / timePeriodSeconds(tt)
        print('send_at_rate(10, %s, %s) --> %s, rate=%s'%(str(ar), str(cnt), str(tt), actRate))

Example #18
0
def update_elapsed_time(time_base, elapsed):
    with patch('thespian.system.timing.currentTime') as p_ctime:
        p_ctime.return_value = time_base + (timePeriodSeconds(
            elapsed) if isinstance(elapsed, timedelta) else elapsed)
        yield p_ctime.return_value
import pytest
from pytest import raises
from thespian.test import *
import time
from thespian.actors import *
from datetime import timedelta
from thespian.system.timing import timePeriodSeconds


MAX_ASK_WAIT_PERIOD = timedelta(seconds=7)
UPDATE_WAIT_PERIOD = timedelta(milliseconds=300)
EXIT_WAIT_PERIOD = timedelta(milliseconds=500)


update_wait = lambda: time.sleep(timePeriodSeconds(UPDATE_WAIT_PERIOD))
exit_wait = lambda: time.sleep(timePeriodSeconds(EXIT_WAIT_PERIOD))



colors = ['Red', 'Blue', 'Green', 'Yellow']

class SetCap(object):
    def __init__(self, capName, capValue):
        self.capName = capName
        self.capValue = capValue


class ColorActorBase(Actor):
    """This actor has a particular color (identified by self.color), and
       requires that color to be a capability of the ActorSystem it runs in.
Example #20
0
def unstable_test(asys, *unstable_bases):
    if asys.base_name in unstable_bases and \
       not pytest.config.getoption('unstable', default=False):
        pytest.skip("Test unstable for %s system base" % asys.base_name)


def actor_system_unsupported(asys, *unsupported_bases):
    if asys.base_name in unsupported_bases:
        pytest.skip("Functionality not supported for %s system base" %
                    asys.base_name)


from thespian.system.timing import timePeriodSeconds
import time

inTestDelay = lambda period: time.sleep(timePeriodSeconds(period))


def delay_for_next_of_kin_notification(system):
    if system.base_name == 'multiprocQueueBase':
        # The multiprocQueueBase signal processor cannot interrupt a
        # sleeping Queue.get(), so for this base it is necessary to
        # wait for the timeout on the Queue.get() to allow it time to
        # notice and process the child exit.
        time.sleep(2.5)
    elif system.base_name == 'multiprocUDPBase':
        time.sleep(0.6)
    else:
        time.sleep(0.1)
Example #21
0
 def testSlow__expected_duration_is_20_seconds(self):
     cnt = 10
     tt = send_at_rate(10, 0.5, cnt)
     print('send_at_rate(10, 0.5, %s) --> %s' % (cnt, str(tt)))
     actRate = cnt / timePeriodSeconds(tt)
     assert 10 > actRate
Example #22
0
def update_elapsed_time(time_base, elapsed):
    with patch('thespian.system.timing.currentTime') as p_ctime:
        p_ctime.return_value = time_base + (timePeriodSeconds(elapsed)
                                            if isinstance(elapsed, timedelta)
                                            else elapsed)
        yield p_ctime.return_value
    def _runWithExpiry(self, incomingHandler):
        """Core scheduling method; called by the current Actor process when
           idle to await new messages (or to do background
           processing).
        """
        if incomingHandler == TransmitOnly or \
           isinstance(incomingHandler, TransmitOnly):
            # transmits are not queued/multistage in this transport, no waiting
            return 0

        self._aborting_run = False

        while not self.run_time.expired() and not self._aborting_run:
            try:
                rcvd = self._myInputQ.get(True, self.run_time.remainingSeconds())
            except Q.Empty:
                # Probably a timeout, but let the while loop decide for sure
                continue
            if rcvd == 'BuMP':
                return Thespian__UpdateWork()
            relayAddr, (sendAddr, destAddr, msg) = rcvd
            if not self._queues.find(sendAddr):
                # We don't directly know about this sender, so
                # remember what path this arrived on to know where to
                # direct future messages for this sender.
                if relayAddr and self._queues.find(relayAddr) and \
                   not self._fwdvia.find(sendAddr):
                    # relayAddr might be None if it's our parent, which is OK because
                    # the default message forwarding is to the parent.  If it's not
                    # none, it should be in self._queues though!
                    self._fwdvia.add(sendAddr, relayAddr)
            if hasattr(self, '_addressMgr'):
                destAddr,msg = self._addressMgr.prepMessageSend(destAddr, msg)
            if destAddr is None:
                thesplog('Unexpected target inaccessibility for %s', msg,
                         level = logging.WARNING)
                raise CannotPickleAddress(destAddr)

            if msg is SendStatus.DeadTarget:
                thesplog('Faking message "sent" because target is dead and recursion avoided.')
                continue

            if destAddr == self._myQAddress:
                if incomingHandler is None:
                    return ReceiveEnvelope(sendAddr, msg)
                if not incomingHandler(ReceiveEnvelope(sendAddr, msg)):
                    return  # handler returned False, indicating run() should exit
            else:
                # Note: the following code has implicit knowledge of serialize() and xmit
                putQValue = lambda relayer: (relayer, (sendAddr, destAddr, msg))
                deadQValue = lambda relayer: (relayer, (sendAddr,
                                                        self._adminAddr,
                                                        DeadEnvelope(destAddr, msg)))
                # Must forward this packet via a known forwarder or our parent.
                tgtQ = self._queues.find(destAddr)
                if tgtQ:
                    sendArgs = putQValue(self.myAddress), True
                if not tgtQ:
                    tgtA = self._fwdvia.find(destAddr)
                    if tgtA:
                        tgtQ = self._queues.find(tgtA)
                        sendArgs = putQValue(None),
                if tgtQ:
                    try:
                        tgtQ.put(*sendArgs,
                                 timeout=timePeriodSeconds(MAX_QUEUE_TRANSMIT_PERIOD))
                    except Q.Full:
                        thesplog('Unable to send msg %s to dest %s; dead lettering',
                                 msg, destAddr)
                        try:
                            (self._parentQ or self._adminQ).put(
                                deadQValue(self.myAddress if self._parentQ else None),
                                True,
                                timePeriodSeconds(MAX_QUEUE_TRANSMIT_PERIOD))
                        except Q.Full:
                            thesplog('Unable to send deadmsg %s to %s or admin; discarding',
                                     msg, destAddr)
                else:
                    # Not sure how to route this message yet.  It
                    # could be a heretofore silent child of one of our
                    # children, it could be our parent (whose address
                    # we don't know), or it could be elsewhere in the
                    # tree.
                    #
                    # Try sending it to the parent first.  If the
                    # parent can't determine the routing, it will be
                    # sent back down (relayAddr will be None in that
                    # case) and it must be sprayed out to all children
                    # in case the target lives somewhere beneath us.
                    # Note that _parentQ will be None for top-level
                    # actors, which send up to the Admin instead.
                    #
                    # As a special case, the external system is the
                    # parent of the admin, but the admin is the
                    # penultimate parent of all others, so this code
                    # must keep the admin and the parent from playing
                    # ping-pong with the message.  But... the message
                    # might be directed to the external system, which
                    # is the parent of the Admin, so we need to check
                    # with it first.
                    #   parentQ == None but adminQ good --> external
                    #   parentQ and adminQ and myAddress == adminAddr --> Admin
                    #   parentQ and adminQ and myAddress != adminADdr --> other Actor

                    if relayAddr:
                        # Send message up to the parent to see if the
                        # parent knows how to forward it
                        try:
                            (self._parentQ or self._adminQ).put(
                                putQValue(self.myAddress if self._parentQ else None),
                                True,
                                timePeriodSeconds(MAX_QUEUE_TRANSMIT_PERIOD))
                        except Q.Full:
                            thesplog('Unable to send dead msg %s to %s or admin; discarding',
                                     msg, destAddr)
                    else:
                        # Sent by parent or we are an external, so this
                        # may be some grandchild not currently known.
                        # Do the worst case and just send this message
                        # to ALL immediate children, hoping it will
                        # get there via some path.
                        for A,AQ in self._queues.items():
                            if A not in [self._adminAddr, str(self._adminAddr)]:
                                # None means sent by Parent, so don't
                                # send BACK to parent if unknown
                                try:
                                    AQ.put(putQValue(None),
                                           True,
                                           timePeriodSeconds(MAX_QUEUE_TRANSMIT_PERIOD))
                                except Q.Full:
                                    pass
        return None
Example #24
0
systems (which should not be an issue under normal operations).
"""

import pytest
from pytest import raises
from thespian.test import *
import time
from thespian.actors import *
from datetime import timedelta
from thespian.system.timing import timePeriodSeconds

MAX_ASK_WAIT_PERIOD = timedelta(seconds=7)
UPDATE_WAIT_PERIOD = timedelta(milliseconds=300)
EXIT_WAIT_PERIOD = timedelta(milliseconds=500)

update_wait = lambda: time.sleep(timePeriodSeconds(UPDATE_WAIT_PERIOD))
exit_wait = lambda: time.sleep(timePeriodSeconds(EXIT_WAIT_PERIOD))

colors = ['Red', 'Blue', 'Green', 'Yellow']


class SetCap(object):
    def __init__(self, capName, capValue):
        self.capName = capName
        self.capValue = capValue


class GetCaps(object):
    def __init__(self):
        self.caps = None
        self.reqs = None
Example #25
0
def report(what, sysBase, elapsed, nMessages, nActors):
    print('%3d Actors, %29s %29s -- %s -- %5.2f/sec overall -- %7.2f msg/sec' %
          (nActors, what, sysBase, elapsed,
           nMessages / timePeriodSeconds(elapsed),
           nMessages * nActors / timePeriodSeconds(elapsed)))
Example #26
0
def report(what, sysBase, elapsed, nMessages, nActors):
    print('%5d Actors, %30s %22s -- %s -- %5.2f/sec overall -- %7.2f msg/sec'%(
        nActors, what, sysBase, elapsed,
        nMessages / timePeriodSeconds(elapsed),
        nMessages * nActors / timePeriodSeconds(elapsed)))