예제 #1
0
    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)
예제 #2
0
    def _next_XMIT_1(self, intent):
        intent.socket = socket.socket(
            *intent.targetAddr.addressDetails.socketArgs)
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        intent.socket.setblocking(0)
        # Disable Nagle to transmit headers and acks asap; our sends are usually small
        intent.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)

        intent.socket.settimeout(timePeriodSeconds(intent.delay()))
        try:
            intent.socket.connect(
                *intent.targetAddr.addressDetails.connectArgs)
        except socket.error as err:
            # EINPROGRESS means non-blocking socket connect is in progress...
            if err.errno != errno.EINPROGRESS:
                thesplog('Socket connect failure %s to %s (returning %s)',
                         err,
                         intent.targetAddr,
                         intent.completionCallback,
                         level=logging.WARNING)
                return self._finishIntent(intent,
                                          SendStatus.DeadTarget \
                                          if err.errno == errno.ECONNREFUSED \
                                          else SendStatus.Failed)
            intent.backoffPause(True)
        except Exception as ex:
            thesplog('Unexpected TCP socket connect exception: %s',
                     ex,
                     level=logging.ERROR)
            return self._finishIntent(intent, SendStatus.BadPacket)
        intent.stage = self._XMITStepSendData  # When connect completes
        intent.amtSent = 0
        return True
예제 #3
0
    def _next_XMIT_1(self, intent):
        intent.socket = socket.socket(*intent.targetAddr.addressDetails.socketArgs)
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        intent.socket.setblocking(0)
        # Disable Nagle to transmit headers and acks asap; our sends are usually small
        intent.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)

        intent.socket.settimeout(timePeriodSeconds(intent.delay()))
        try:
            intent.socket.connect(*intent.targetAddr.addressDetails.connectArgs)
        except socket.error as err:
            # EINPROGRESS means non-blocking socket connect is in progress...
            if err.errno != errno.EINPROGRESS:
                thesplog('Socket connect failure %s to %s (returning %s)',
                         err, intent.targetAddr, intent.completionCallback,
                         level=logging.WARNING)
                return self._finishIntent(intent,
                                          SendStatus.DeadTarget \
                                          if err.errno == errno.ECONNREFUSED \
                                          else SendStatus.Failed)
            intent.backoffPause(True)
        except Exception as ex:
            thesplog('Unexpected TCP socket connect exception: %s', ex,
                     level=logging.ERROR)
            return self._finishIntent(intent, SendStatus.BadPacket)
        intent.stage = self._XMITStepSendData # When connect completes
        intent.amtSent = 0
        return True
예제 #4
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)
     self.assertGreater(15, actRate)  # add a little buffer for overage... just a little
예제 #5
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
예제 #6
0
    def testTransmitIntentRetryTiming(self):
        maxPeriod = timedelta(milliseconds=90)
        period = timedelta(milliseconds=30)
        ti = TransmitIntent('addr', 'msg', maxPeriod=maxPeriod, retryPeriod=period)
        self.assertFalse(ti.timeToRetry())
        sleep(timePeriodSeconds(period))
        self.assertFalse(ti.timeToRetry())

        self.assertTrue(ti.retry())
        self.assertFalse(ti.timeToRetry())
        sleep(timePeriodSeconds(period))
        self.assertTrue(ti.timeToRetry())

        self.assertTrue(ti.retry())
        self.assertFalse(ti.timeToRetry())
        sleep(timePeriodSeconds(period))
        self.assertFalse(ti.timeToRetry())  # Each retry increases
        sleep(timePeriodSeconds(period))
        self.assertTrue(ti.timeToRetry())

        self.assertFalse(ti.retry())  # Exceeds maximum time
예제 #7
0
    def testTransmitIntentRetryTimingExceedsLimit(self):
        maxPeriod = timedelta(seconds=90)
        period = timedelta(microseconds=1)
        ti = TransmitIntent('addr', 'msg', maxPeriod=maxPeriod, retryPeriod=period)
        self.assertFalse(ti.timeToRetry())

        for N in range(MAX_TRANSMIT_RETRIES+1):
            self.assertTrue(ti.retry())
            for x in range(90):
                if ti.timeToRetry(): break
                sleep(timePeriodSeconds(period))
            self.assertTrue(ti.timeToRetry())

        self.assertFalse(ti.retry())
