示例#1
0
 def _not_compatible(self, createActorEnvelope):
     # Called when the current Actor System is not compatible with
     # the Actor's actorSystemCapabilityCheck.  Forward this
     # createActor request to another system that it's compatible
     # with.
     sourceHash = createActorEnvelope.message.sourceHash
     childRequirements = createActorEnvelope.message.targetActorReq
     childCName = createActorEnvelope.message.actorClassName
     childClass = actualActorClass(
         childCName,
         partial(loadModuleFromHashSource, sourceHash, self._sources)
         if sourceHash else None)
     acceptsCaps = lambda caps: checkActorCapabilities(
         childClass, caps, childRequirements)
     if createActorEnvelope.message.forActor is None:
         # Request from external; use sender address
         createActorEnvelope.message.forActor = createActorEnvelope.sender
     iolist = self._cstate.forward_pending_to_remote_system(
         childClass, createActorEnvelope, sourceHash, acceptsCaps)
     if iolist:
         for each in iolist:
             # Expected to be only one; if the transmit fails,
             # route it back here so that the next possible
             # remote can be tried.
             each.addCallback(onFailure=self._pending_send_failed)
             each.orig_create_envelope = createActorEnvelope
         return self._performIO(iolist)
     self._sendPendingActorResponse(
         createActorEnvelope,
         None,
         errorCode=PendingActorResponse.ERROR_No_Compatible_ActorSystem,
         errorStr="")
     # self._retryPendingChildOperations(childInstance, None)
     return True
示例#2
0
    def _startChildActor(self,
                         childAddr,
                         childClass,
                         globalName,
                         parentAddr,
                         notifyAddr,
                         childRequirements=None,
                         sourceHash=None,
                         sourceToLoad=None):
        """Create a new actor of type `childClass'.

           The `childAddr' is the local address of this child in the
           creator's address-space.

           The `parentAddr' is the parent of this actor in the
           heirarchy and will be another Actor or the local Admin.

           The `notifyAddr' is the Actor or Admin which should be
           notified on successful creation of this child Actor
           (normally this will be the parentAddr, but if the local
           Admin has been enlisted to create this Actor on behalf of
           another (possibly remote) Actor, the local Admin should be
           notified of the successful creation to complete it's
           administration and the Admin will forward the completion to
           the original requestor.).

           The optional `childRequirements' are a list of requirements
           dictated by the creating Actor.

        """
        if parentAddr is None:
            raise ActorSystemFailure('parentAddr cannot be None!')
        if self.asLogger is None:
            raise ActorSystemFailure('logger ADDR cannot be None!')

        try:
            if not checkActorCapabilities(
                    childClass,
                    self.capabilities,
                    childRequirements,
                    partial(loadModuleFromHashSource, sourceHash,
                            {sourceHash: sourceToLoad})
                    if sourceHash  # and sourceToLoad
                    else None):
                raise NoCompatibleSystemForActor(
                    childClass, "no system has compatible capabilities")
        except (InvalidActorSourceHash, ImportError):
            # Allow these exceptions to propagate outward since they
            # have special, public meaning
            raise
        except Exception:
            # Most exceptions should be converted to
            # NoCompatibleSystemForActor so that calling code
            # recognizes this issue and defers the create request to
            # the Admin.
            raise NoCompatibleSystemForActor(
                childClass, "no system has compatible capabilities")

        # KWQ: when child starts it will have this parent address and it will initialize its transport and notify the parent, whereupon the parent will see the incoming message from the child with the id# indicated in the addressmanager localaddress and update the localaddress.  All this should happen in the transport though, not here.
        endpointPrep = self.transport.prepEndpoint(childAddr,
                                                   self.capabilities)

        multiprocessing.process._current_process._daemonic = False

        # Ensure fileNumsToClose is a list, not an iterator because it
        # is an argument passed to the child.
        fileNumsToClose = list(self.transport.childResetFileNumList())

        mp = self.mpcontext if self.mpcontext else multiprocessing

        ccArg = '%s.%s'%(sys.modules[childClass.__module__].__name__,
                         childClass.__name__) \
                if hasattr(childClass, '__name__') else childClass
        child = mp.Process(
            target=startChild,
            args=(ccArg, globalName, endpointPrep, self.transport.__class__,
                  sourceHash or self._sourceHash, sourceToLoad, parentAddr,
                  self._adminAddr, notifyAddr, self.asLogger,
                  childRequirements, self.capabilities, fileNumsToClose,
                  self.mpcontext),
            name='Actor_%s__%s' %
            (getattr(childClass, '__name__', childClass), str(childAddr)))
        child.start()
        # Also note that while non-daemonic children cause the current
        # process to automatically join() those children on exit,
        # daemonic children are sent a terminate() operation (usually
        # indicated by a SIGTERM under unix or TERMINATE indicator
        # under windows.  To avoid this, use another dirty trick and
        # remove all children from the _current_process._children list
        # so that they are not automatically stopped when this process
        # stops.
        detach_child(child)

        if not hasattr(self, '_child_procs'): self._child_procs = []
        self._child_procs.append(
            ChildInfo(childAddr, childClass, child, endpointPrep.addrInst))
        self.transport.connectEndpoint(endpointPrep)
