def test_check_before_activate_with_notifications(lcs1, lcs2):
    ret = LocalConventionState(
        ActorAddress(1), {
            'Admin Port': 1,
            'Convention Address.IPv4': ActorAddress(1),
            'popsicle': 'cold'
        }, StatsManager(), lambda x: ActorAddress(1))
    # Activate the system
    verify_io(ret.setup_convention(), [])

    notifyAddr = ActorAddress('notify')

    lcs1.add_notification_handler(notifyAddr)

    ret = LocalConventionState(
        ActorAddress(2), {
            'Admin Port': 2,
            'Convention Address.IPv4': ActorAddress(1),
            'apple pie': 'hot'
        }, StatsManager(), lambda x: ActorAddress(1))
    ret._expected_setup_convreg = ConventionRegister(ActorAddress(2),
                                                     ret.capabilities,
                                                     firstTime=True,
                                                     preRegister=False)

    verify_io(ret.check_convention(), [])

    # Activate the system
    verify_io(ret.setup_convention(), [
        (ConventionRegister, lambda r, a:
         (r == ret._expected_setup_convreg and a == ActorAddress(1))),
        (LogAggregator, None),
    ])
Exemple #2
0
 def __init__(self, adminAddr, transport):
     self._adminAddr   = adminAddr
     self.transport    = transport
     self._addrManager = ActorAddressManager(adminAddr, self.transport.myAddress)
     self.transport.setAddressManager(self._addrManager)
     self._pendingTransmits = PendingTransmits(self._addrManager)
     self._awaitingAddressUpdate = AddressWaitTransmits()
     self._receiveQueue = []  # array of ReceiveMessage to be processed
     self._children = []  # array of Addresses of children of this Actor/Admin
     self._governer = RateThrottle(RATE_THROTTLE)
     self._sCBStats = StatsManager()
Exemple #3
0
 def __init__(self, adminAddr, transport):
     self._adminAddr = adminAddr
     self.transport = transport
     self._addrManager = ActorAddressManager(adminAddr,
                                             self.transport.myAddress)
     self.transport.setAddressManager(self._addrManager)
     self._finalTransmitPending = {
     }  # key = target ActorAddress, value=None or the last pending Intent
     self._awaitingAddressUpdate = {
     }  # key = actorAddress waited on (usually local), value=array of transmit Intents
     self._receiveQueue = []  # array of ReceiveMessage to be processed
     self._children = [
     ]  # array of Addresses of children of this Actor/Admin
     self._governer = RateThrottle(RATE_THROTTLE)
     self._sCBStats = StatsManager()
def lcs1():
    ret = LocalConventionState(
        ActorAddress(1), {
            'Admin Port': 1,
            'Convention Address.IPv4': ActorAddress(1),
            'popsicle': 'cold'
        }, StatsManager(), lambda x: ActorAddress(1))
    # Activate the system
    verify_io(ret.setup_convention(activation=True), [])
    return ret
Exemple #5
0
 def __init__(self, adminAddr, transport):
     self._adminAddr   = adminAddr
     self.transport    = transport
     self._addrManager = ActorAddressManager(adminAddr, self.transport.myAddress)
     self.transport.setAddressManager(self._addrManager)
     self._finalTransmitPending = {} # key = target ActorAddress, value=None or the last pending Intent
     self._awaitingAddressUpdate = {}  # key = actorAddress waited on (usually local), value=array of transmit Intents
     self._receiveQueue = []  # array of ReceiveMessage to be processed
     self._children = []  # array of Addresses of children of this Actor/Admin
     self._governer = RateThrottle(RATE_THROTTLE)
     self._sCBStats = StatsManager()
def solo_lcs2():
    # Like lcs2, but does not specify a convention address; intended
    # for use with pre-registration (e.g. to simulate TXOnly
    # environments.
    ret = LocalConventionState(ActorAddress(2), {
        'Admin Port': 2,
        'apple pie': 'hot'
    }, StatsManager(), lambda x: None)
    # Activate the system
    assert [] == ret.setup_convention()
    return ret
def lcs2():
    ret = LocalConventionState(
        ActorAddress(2), {
            'Admin Port': 2,
            'Convention Address.IPv4': ActorAddress(1),
            'apple pie': 'hot'
        }, StatsManager(), lambda x: ActorAddress(1))
    ret._expected_setup_convreg = ConventionRegister(ActorAddress(2),
                                                     ret.capabilities,
                                                     firstTime=True,
                                                     preRegister=False)
    # Activate the system
    verify_io(ret.setup_convention(activation=True), [
        (ConventionRegister, lambda r, a:
         (r == ret._expected_setup_convreg and a == ActorAddress(1))),
        (LogAggregator, None),
    ])
    # KWQ: above is a HysteresisSend
    return ret