예제 #8
0
    def testTransmitIntentRetryTiming(self):
        maxPeriod = timedelta(milliseconds=90)
        period = timedelta(milliseconds=30)
        ti = TransmitIntent('addr',
                            'msg',
                            maxPeriod=maxPeriod,
                            retryPeriod=period)
        self.assertFalse(ti.timeToRetry())
        sleep(timePeriodSeconds(period))
        self.assertFalse(ti.timeToRetry())

        self.assertTrue(ti.retry())
        self.assertFalse(ti.timeToRetry())
        sleep(timePeriodSeconds(period))
        self.assertTrue(ti.timeToRetry())

        self.assertTrue(ti.retry())
        self.assertFalse(ti.timeToRetry())
        sleep(timePeriodSeconds(period))
        self.assertFalse(ti.timeToRetry())  # Each retry increases
        sleep(timePeriodSeconds(period))
        self.assertTrue(ti.timeToRetry())

        self.assertFalse(ti.retry())  # Exceeds maximum time
예제 #9
0
    def testTransmitIntentRetryTimingExceedsLimit(self):
        maxPeriod = timedelta(seconds=90)
        period = timedelta(microseconds=1)
        ti = TransmitIntent('addr',
                            'msg',
                            maxPeriod=maxPeriod,
                            retryPeriod=period)
        self.assertFalse(ti.timeToRetry())

        for N in range(MAX_TRANSMIT_RETRIES + 1):
            self.assertTrue(ti.retry())
            for x in range(90):
                if ti.timeToRetry(): break
                sleep(timePeriodSeconds(period))
            self.assertTrue(ti.timeToRetry())

        self.assertFalse(ti.retry())
예제 #10
0
    def testTransmitIntentRetryTimingExceedsLimit(self):
        maxPeriod = timedelta(seconds=90)
        period = timedelta(microseconds=1)
        ti = TransmitIntent('addr', 'msg', maxPeriod=maxPeriod, retryPeriod=period)
        self.assertFalse(ti.timeToRetry())

        for N in range(MAX_TRANSMIT_RETRIES+1):
            # Indicate "failure" and the need to retry
            self.assertTrue(ti.retry())
            # Wait for the indication that it is time to retry
            time_to_retry = False
            for x in range(90):
                # Only call timeToRetry once, because it auto-resets
                time_to_retry = ti.timeToRetry()
                if time_to_retry: break
                sleep(timePeriodSeconds(period) * 1.5)
            self.assertTrue(time_to_retry)

        self.assertFalse(ti.retry())
예제 #11
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
예제 #12
0
 def _runSends(self, timeout=None):
     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 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()
예제 #13
0
 def _runSends(self, timeout=None):
     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 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()