示例#3
0
    def _startChildActor(self, childAddr, childClass, parentAddr, notifyAddr,
                         childRequirements=None,
                         sourceHash=None, sourceToLoad=None):
        """Create a new actor of type `childClass'.

           The `childAddr' is the local address of this child in the
           creator's address-space.

           The `parentAddr' is the parent of this actor in the
           heirarchy and will be another Actor or the local Admin.

           The `notifyAddr' is the Actor or Admin which should be
           notified on successful creation of this child Actor
           (normally this will be the parentAddr, but if the local
           Admin has been enlisted to create this Actor on behalf of
           another (possibly remote) Actor, the local Admin should be
           notified of the successful creation to complete it's
           administration and the Admin will forward the completion to
           the original requestor.).

           The optional `childRequirements' are a list of requirements
           dictated by the creating Actor.

        """
        if parentAddr is None:
            raise ActorSystemFailure('parentAddr cannot be None!')
        if self.asLogger is None:
            raise ActorSystemFailure('logger ADDR cannot be None!')

        if not checkActorCapabilities(childClass, self.capabilities, childRequirements,
                                      partial(loadModuleFromHashSource,
                                              sourceHash,
                                              { sourceHash: sourceToLoad })
                                      if sourceHash else None):
            raise NoCompatibleSystemForActor(childClass,
                                             "no system has compatible capabilities")

        # KWQ: when child starts it will have this parent address and it will initialize its transport and notify the parent, whereupon the parent will see the incoming message from the child with the id# indicated in the addressmanager localaddress and update the localaddress.  All this should happen in the transport though, not here.
        endpointPrep = self.transport.prepEndpoint(childAddr)

        multiprocessing.process._current_process._daemonic = False

        fileNumsToClose = self.transport.childResetFileNumList()

        child = multiprocessing.Process(target=startChild,  #KWQ: instantiates module specified by sourceHash to create actor
                                        args=(childClass,
                                              endpointPrep,
                                              self.transport.__class__,
                                              sourceHash or self._sourceHash,
                                              sourceToLoad,
                                              parentAddr,
                                              self._adminAddr,
                                              notifyAddr,
                                              self.asLogger,
                                              childRequirements,
                                              self.capabilities,
                                              fileNumsToClose),
                                        name='Actor_%s__%s'%(childClass, str(childAddr)))
        child.daemon = True
        #multiprocessing.process._current_process._daemonic = True
        child.start()
        # Also note that while non-daemonic children cause the current
        # process to automatically join() those children on exit,
        # daemonic children are sent a terminate() operation (usually
        # indicated by a SIGTERM under unix or TERMINATE indicator
        # under windows.  To avoid this, use another dirty trick and
        # remove all children from the _current_process._children list
        # so that they are not automatically stopped when this process
        # stops.
        multiprocessing.process._current_process._children.remove(child)

        if not hasattr(self, '_child_procs'): self._child_procs = []
        self._child_procs.append(child)
        self.transport.connectEndpoint(endpointPrep)
