class BaseManager(object): ''' Base class for managers ''' def __init__(self, address=None, authkey=None): ''' `address`: The address on which manager should listen for new connections. If `address` is None then an arbitrary one is chosen (which will be available as `self.address`). `authkey`: Only connections from clients which are using `authkey` as an authentication key will be accepted. If `authkey` is `None` then `currentProcess().getAuthKey()` is used. ''' self._address = address # XXX not necessarily the final address if authkey is None: self._authkey = authkey = currentProcess().getAuthKey() else: self._authkey = authkey assert type(authkey) is str self._started = False def start(self): ''' Spawn a server process for this manager object ''' assert not self._started self._started = True self._registry, _ = BaseManager._getRegistryCreators(self) # pipe over which we will retreive address of server reader, writer = Pipe(duplex=False) # spawn process which runs a server self._process = Process( target=self._runServer, args=(self._registry, self._address, self._authkey, writer), ) ident = ':'.join(map(str, self._process._identity)) self._process.setName(type(self).__name__ + '-' + ident) self._process.setAuthKey(self._authkey) self._process.start() # get address of server writer.close() self._address = reader.recv() reader.close() # register a finalizer self.shutdown = Finalize(self, BaseManager._finalizeManager, args=(self._process, self._address, self._authkey), exitpriority=0) @classmethod def _runServer(cls, registry, address, authkey, writer): ''' Create a server, report its address and run it ''' # create server server = Server(registry, address, authkey) currentProcess()._server = server # inform parent process of the server's address writer.send(server.address) writer.close() # run the manager info('manager serving at %r', server.address) server.serveForever() def serveForever(self, verbose=True): ''' Start server in the current process ''' assert not self._started self._started = True registry, _ = BaseManager._getRegistryCreators(self) server = Server(registry, self._address, self._authkey) currentProcess()._server = server if verbose: print >>sys.stderr, '%s serving at address %s' % \ (type(self).__name__, server.address) server.serveForever() @classmethod def fromAddress(cls, address, authkey): ''' Create a new manager object for a pre-existing server process ''' manager = cls(address, authkey) transact(address, authkey, 'dummy') manager._started = True return manager def _create(self, typeid, *args, **kwds): ''' Create a new shared object; return the token and exposed tuple ''' assert self._started id, exposed = transact(self._address, self._authkey, 'create', (typeid, ) + args, kwds) return Token(typeid, self._address, id), exposed def join(self, timeout=None): ''' Join the manager process (if it has been spawned) ''' self._process.join(timeout) def _debugInfo(self): ''' Return some info about the servers shared objects and connections ''' return transact(self._address, self._authkey, 'debugInfo') def _proxyFromToken(self, token): ''' Create a proxy for a token ''' assert token.address == self.address _, creators = BaseManager._getRegistryCreators(self) proxytype = creators[token.typeid]._proxytype return proxytype(token, authkey=self._authkey) @staticmethod def _getRegistryCreators(self_or_cls): registry = {} creators = {} for name in dir(self_or_cls): obj = getattr(self_or_cls, name) info = getattr(obj, '_manager_info', None) if info is not None and hasattr(obj, '__call__'): creators[name] = obj typeid, callable, exposed = info assert typeid not in registry, 'typeids must be unique' registry[typeid] = (callable, exposed) return registry, creators def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): self.shutdown() @staticmethod def _finalizeManager(process, address, authkey): ''' Shutdown the manager process; will be registered as a finalizer ''' if process.isAlive(): info('sending shutdown message to manager') try: transact(address, authkey, 'shutdown') except (SystemExit, KeyboardInterrupt): raise except Exception: pass process.join(timeout=0.2) if process.isAlive(): info('manager still alive') if hasattr(process, 'terminate'): info('trying to `terminate()` manager process') process.terminate() process.join(timeout=0.1) if process.isAlive(): info('manager still alive after terminate') try: del BaseProxy._address_to_local[address] except KeyError: pass address = property(lambda self: self._address) # deprecated from_address = fromAddress serve_forever = serveForever
class BaseManager(object): ''' Base class for managers ''' def __init__(self, address=None, authkey=None): ''' `address`: The address on which manager should listen for new connections. If `address` is None then an arbitrary one is chosen (which will be available as `self.address`). `authkey`: Only connections from clients which are using `authkey` as an authentication key will be accepted. If `authkey` is `None` then `currentProcess().getAuthKey()` is used. ''' self._address = address # XXX not necessarily the final address if authkey is None: self._authkey = authkey = currentProcess().getAuthKey() else: self._authkey = authkey assert type(authkey) is str self._started = False def start(self): ''' Spawn a server process for this manager object ''' assert not self._started self._started = True self._registry, _ = BaseManager._getRegistryCreators(self) # pipe over which we will retreive address of server reader, writer = Pipe(duplex=False) # spawn process which runs a server self._process = Process( target=self._runServer, args=(self._registry, self._address, self._authkey, writer), ) ident = ':'.join(map(str, self._process._identity)) self._process.setName(type(self).__name__ + '-' + ident) self._process.setAuthKey(self._authkey) self._process.start() # get address of server writer.close() self._address = reader.recv() reader.close() # register a finalizer self.shutdown = Finalize( self, BaseManager._finalizeManager, args=(self._process, self._address, self._authkey), exitpriority=0 ) @classmethod def _runServer(cls, registry, address, authkey, writer): ''' Create a server, report its address and run it ''' # create server server = Server(registry, address, authkey) currentProcess()._server = server # inform parent process of the server's address writer.send(server.address) writer.close() # run the manager info('manager serving at %r', server.address) server.serveForever() def serveForever(self, verbose=True): ''' Start server in the current process ''' assert not self._started self._started = True registry, _ = BaseManager._getRegistryCreators(self) server = Server(registry, self._address, self._authkey) currentProcess()._server = server if verbose: print >>sys.stderr, '%s serving at address %s' % \ (type(self).__name__, server.address) server.serveForever() @classmethod def fromAddress(cls, address, authkey): ''' Create a new manager object for a pre-existing server process ''' manager = cls(address, authkey) transact(address, authkey, 'dummy') manager._started = True return manager def _create(self, typeid, *args, **kwds): ''' Create a new shared object; return the token and exposed tuple ''' assert self._started id, exposed = transact( self._address, self._authkey, 'create', (typeid,) + args, kwds ) return Token(typeid, self._address, id), exposed def join(self, timeout=None): ''' Join the manager process (if it has been spawned) ''' self._process.join(timeout) def _debugInfo(self): ''' Return some info about the servers shared objects and connections ''' return transact(self._address, self._authkey, 'debugInfo') def _proxyFromToken(self, token): ''' Create a proxy for a token ''' assert token.address == self.address _, creators = BaseManager._getRegistryCreators(self) proxytype = creators[token.typeid]._proxytype return proxytype(token, authkey=self._authkey) @staticmethod def _getRegistryCreators(self_or_cls): registry = {} creators = {} for name in dir(self_or_cls): obj = getattr(self_or_cls, name) info = getattr(obj, '_manager_info', None) if info is not None and hasattr(obj, '__call__'): creators[name] = obj typeid, callable, exposed = info assert typeid not in registry, 'typeids must be unique' registry[typeid] = (callable, exposed) return registry, creators def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): self.shutdown() @staticmethod def _finalizeManager(process, address, authkey): ''' Shutdown the manager process; will be registered as a finalizer ''' if process.isAlive(): info('sending shutdown message to manager') try: transact(address, authkey, 'shutdown') except (SystemExit, KeyboardInterrupt): raise except Exception: pass process.join(timeout=0.2) if process.isAlive(): info('manager still alive') if hasattr(process, 'terminate'): info('trying to `terminate()` manager process') process.terminate() process.join(timeout=0.1) if process.isAlive(): info('manager still alive after terminate') try: del BaseProxy._address_to_local[address] except KeyError: pass address = property(lambda self: self._address) # deprecated from_address = fromAddress serve_forever = serveForever