예제 #14
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
예제 #15
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.utilis 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.
예제 #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
예제 #17
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))
예제 #18
0
    def _runWithExpiry(self, incomingHandler):
        xmitOnly = incomingHandler == TransmitOnly or \
                   isinstance(incomingHandler, TransmitOnly)

        if hasattr(self, '_aborting_run'): delattr(self, '_aborting_run')

        while not self.run_time.expired() and \
              (not hasattr(self, '_aborting_run') or
               (self._aborting_run and self._transmitIntents)):

            if xmitOnly:
                if not self._transmitIntents:
                    return 0
            else:
                while self._incomingEnvelopes:
                    rEnv = self._incomingEnvelopes.pop(0)
                    if incomingHandler is None:
                        return rEnv
                    if not incomingHandler(rEnv):
                        return None

            wsend, wrecv = fmap(TCPTransport._socketFile,
                                partition(TCPTransport._waitForSendable,
                                          filter(lambda T: not T.backoffPause(),
                                                 self._transmitIntents)))

            wrecv = list(filter(None, wrecv))
            wsend = list(filter(None, wsend))
            wrecv.extend(list(filter(None,
                                     [TCPTransport._socketFile(I)
                                      for I in self._incomingSockets
                                      if not I.backoffPause()])))

            delays = list([R for R in [self.run_time.remaining()] +
                           [T.delay() for T in self._transmitIntents] +
                           [T.delay() for T in self._incomingSockets]
                           if R is not None])
            delay = timePeriodSeconds(min(delays)) if delays else None

            if not hasattr(self, '_aborting_run') and not xmitOnly:
                wrecv.extend([self.socket.fileno()])
            # rrecv, rsend, _ign2 = select.select(wrecv, wsend, [], delay)
            try:
                rrecv, rsend, _ign2 = select.select(wrecv, wsend, set(wsend+wrecv),
                                                    delay)
            except ValueError as ex:
                thesplog('ValueError on select(#%d: %s, #%d: %s, #%d: %s, %s)',
                         len(wrecv), wrecv, len(wsend), wsend,
                         len(set(wsend + wrecv)), set(wsend + wrecv),
                         delay, level=logging.ERROR)
                raise
            except select.error as ex:
                if ex.args[0] in (errno.EINVAL,  # probably a change in descriptors
                                  errno.EINTR,
                              ):
                    thesplog('select retry on %s', ex, level=logging.ERROR)
                    continue
                raise


            if _ign2:
                thesplog('WHOA... something else to do for sockets: %s',
                         _ign2, level=logging.WARNING)

            origPendingSends = len(self._transmitIntents)

            # Handle newly sendable data
            for eachs in rsend:
                self._transmitIntents = [I for I in self._transmitIntents
                                         if self._nextTransmitStepCheck(I, eachs)]

            # Handle newly receivable data
            for each in rrecv:
                if each == self.socket.fileno():
                    self._acceptNewIncoming()
                    continue
                self._incomingSockets = [S for S in self._incomingSockets
                                         if self._handlePossibleIncoming(S, each)]
                self._transmitIntents = [I for I in self._transmitIntents
                                         if self._nextTransmitStepCheck(I, each)]

            # Handle timeouts
            self._transmitIntents = [I for I in self._transmitIntents
                                     if self._nextTransmitStepCheck(I, -1)]
            self._incomingSockets = [S for S in self._incomingSockets
                                     if self._handlePossibleIncoming(S, -1)]

            # Check if it's time to quit
            if [] == rrecv and [] == rsend:
                if [] == _ign2 and self.run_time.expired():
                    # Timeout, give up
                    return None
                continue
            if xmitOnly:
                remXmits = len(self._transmitIntents)
                if origPendingSends > remXmits or remXmits == 0:
                    return remXmits

            # Handle queued internal "received" data
            if not xmitOnly:
                while self._incomingEnvelopes:
                    rEnv = self._incomingEnvelopes.pop(0)
                    if incomingHandler is None:
                        return rEnv
                    if not incomingHandler(rEnv):
                        return None

        return None
예제 #19
0
    #   5. This parent is the external port for asys1.
    #   6. If asys1 is shutdown first, then asys2 must time out
    #      on the transmit attempt (usually 5 minutes) before
    #      it can exit.
    #   7. If the test is re-run within this 5 minute period, it will fail
    #      because the old asys2 is still existing but in shutdown state
    #      (and will therefore rightfully refuse new actions).
    # By shutting down asys2 first, the parent notification can be
    # performed and subsequent runs don't encounter the lingering
    # asys2.
    request.addfinalizer(lambda asys=asys2: asys2.shutdown())
    return (asys, asys2)


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.utilis import timePeriodSeconds
import time

inTestDelay = lambda period: time.sleep(timePeriodSeconds(period))
예제 #20
0
 def testModerate__expected_duration_is_20_seconds(self):
     cnt = 100
     tt = send_at_rate(10, 5, cnt)
     print('send_at_rate(10, 5, %s) --> %s' % (cnt, str(tt)))
     actRate = cnt / timePeriodSeconds(tt)
     self.assertGreater(10, actRate)
예제 #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)
     self.assertGreater(10, actRate)