示例#4
0
    def h_PendingActor(self, envelope):
        sourceHash = envelope.message.sourceHash
        childRequirements = envelope.message.targetActorReq
        thesplog('Pending Actor request received for %s%s reqs %s from %s',
                 envelope.message.actorClassName,
                 ' (%s)'%sourceHash if sourceHash else '',
                 childRequirements, envelope.sender)

        if sourceHash:
            if sourceHash not in self._sources:
                # If this request was forwarded by a remote Admin and the
                # sourceHash is not known locally, request it from the sending
                # remote Admin
                if self._cstate.sentByRemoteAdmin(envelope) and \
                   self._acceptsRemoteLoadedSourcesFrom(envelope):
                    self._sources[sourceHash] = PendingSource(sourceHash, None)
                    self._sources[sourceHash].pending_actors.append(envelope)
                    self._hysteresisSender.sendWithHysteresis(
                        TransmitIntent(
                            envelope.sender,
                            SourceHashTransferRequest(sourceHash,
                                                      bool(self._sourceAuthority))))
                    # sent with hysteresis, so break out to local _run
                    return False
            if sourceHash in self._sources and \
               not self._sources[sourceHash].source_valid:
                # Still pending, add this create request to the waiting list
                self._sources[sourceHash].pending_actors.append(envelope)
                return True

        # If the requested ActorClass is compatible with this
        # ActorSystem, attempt to start it, otherwise forward the
        # request to any known compatible ActorSystem.
        childClass = envelope.message.actorClassName
        try:
            childClass = actualActorClass(envelope.message.actorClassName,
                                          partial(loadModuleFromHashSource,
                                                  sourceHash,
                                                  self._sources)
                                          if sourceHash else None)
            acceptsCaps = lambda caps: checkActorCapabilities(childClass, caps,
                                                              childRequirements)
            if not acceptsCaps(self.capabilities):
                if envelope.message.forActor is None:
                    # Request from external; use sender address
                    envelope.message.forActor = envelope.sender
                iolist = self._cstate.forward_pending_to_remote_system(
                    childClass, envelope, sourceHash, acceptsCaps)
                for each in iolist:
                    # Expected to be only one; if the transmit fails,
                    # route it back here so that the next possible
                    # remote can be tried.
                    each.addCallback(onFailure=self._pending_send_failed)
                self._performIO(iolist)
                return True
        except NoCompatibleSystemForActor as ex:
            thesplog(str(ex), level=logging.WARNING, primary=True)
            self._sendPendingActorResponse(
                envelope, None,
                errorCode=PendingActorResponse.ERROR_No_Compatible_ActorSystem)
            return True
        except InvalidActorSourceHash:
            self._sendPendingActorResponse(
                envelope, None,
                errorCode=PendingActorResponse.ERROR_Invalid_SourceHash)
            return True
        except InvalidActorSpecification as ex:
            thesplog('Error: InvalidActorSpecification: %s', str(ex), exc_info=True)
            self._sendPendingActorResponse(
                envelope, None,
                errorCode=PendingActorResponse.ERROR_Invalid_ActorClass,
                errorStr=str(ex))
            return True
        except ImportError as ex:
            self._sendPendingActorResponse(
                envelope, None,
                errorCode=PendingActorResponse.ERROR_Import,
                errorStr=str(ex))
            return True
        except AttributeError as ex:
            # Usually when the module has no attribute FooActor
            thesplog('Error: AttributeError: %s', str(ex), exc_info=True)
            self._sendPendingActorResponse(
                envelope, None,
                errorCode=PendingActorResponse.ERROR_Invalid_ActorClass,
                errorStr=str(ex))
            return True
        except Exception as ex:
            import traceback
            thesplog('Exception "%s" handling PendingActor: %s', ex, traceback.format_exc(), level=logging.ERROR)
            self._sendPendingActorResponse(
                envelope, None,
                errorCode=PendingActorResponse.ERROR_Invalid_ActorClass,
                errorStr=str(ex))
            return True
        return super(ConventioneerAdmin, self).h_PendingActor(envelope)
