Žiga Seilnacht <ziga.seilna...@gmail.com> writes: > It is possible to daemonize a process on Windows. I experimented with > adding that support to the twistd script, but got swamped with other > work and couldn't finish it. Below is the code that I have so far. You > can save it in a module and call the daemonize() function from your script.
While this process is certainly doable, I'll also point out that on Windows, the more "natural" approach to this is to implement the process as a service. That also buys you some regular Windows approaches to management (net stop/start from command line, services UI from the control panel) and status inquiry (sc query from command line). So while it may be a little platform-specific code you're final result will integrate more naturally into that environment for any system administrators. While I haven't done this with a twistd based Twisted service, I've done it with a lot of Twisted code in general. It's easiest if you have pywin32 installed and can use it's utility service wrappers, for which the pywin32 package has examples. I've tended to offload the service definition to its own module, and have it just import and execute the main code (with the twisted reactor.run call) after the service gets started - that way you can also manually run the twisted code without involving any of the service support, or to support execution on non-Windows platforms. Here's one example of a service object that invoices Twisted-based code. When stopping, you use callFromThread because the thread that handles the request from the Windows service manager is separate from the thread executing the main code (which is a thread created during the startup process). That's also why you start the reactor without signal initialization, since it'll be in a secondary thread. In SvcDoRun is where you could import platform-generic modules to set up your twisted code, and then this code starts the reactor. Oh, and I left some code in that shows retrieving service-specific parameters from the registry as is typical for Windows services (stored in HKLM/System/CurrentControlSet/Services/<svc_name>/Parameters if I recall corrrectly): - - - - - class DataImportService(win32serviceutil.ServiceFramework): __version__ = '1.0.0' _svc_name_ = 'fdi' _svc_display_name_ = 'SomeCompany Data Integration' stopping = False debug = False def __init__(self, *args, **kwargs): win32serviceutil.ServiceFramework.__init__(self, *args, **kwargs) self.initialize() self._stopped = threading.Event() self.log = None def initialize(self): # This is separate from __init__ so during debugging the bootstrap # code can override __init__ but still finish initialization. def _getOption(self, option, default): return win32serviceutil.GetServiceCustomOption(self._svc_name_, option, default) def SvcStop(self): self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) print '%s Service stopping' % self._svc_display_name_ reactor.callFromThread(reactor.stop) self._stopped.wait(5) print '%s Service stopped' % self._svc_display_name_ if self.log: self.log.close() def SvcDoRun(self): """Main entry point for service execution""" if hasattr(sys, 'frozen'): home_dir = os.path.dirname(sys.executable) else: home_dir = os.path.dirname(__file__) # First, let's set up some logging if self.debug: dupstdout = True logprefix = None else: dupstdout = False logprefix = os.path.join(home_dir, 'logs', 'dataimport.log') self.log = LogClass(logprefix, dupstdout) # And then reroute stdout/stderr to that file object sys.stdout = self.log sys.stderr = self.log print '%s Service %s starting' % (self._svc_display_name_, self.__version__) try: # Process config file config_file = self._getOption('config', os.path.join(home_dir, 'data', 'dataimport.ini')) # ... other service-related initialization ... # ... do any Twisted related initialization ... # Start everything up reactor.callLater(0, self.log.write, '%s Service operational\n' % self._svc_display_name_) reactor.run(installSignalHandlers=False) # We're shutting down. # ... do any shutdown processing ... # Flag that we're exiting so service thread can be more # accurate in terms of declaring shutdown. self._stopped.set() except: # For right now just log a traceback and abort log.err() # But try to gracefully close down log to let final traceback # information make it out to the log file. if self.log: self.log.close() - - - - - Your main startup code in the service wrapper module can use helper functions from win32serviceutil for startup (see the pywin32 examples) which provides some automatic support for installing/uninstalling the service, or you can implement your own startup if you want to support different options and what not. This all works under py2exe as well if you want to package things up and have a nice self-contained exe as a Windows service. -- David _______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python