예제 #22
0
    def _runWithExpiry(self, incomingHandler):
        xmitOnly = incomingHandler == TransmitOnly or \
                   isinstance(incomingHandler, TransmitOnly)

        if hasattr(self, '_aborting_run'): delattr(self, '_aborting_run')

        while not self.run_time.expired() and \
              (not hasattr(self, '_aborting_run') or
               (self._aborting_run and self._transmitIntents)):

            if xmitOnly:
                if not self._transmitIntents:
                    return 0
            else:
                while self._incomingEnvelopes:
                    rEnv = self._incomingEnvelopes.pop(0)
                    if incomingHandler is None:
                        return rEnv
                    if not incomingHandler(rEnv):
                        return None

            wsend, wrecv = fmap(
                TCPTransport._socketFile,
                partition(
                    TCPTransport._waitForSendable,
                    filter(lambda T: not T.backoffPause(),
                           self._transmitIntents)))

            wrecv = list(filter(None, wrecv))
            wsend = list(filter(None, wsend))
            wrecv.extend(
                list(
                    filter(None, [
                        TCPTransport._socketFile(I)
                        for I in self._incomingSockets if not I.backoffPause()
                    ])))

            delays = list([
                R for R in [self.run_time.remaining()] +
                [T.delay() for T in self._transmitIntents] +
                [T.delay() for T in self._incomingSockets] if R is not None
            ])
            delay = timePeriodSeconds(min(delays)) if delays else None

            if not hasattr(self, '_aborting_run') and not xmitOnly:
                wrecv.extend([self.socket.fileno()])
            # rrecv, rsend, _ign2 = select.select(wrecv, wsend, [], delay)
            try:
                rrecv, rsend, _ign2 = select.select(wrecv, wsend,
                                                    set(wsend + wrecv), delay)
            except ValueError as ex:
                thesplog('ValueError on select(#%d: %s, #%d: %s, #%d: %s, %s)',
                         len(wrecv),
                         wrecv,
                         len(wsend),
                         wsend,
                         len(set(wsend + wrecv)),
                         set(wsend + wrecv),
                         delay,
                         level=logging.ERROR)
                raise
            except select.error as ex:
                if ex.args[0] in (
                        errno.EINVAL,  # probably a change in descriptors
                        errno.EINTR,
                ):
                    thesplog('select retry on %s', ex, level=logging.ERROR)
                    continue
                raise

            if _ign2:
                thesplog('WHOA... something else to do for sockets: %s',
                         _ign2,
                         level=logging.WARNING)

            origPendingSends = len(self._transmitIntents)

            # Handle newly sendable data
            for eachs in rsend:
                self._transmitIntents = [
                    I for I in self._transmitIntents
                    if self._nextTransmitStepCheck(I, eachs)
                ]

            # Handle newly receivable data
            for each in rrecv:
                if each == self.socket.fileno():
                    self._acceptNewIncoming()
                    continue
                self._incomingSockets = [
                    S for S in self._incomingSockets
                    if self._handlePossibleIncoming(S, each)
                ]
                self._transmitIntents = [
                    I for I in self._transmitIntents
                    if self._nextTransmitStepCheck(I, each)
                ]

            # Handle timeouts
            self._transmitIntents = [
                I for I in self._transmitIntents
                if self._nextTransmitStepCheck(I, -1)
            ]
            self._incomingSockets = [
                S for S in self._incomingSockets
                if self._handlePossibleIncoming(S, -1)
            ]

            # Check if it's time to quit
            if [] == rrecv and [] == rsend:
                if [] == _ign2 and self.run_time.expired():
                    # Timeout, give up
                    return None
                continue
            if xmitOnly:
                remXmits = len(self._transmitIntents)
                if origPendingSends > remXmits or remXmits == 0:
                    return remXmits

            # Handle queued internal "received" data
            if not xmitOnly:
                while self._incomingEnvelopes:
                    rEnv = self._incomingEnvelopes.pop(0)
                    if incomingHandler is None:
                        return rEnv
                    if not incomingHandler(rEnv):
                        return None

        return None
예제 #23
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)))
예제 #24
0
        print('send_at_rate(10, 9, %s) --> %s'%(cnt, str(tt)))
        actRate = cnt / timePeriodSeconds(tt)
        self.assertGreater(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)
        self.assertGreater(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)
        self.assertGreater(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))

예제 #25
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)
     self.assertGreater(10, actRate)
예제 #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)))
예제 #27
0
    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