示例#5
0
 def h_PendingActor(self, envelope):
     sourceHash = envelope.message.sourceHash
     childRequirements = envelope.message.targetActorReq
     thesplog('Pending Actor request for %s%s reqs %s from %s',
              envelope.message.actorClassName,
              ' (%s)' % sourceHash if sourceHash else '', childRequirements,
              envelope.sender)
     # If this request was forwarded by a remote Admin and the
     # sourceHash is not known locally, request it from the sending
     # remote Admin
     if sourceHash and \
        sourceHash not in self._sources and \
        self._sentByRemoteAdmin(envelope) and \
        self._acceptsRemoteLoadedSourcesFrom(envelope):
         requestedAlready = self._pendingSources.get(sourceHash, False)
         self._pendingSources.setdefault(sourceHash, []).append(envelope)
         if not requestedAlready:
             self._hysteresisSender.sendWithHysteresis(
                 TransmitIntent(envelope.sender,
                                SourceHashTransferRequest(sourceHash)))
             return False  # sent with hysteresis, so break out to local _run
         return True
     # If the requested ActorClass is compatible with this
     # ActorSystem, attempt to start it, otherwise forward the
     # request to any known compatible ActorSystem.
     try:
         childClass = actualActorClass(
             envelope.message.actorClassName,
             partial(loadModuleFromHashSource, sourceHash, self._sources)
             if sourceHash else None)
         acceptsCaps = lambda caps: checkActorCapabilities(
             childClass, caps, childRequirements)
         if not acceptsCaps(self.capabilities):
             if envelope.message.forActor is None:
                 # Request from external; use sender address
                 envelope.message.forActor = envelope.sender
             remoteCandidates = [
                 K for K in self._conventionMembers
                 if not self._conventionMembers[K].registryValid.expired()
                 and self._conventionMembers[K].remoteAddress !=
                 envelope.sender  # source Admin
                 and self._conventionMembers[K].remoteAddress not in
                 getattr(envelope.message, 'alreadyTried', []) and
                 acceptsCaps(self._conventionMembers[K].remoteCapabilities)
             ]
             if not remoteCandidates:
                 if self.isConventionLeader():
                     thesplog(
                         'No known ActorSystems can handle a %s for %s',
                         childClass,
                         envelope.message.forActor,
                         level=logging.WARNING,
                         primary=True)
                     self._sendPendingActorResponse(
                         envelope,
                         None,
                         errorCode=PendingActorResponse.
                         ERROR_No_Compatible_ActorSystem)
                     return True
                 # Let the Convention Leader try to find an appropriate ActorSystem
                 bestC = self._conventionAddress
             else:
                 # distribute equally amongst candidates
                 C = [(self._conventionMembers[K].remoteAddress,
                       len(self._conventionMembers[K].hasRemoteActors))
                      for K in remoteCandidates]
                 bestC = foldl(
                     lambda best, possible: best
                     if best[1] <= possible[1] else possible, C)[0]
                 thesplog('Requesting creation of %s%s on remote admin %s',
                          envelope.message.actorClassName,
                          ' (%s)' % sourceHash if sourceHash else '', bestC)
             envelope.message.alreadyTried.append(self.myAddress)
             self._send_intent(TransmitIntent(bestC, envelope.message))
             return True
     except InvalidActorSourceHash:
         self._sendPendingActorResponse(
             envelope,
             None,
             errorCode=PendingActorResponse.ERROR_Invalid_SourceHash)
         return True
     except InvalidActorSpecification:
         self._sendPendingActorResponse(
             envelope,
             None,
             errorCode=PendingActorResponse.ERROR_Invalid_ActorClass)
         return True
     except ImportError as ex:
         self._sendPendingActorResponse(
             envelope,
             None,
             errorCode=PendingActorResponse.ERROR_Import,
             errorStr=str(ex))
         return True
     except AttributeError as ex:
         # Usually when the module has no attribute FooActor
         self._sendPendingActorResponse(
             envelope,
             None,
             errorCode=PendingActorResponse.ERROR_Invalid_ActorClass,
             errorStr=str(ex))
         return True
     except Exception as ex:
         import traceback
         thesplog('Exception "%s" handling PendingActor: %s', ex,
                  traceback.format_exc())
         self._sendPendingActorResponse(
             envelope,
             None,
             errorCode=PendingActorResponse.ERROR_Invalid_ActorClass,
             errorStr=str(ex))
         return True
     return super(ConventioneerAdmin, self).h_PendingActor(envelope)