Exemple #8
0
class systemCommonBase(object):
    def __init__(self, adminAddr, transport):
        self._adminAddr = adminAddr
        self.transport = transport
        self._addrManager = ActorAddressManager(adminAddr,
                                                self.transport.myAddress)
        self.transport.setAddressManager(self._addrManager)
        self._pendingTransmits = PendingTransmits(self._addrManager)
        self._awaitingAddressUpdate = AddressWaitTransmits()
        self._receiveQueue = []  # array of ReceiveMessage to be processed
        self._children = [
        ]  # array of Addresses of children of this Actor/Admin
        self._governer = RateThrottle(RATE_THROTTLE)
        self._sCBStats = StatsManager()

    @property
    def address(self):
        return self.transport.myAddress

    @property
    def myAddress(self):
        return self.transport.myAddress

    @property
    def childAddresses(self):
        return self._children

    def _registerChild(self, childAddress):
        self._children.append(childAddress)

    def _handleChildExited(self, childAddress):
        self._sCBStats.inc('Common.Message Received.Child Actor Exited')
        self.transport.deadAddress(self._addrManager, childAddress)
        self._childExited(childAddress)
        self._children = [C for C in self._children if C != childAddress]
        if hasattr(self, '_exiting') and not self._children:
            # OK, all children are dead, can now exit this actor, but
            # make sure this final cleanup only occurs once
            # (e.g. transport.deadAddress above could recurse through
            # here as well.
            if not hasattr(self, '_exitedAlready'):
                self._exitedAlready = True
                self._sayGoodbye()
                self.transport.abort_run(drain=True)
            return False
        return True

    def _updateStatusResponse(self, resp):
        "Called to update a Thespian_SystemStatus or Thespian_ActorStatus with common information"
        for each in self.childAddresses:
            resp.addChild(each)
        for each in self._receiveQueue:
            resp.addReceivedMessage(each.sender, self.myAddress, each.message)
        self._sCBStats.copyToStatusResponse(resp)
        self._pendingTransmits.update_status_response(resp, self.myAddress)
        resp.governer = str(self._governer)
        fmap(lambda x: resp.addTXPendingAddressCount(*len_second(x)),
             self._awaitingAddressUpdate)
        self.transport._updateStatusResponse(resp)

    def setLoggingControls(self, envelope):
        from thespian.system.utilis import thesplog_control
        msg = envelope.message
        thesplog_control(msg.threshold, msg.useLogging, msg.useFile)
        return True

    # ----------------------------------------------------------------------
    # Transmit management

    def _send_intent(self, intent, curtime=None):
        self._governer.eventRatePause(curtime or datetime.now())
        # Check if there are any existing transmits in progress to
        # this address (on either the input address or the validated
        # address); if so, just add the new one to the list and
        # return.
        if self._pendingTransmits.p_can_send_now(self._sCBStats, intent):
            self._send_intent_to_transport(intent)

    def _retryPendingChildOperations(self, childInstance, actualAddress):
        # actualAddress will be none if the child could not be created
        lcladdr = self._addrManager.getLocalAddress(childInstance)

        if not actualAddress:
            self._receiveQueue.append(
                ReceiveEnvelope(lcladdr, ChildActorExited(lcladdr)))
        else:
            self._pendingTransmits.change_address_for_transmit(
                lcladdr, actualAddress)

        for each in self._awaitingAddressUpdate\
                        .remove_intents_for_address(lcladdr):
            if actualAddress:
                self._sCBStats.inc('Actor.Message Send.Transmit ReInitiated')
                self._send_intent(each)
            else:
                if not isinstance(each.message, PoisonMessage):
                    self._receiveQueue.append(
                        ReceiveEnvelope(
                            self.myAddress,
                            PoisonMessage(each.message, 'Child Aborted')))
                self._sCBStats.inc(
                    'Actor.Message Send.Poison Return on Child Abort')
                each.tx_done(SendStatus.Failed)

    def _send_intent_to_transport(self, intent):
        thesplog('Attempting intent %s',
                 intent.identify(),
                 level=logging.DEBUG)
        if not hasattr(intent, '_addedCheckNextTransmitCB'):
            intent.addCallback(self._checkNextTransmit,
                               self._checkNextTransmit)
            # Protection against duplicate callback additions in case
            # of a retry due to the CannotPickleAddress exception below.
            intent._addedCheckNextTransmitCB = True
        intent._transmit_pending_to_transport = True
        try:
            self.transport.scheduleTransmit(self._addrManager, intent)
            self._sCBStats.inc('Actor.Message Send.Transmit Started')
            return
        except CannotPickleAddress as ex:
            thesplog('CannotPickleAddress, appending intent for %s',
                     ex.address,
                     level=logging.DEBUG)
            self._sCBStats.inc('Actor.Message Send.Postponed for Address')
            self._awaitingAddressUpdate.add(ex.address, intent)
            # Callback is still registered, so callback can use the
            # _transmit_pending_to_transport to determine if it was
            # actually being transmitted or not.
            intent._transmit_pending_to_transport = False
            next_intent = self._pendingTransmits.cannot_send_now(intent)
            if next_intent:
                self._send_intent_to_transport(next_intent)
        except Exception:
            import traceback
            thesplog('Declaring transmit of %s as Poison: %s',
                     intent.identify(),
                     traceback.format_exc(),
                     exc_info=True,
                     level=logging.ERROR)
            if not isinstance(intent.message, PoisonMessage):
                self._receiveQueue.append(
                    ReceiveEnvelope(
                        intent.targetAddr,
                        PoisonMessage(intent.message, traceback.format_exc())))
            self._sCBStats.inc('Actor.Message Send.Transmit Poison Rejection')
            intent.tx_done(SendStatus.Failed)

    def _checkNextTransmit(self, result, completedIntent):
        # This is the callback for (all) TransmitIntents that will
        # send the next queued intent for that destination.
        if getattr(completedIntent, '_transmit_pending_to_transport', False):
            next_intent = self._pendingTransmits.get_next(completedIntent)
            if next_intent:
                self._send_intent_to_transport(next_intent)

    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
Exemple #9
0
class systemCommonBase(object):
    def __init__(self, adminAddr, transport):
        self._adminAddr = adminAddr
        self.transport = transport
        self._addrManager = ActorAddressManager(adminAddr,
                                                self.transport.myAddress)
        self.transport.setAddressManager(self._addrManager)
        self._finalTransmitPending = {
        }  # key = target ActorAddress, value=None or the last pending Intent
        self._awaitingAddressUpdate = {
        }  # key = actorAddress waited on (usually local), value=array of transmit Intents
        self._receiveQueue = []  # array of ReceiveMessage to be processed
        self._children = [
        ]  # array of Addresses of children of this Actor/Admin
        self._governer = RateThrottle(RATE_THROTTLE)
        self._sCBStats = StatsManager()

    @property
    def address(self):
        return self.transport.myAddress

    @property
    def myAddress(self):
        return self.transport.myAddress

    @property
    def childAddresses(self):
        return self._children

    def _registerChild(self, childAddress):
        self._children.append(childAddress)

    def _handleChildExited(self, childAddress):
        self._sCBStats.inc('Common.Message Received.Child Actor Exited')
        self._addrManager.deadAddress(childAddress)
        self.transport.deadAddress(self._addrManager, childAddress)
        self._childExited(childAddress)
        self._children = [C for C in self._children if C != childAddress]
        if hasattr(self, '_exiting') and not self._children:
            # OK, all children are dead, can now exit this actor, but
            # make sure this final cleanup only occurs once
            # (e.g. transport.deadAddress above could recurse through
            # here as well.
            if not hasattr(self, '_exitedAlready'):
                self._exitedAlready = True
                self._sayGoodbye()
                self.transport.abort_run(drain=True)
        return True

    def _updateStatusResponse(self, resp):
        "Called to update a Thespian_SystemStatus or Thespian_ActorStatus with common information"
        for each in self.childAddresses:
            resp.addChild(each)
        for each in self._receiveQueue:
            resp.addReceivedMessage(each.sender, self.myAddress, each.message)
        self._sCBStats.copyToStatusResponse(resp)
        # Need to show _finalTransmitPending?  where is head of chain? shown by transport? (no)
        resp.governer = str(self._governer)
        for addr in self._awaitingAddressUpdate:
            resp.addTXPendingAddressCount(
                addr, len(self._awaitingAddressUpdate[addr]))
        self.transport._updateStatusResponse(resp)

    def setLoggingControls(self, envelope):
        from thespian.system.utilis import thesplog_control
        msg = envelope.message
        thesplog_control(msg.threshold, msg.useLogging, msg.useFile)
        return True

    # ----------------------------------------------------------------------
    # Transmit management

    def _send_intent(self, intent):
        self._governer.eventRatePause()
        # Check if there are any existing transmits in progress to
        # this address (on either the input address or the validated
        # address); if so, just add the new one to the list and
        # return.
        sendAddr = self._addrManager.sendToAddress(intent.targetAddr)
        finalIntent = self._finalTransmitPending.get(
            intent.targetAddr, self._finalTransmitPending.get(sendAddr, None))
        self._finalTransmitPending[sendAddr or intent.targetAddr] = intent
        if finalIntent:
            finalIntent.nextIntent = intent
            self._sCBStats.inc('Actor.Message Send.Added to End of Sends')
            return
        self._send_intent_to_transport(intent)

    def _retryPendingChildOperations(self, childInstance, actualAddress):
        # actualAddress will be none if the child could not be created
        lcladdr = self._addrManager.getLocalAddress(childInstance)

        if not actualAddress:
            self._receiveQueue.append(
                ReceiveEnvelope(lcladdr, ChildActorExited(lcladdr)))

        if lcladdr in self._finalTransmitPending:
            # KWQ: what to do when actualAddress is None?
            self._finalTransmitPending[
                actualAddress] = self._finalTransmitPending[lcladdr]
            del self._finalTransmitPending[lcladdr]

        if lcladdr in self._awaitingAddressUpdate:
            pending = self._awaitingAddressUpdate[lcladdr]
            del self._awaitingAddressUpdate[lcladdr]
            for each in pending:
                if actualAddress:
                    # KWQ: confirm the following two lines can be removed; send_intent_to_transport should do this translation on its own.  At that point, the changeTargetAddr method should be able to be removed.
                    #                if each.targetAddr == lcladdr:
                    #                    each.changeTargetAddr(actualAddress)
                    self._sCBStats.inc(
                        'Actor.Message Send.Transmit ReInitiated')
                    self._send_intent(each)
                else:
                    if not isinstance(each.message, PoisonMessage):
                        self._receiveQueue.append(
                            ReceiveEnvelope(self.myAddress,
                                            PoisonMessage(each.message)))
                    self._sCBStats.inc(
                        'Actor.Message Send.Poison Return on Child Abort')
                    each.result = SendStatus.Failed
                    each.completionCallback()

    def _send_intent_to_transport(self, intent):
        thesplog('Attempting intent %s',
                 intent.identify(),
                 level=logging.DEBUG)
        if not hasattr(intent, '_addedCheckNextTransmitCB'):
            intent.addCallback(self._checkNextTransmit,
                               self._checkNextTransmit)
            # Protection against duplicate callback additions in case
            # of a retry due to the CannotPickleAddress exception below.
            intent._addedCheckNextTransmitCB = True
        try:
            self.transport.scheduleTransmit(self._addrManager, intent)
            self._sCBStats.inc('Actor.Message Send.Transmit Started')
        except CannotPickleAddress as ex:
            thesplog('CannotPickleAddress, appending intent for %s (hash=%s)',
                     ex.address,
                     hash(ex.address),
                     level=logging.DEBUG)
            self._awaitingAddressUpdate.setdefault(ex.address,
                                                   []).append(intent)
            self._sCBStats.inc('Actor.Message Send.Postponed for Address')
            self._checkNextTransmit(0, intent)
        except Exception:
            import traceback
            thesplog('Declaring transmit of %s as Poison: %s',
                     intent.identify(),
                     traceback.format_exc(),
                     exc_info=True,
                     level=logging.ERROR)
            if not isinstance(intent.message, PoisonMessage):
                self._receiveQueue.append(
                    ReceiveEnvelope(intent.targetAddr,
                                    PoisonMessage(intent.message)))
            self._sCBStats.inc('Actor.Message Send.Transmit Poison Rejection')
            intent.result = SendStatus.Failed
            intent.completionCallback()

    def _checkNextTransmit(self, result, completedIntent):
        # This is the callback for (all) TransmitIntents that will
        # send the next queued intent for that destination.
        if completedIntent.nextIntent:
            self._send_intent_to_transport(completedIntent.nextIntent)
        else:
            fkey = completedIntent.targetAddr
            if fkey not in self._finalTransmitPending:
                fkey = self._addrManager.sendToAddress(
                    completedIntent.targetAddr)
                if fkey not in self._finalTransmitPending:
                    if isinstance(completedIntent.message, DeadEnvelope):
                        fkey = completedIntent.message.deadAddress
                        if fkey not in self._finalTransmitPending:
                            fkey = self._addrManager.sendToAddress(fkey)

            if fkey in self._finalTransmitPending:
                if self._finalTransmitPending[fkey] != completedIntent:
                    thesplog(
                        'Completed final intent %s does not match recorded final intent: %s',
                        completedIntent.identify(),
                        self._finalTransmitPending[fkey].identify(),
                        level=logging.WARNING)
                del self._finalTransmitPending[fkey]
            else:
                thesplog(
                    'Completed Transmit Intent %s for unrecorded destination %s / %s in %s',
                    completedIntent.identify(),
                    str(
                        self._addrManager.sendToAddress(
                            completedIntent.targetAddr)),
                    fkey,
                    str(map(str, self._finalTransmitPending.keys())),
                    level=logging.WARNING)
                self._sCBStats.inc('Action.Message Send.Unknown Completion')
                return