示例#6
0
 def h_PendingActor(self, envelope):
     sourceHash = envelope.message.sourceHash
     childRequirements = envelope.message.targetActorReq
     thesplog('Pending Actor request received for %s%s reqs %s from %s',
              envelope.message.actorClassName,
              ' (%s)' % sourceHash if sourceHash else '', childRequirements,
              envelope.sender)
     # If this request was forwarded by a remote Admin and the
     # sourceHash is not known locally, request it from the sending
     # remote Admin
     if sourceHash and \
        sourceHash not in self._sources and \
        self._cstate.sentByRemoteAdmin(envelope) and \
        self._acceptsRemoteLoadedSourcesFrom(envelope):
         requestedAlready = self._pendingSources.get(sourceHash, False)
         self._pendingSources.setdefault(sourceHash, []).append(envelope)
         if not requestedAlready:
             self._hysteresisSender.sendWithHysteresis(
                 TransmitIntent(envelope.sender,
                                SourceHashTransferRequest(sourceHash)))
             return False  # sent with hysteresis, so break out to local _run
         return True
     # If the requested ActorClass is compatible with this
     # ActorSystem, attempt to start it, otherwise forward the
     # request to any known compatible ActorSystem.
     childClass = envelope.message.actorClassName
     try:
         childClass = actualActorClass(
             envelope.message.actorClassName,
             partial(loadModuleFromHashSource, sourceHash, self._sources)
             if sourceHash else None)
         acceptsCaps = lambda caps: checkActorCapabilities(
             childClass, caps, childRequirements)
         if not acceptsCaps(self.capabilities):
             if envelope.message.forActor is None:
                 # Request from external; use sender address
                 envelope.message.forActor = envelope.sender
             iolist = self._cstate.forward_pending_to_remote_system(
                 childClass, envelope, sourceHash, acceptsCaps)
             for each in iolist:
                 # Expected to be only one; if the transmit fails,
                 # route it back here so that the next possible
                 # remote can be tried.
                 each.addCallback(onFailure=self._pending_send_failed)
             self._performIO(iolist)
             return True
     except NoCompatibleSystemForActor as ex:
         thesplog(str(ex), level=logging.WARNING, primary=True)
         self._sendPendingActorResponse(
             envelope,
             None,
             errorCode=PendingActorResponse.ERROR_No_Compatible_ActorSystem)
         return True
     except InvalidActorSourceHash:
         self._sendPendingActorResponse(
             envelope,
             None,
             errorCode=PendingActorResponse.ERROR_Invalid_SourceHash)
         return True
     except InvalidActorSpecification:
         self._sendPendingActorResponse(
             envelope,
             None,
             errorCode=PendingActorResponse.ERROR_Invalid_ActorClass)
         return True
     except ImportError as ex:
         self._sendPendingActorResponse(
             envelope,
             None,
             errorCode=PendingActorResponse.ERROR_Import,
             errorStr=str(ex))
         return True
     except AttributeError as ex:
         # Usually when the module has no attribute FooActor
         self._sendPendingActorResponse(
             envelope,
             None,
             errorCode=PendingActorResponse.ERROR_Invalid_ActorClass,
             errorStr=str(ex))
         return True
     except Exception as ex:
         import traceback
         thesplog('Exception "%s" handling PendingActor: %s',
                  ex,
                  traceback.format_exc(),
                  level=logging.ERROR)
         self._sendPendingActorResponse(
             envelope,
             None,
             errorCode=PendingActorResponse.ERROR_Invalid_ActorClass,
             errorStr=str(ex))
         return True
     return super(ConventioneerAdmin, self).h_PendingActor(envelope)
示例#7
0
 def h_PendingActor(self, envelope):
     sourceHash = envelope.message.sourceHash
     childRequirements = envelope.message.targetActorReq
     # If this request was forwarded by a remote Admin and the
     # sourceHash is not known locally, request it from the sending
     # remote Admin
     if sourceHash and \
        sourceHash not in self._sources and \
        self._sentByRemoteAdmin(envelope) and \
        self._acceptsRemoteLoadedSourcesFrom(envelope):
         requestedAlready = self._pendingSources.get(sourceHash, False)
         self._pendingSources.setdefault(sourceHash, []).append(envelope)
         if not requestedAlready:
             self._hysteresisSender.sendWithHysteresis(
                 TransmitIntent(envelope.sender,
                                SourceHashTransferRequest(sourceHash)))
             return False  # sent with hysteresis, so break out to local _run
         return True
     # If the requested ActorClass is compatible with this
     # ActorSystem, attempt to start it, otherwise forward the
     # request to any known compatible ActorSystem.
     try:
         childClass = actualActorClass(envelope.message.actorClassName,
                                       partial(loadModuleFromHashSource,
                                               sourceHash,
                                               self._sources)
                                       if sourceHash else None)
         acceptsCaps = lambda caps: checkActorCapabilities(childClass, caps,
                                                           childRequirements)
         if not acceptsCaps(self.capabilities):
             if envelope.message.forActor is None:
                 # Request from external; use sender address
                 envelope.message.forActor = envelope.sender
             remoteCandidates = [
                 K
                 for K in self._conventionMembers
                 if not self._conventionMembers[K].registryValid.expired()
                 and self._conventionMembers[K].remoteAddress != envelope.sender # source Admin
                 and acceptsCaps(self._conventionMembers[K].remoteCapabilities)]
             if not remoteCandidates:
                 if self.isConventionLeader():
                     thesplog('No known ActorSystems can handle a %s for %s',
                              childClass, envelope.message.forActor,
                              level=logging.WARNING, primary=True)
                     self._sendPendingActorResponse(envelope, None,
                                                    errorCode = PendingActorResponse.ERROR_No_Compatible_ActorSystem)
                     return True
                 # Let the Convention Leader try to find an appropriate ActorSystem
                 bestC = self._conventionAddress
             else:
                 # distribute equally amongst candidates
                 C = [(self._conventionMembers[K].remoteAddress,
                       len(self._conventionMembers[K].hasRemoteActors))
                      for K in remoteCandidates]
                 bestC = foldl(lambda best,possible:
                               best if best[1] <= possible[1] else possible,
                               C)[0]
             self._send_intent(TransmitIntent(bestC, envelope.message))
             return True
     except InvalidActorSourceHash:
         self._sendPendingActorResponse(envelope, None,
                                        errorCode = PendingActorResponse.ERROR_Invalid_SourceHash)
         return True
     except InvalidActorSpecification:
         self._sendPendingActorResponse(envelope, None,
                                        errorCode = PendingActorResponse.ERROR_Invalid_ActorClass)
         return True
     except ImportError:
         self._sendPendingActorResponse(envelope, None,
                                        errorCode = PendingActorResponse.ERROR_Import)
         return True
     return super(ConventioneerAdmin, self).h_PendingActor(envelope)