Exemple #10
0
class systemCommonBase(object):

    def __init__(self, adminAddr, transport):
        self._adminAddr   = adminAddr
        self.transport    = transport
        self._addrManager = ActorAddressManager(adminAddr, self.transport.myAddress)
        self.transport.setAddressManager(self._addrManager)
        self._finalTransmitPending = {} # key = target ActorAddress, value=None or the last pending Intent
        self._awaitingAddressUpdate = {}  # key = actorAddress waited on (usually local), value=array of transmit Intents
        self._receiveQueue = []  # array of ReceiveMessage to be processed
        self._children = []  # array of Addresses of children of this Actor/Admin
        self._governer = RateThrottle(RATE_THROTTLE)
        self._sCBStats = StatsManager()


    @property
    def address(self): return self.transport.myAddress
    @property
    def myAddress(self): return self.transport.myAddress


    @property
    def childAddresses(self): return self._children

    def _registerChild(self, childAddress): self._children.append(childAddress)

    def _handleChildExited(self, childAddress):
        self._sCBStats.inc('Common.Message Received.Child Actor Exited')
        self._addrManager.deadAddress(childAddress)
        self.transport.deadAddress(self._addrManager, childAddress)
        self._childExited(childAddress)
        self._children = [C for C in self._children if C != childAddress]
        if hasattr(self, '_exiting') and not self._children:
            # OK, all children are dead, can now exit this actor, but
            # make sure this final cleanup only occurs once
            # (e.g. transport.deadAddress above could recurse through
            # here as well.
            if not hasattr(self, '_exitedAlready'):
                self._exitedAlready = True
                self._sayGoodbye()
                self.transport.abort_run(drain=True)
        return True


    def _updateStatusResponse(self, resp):
        "Called to update a Thespian_SystemStatus or Thespian_ActorStatus with common information"
        for each in self.childAddresses:
            resp.addChild(each)
        for each in self._receiveQueue:
            resp.addReceivedMessage(each.sender, self.myAddress, each.message)
        self._sCBStats.copyToStatusResponse(resp)
        # Need to show _finalTransmitPending?  where is head of chain? shown by transport? (no)
        resp.governer = str(self._governer)
        for addr in self._awaitingAddressUpdate:
            resp.addTXPendingAddressCount(addr, len(self._awaitingAddressUpdate[addr]))
        self.transport._updateStatusResponse(resp)


    def setLoggingControls(self, envelope):
        from thespian.system.utilis import thesplog_control
        msg = envelope.message
        thesplog_control(msg.threshold, msg.useLogging, msg.useFile)
        return True


    # ----------------------------------------------------------------------
    # Transmit management

    def _send_intent(self, intent):
        self._governer.eventRatePause()
        # Check if there are any existing transmits in progress to
        # this address (on either the input address or the validated
        # address); if so, just add the new one to the list and
        # return.
        sendAddr = self._addrManager.sendToAddress(intent.targetAddr)
        finalIntent = self._finalTransmitPending.get(
            intent.targetAddr,
            self._finalTransmitPending.get(sendAddr, None))
        self._finalTransmitPending[sendAddr or intent.targetAddr] = intent
        if finalIntent:
            finalIntent.nextIntent = intent
            self._sCBStats.inc('Actor.Message Send.Added to End of Sends')
            return
        self._send_intent_to_transport(intent)


    def _retryPendingChildOperations(self, childInstance, actualAddress):
        # actualAddress will be none if the child could not be created
        lcladdr = self._addrManager.getLocalAddress(childInstance)

        if not actualAddress:
            self._receiveQueue.append(ReceiveEnvelope(lcladdr, ChildActorExited(lcladdr)))

        if lcladdr in self._finalTransmitPending:
            # KWQ: what to do when actualAddress is None?
            self._finalTransmitPending[actualAddress] = self._finalTransmitPending[lcladdr]
            del self._finalTransmitPending[lcladdr]

        if lcladdr in self._awaitingAddressUpdate:
            pending = self._awaitingAddressUpdate[lcladdr]
            del self._awaitingAddressUpdate[lcladdr]
            for each in pending:
                if actualAddress:
                    # KWQ: confirm the following two lines can be removed; send_intent_to_transport should do this translation on its own.  At that point, the changeTargetAddr method should be able to be removed.
    #                if each.targetAddr == lcladdr:
    #                    each.changeTargetAddr(actualAddress)
                    self._sCBStats.inc('Actor.Message Send.Transmit ReInitiated')
                    self._send_intent(each)
                else:
                    if not isinstance(each.message, PoisonMessage):
                        self._receiveQueue.append(
                            ReceiveEnvelope(self.myAddress,
                                            PoisonMessage(each.message)))
                    self._sCBStats.inc('Actor.Message Send.Poison Return on Child Abort')
                    each.result = SendStatus.Failed
                    each.completionCallback()


    def _send_intent_to_transport(self, intent):
        thesplog('Attempting intent %s', intent.identify(), level=logging.DEBUG)
        if not hasattr(intent, '_addedCheckNextTransmitCB'):
            intent.addCallback(self._checkNextTransmit, self._checkNextTransmit)
            # Protection against duplicate callback additions in case
            # of a retry due to the CannotPickleAddress exception below.
            intent._addedCheckNextTransmitCB = True
        try:
            self.transport.scheduleTransmit(self._addrManager, intent)
            self._sCBStats.inc('Actor.Message Send.Transmit Started')
        except CannotPickleAddress as ex:
            thesplog('CannotPickleAddress, appending intent for %s (hash=%s)',
                     ex.address, hash(ex.address), level=logging.DEBUG)
            self._awaitingAddressUpdate.setdefault(ex.address, []).append(intent)
            self._sCBStats.inc('Actor.Message Send.Postponed for Address')
            self._checkNextTransmit(0, intent)
        except Exception:
            import traceback
            thesplog('Declaring transmit of %s as Poison: %s', intent.identify(),
                     traceback.format_exc(), exc_info=True, level=logging.ERROR)
            if not isinstance(intent.message, PoisonMessage):
                self._receiveQueue.append(ReceiveEnvelope(intent.targetAddr, PoisonMessage(intent.message)))
            self._sCBStats.inc('Actor.Message Send.Transmit Poison Rejection')
            intent.result = SendStatus.Failed
            intent.completionCallback()


    def _checkNextTransmit(self, result, completedIntent):
        # This is the callback for (all) TransmitIntents that will
        # send the next queued intent for that destination.
        if completedIntent.nextIntent:
            self._send_intent_to_transport(completedIntent.nextIntent)
        else:
            fkey = completedIntent.targetAddr
            if fkey not in self._finalTransmitPending:
                fkey = self._addrManager.sendToAddress(completedIntent.targetAddr)
                if fkey not in self._finalTransmitPending:
                    if isinstance(completedIntent.message, DeadEnvelope):
                        fkey = completedIntent.message.deadAddress
                        if fkey not in self._finalTransmitPending:
                            fkey = self._addrManager.sendToAddress(fkey)

            if fkey in self._finalTransmitPending:
                if self._finalTransmitPending[fkey] != completedIntent:
                    thesplog('Completed final intent %s does not match recorded final intent: %s',
                             completedIntent.identify(),
                             self._finalTransmitPending[fkey].identify(),
                             level=logging.WARNING)
                del self._finalTransmitPending[fkey]
            else:
                thesplog('Completed Transmit Intent %s for unrecorded destination %s / %s in %s',
                         completedIntent.identify(),
                         str(self._addrManager.sendToAddress(completedIntent.targetAddr)),
                         fkey,
                         str(map(str,self._finalTransmitPending.keys())),
                         level=logging.WARNING)
                self._sCBStats.inc('Action.Message Send.Unknown Completion')
                return