¿Cómo se ejecuta un script de Python como servicio en Windows?
Estoy esbozando la arquitectura de un conjunto de programas que comparten varios objetos interrelacionados almacenados en una base de datos. Quiero que uno de los programas actúe como un servicio que proporcione una interfaz de nivel superior para operaciones en estos objetos, y que los otros programas accedan a los objetos a través de ese servicio.
Actualmente estoy apuntando a Python y el marco Django como tecnologías para implementar ese servicio. Estoy bastante seguro de que descubrí cómo demonizar el programa Python en Linux. Sin embargo, es un elemento de especificación opcional que el sistema debería ser compatible con Windows. Tengo poca experiencia con la programación de Windows y ninguna experiencia con los servicios de Windows.
¿Es posible ejecutar programas Python como un servicio de Windows (es decir, ejecutarlo automáticamente sin que el usuario inicie sesión)? No necesariamente tendré que implementar esta parte, pero necesito una idea aproximada de cómo se haría para poder decidir si diseñar según estas líneas.
Editar: Gracias por todas las respuestas hasta ahora, son bastante completas. Me gustaría saber una cosa más: ¿ Cómo sabe Windows mi servicio? ¿Puedo gestionarlo con las utilidades nativas de Windows? ¿Cuál es el equivalente a poner un script de inicio/parada en /etc/init.d?
Sí tu puedes. Lo hago usando las bibliotecas de pythoncom que vienen incluidas con ActivePython o que se pueden instalar con pywin32 (extensiones de Python para Windows).
Este es un esqueleto básico para un servicio simple:
import win32serviceutil
import win32service
import win32event
import servicemanager
import socket
class AppServerSvc (win32serviceutil.ServiceFramework):
_svc_name_ = "TestService"
_svc_display_name_ = "Test Service"
def __init__(self,args):
win32serviceutil.ServiceFramework.__init__(self,args)
self.hWaitStop = win32event.CreateEvent(None,0,0,None)
socket.setdefaulttimeout(60)
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
def SvcDoRun(self):
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_,''))
self.main()
def main(self):
pass
if __name__ == '__main__':
win32serviceutil.HandleCommandLine(AppServerSvc)
Su código iría en el main()
método, generalmente con algún tipo de bucle infinito que podría interrumpirse al marcar una bandera, que usted establece en el SvcStop
método.
La forma más sencilla es utilizar: NSSM, el administrador de servicios sin succión. Simplemente descárguelo y descomprímalo en la ubicación que elija. Es una utilidad autónoma, de alrededor de 300 KB (mucho menos que instalar todo el paquete pywin32 solo para este propósito) y no necesita "instalación". El zip contiene una versión de 64 bits y una de 32 bits de la utilidad. Cualquiera de los dos debería funcionar bien en los sistemas actuales (puede usar la versión de 32 bits para administrar servicios en sistemas de 64 bits).
Enfoque GUI
1 - instale el programa Python como servicio. Abra un mensaje de Win como administrador
c:\>nssm.exe install WinService
2 - En la consola GUI de NSSM:
ruta: C:\Python27\Python27.exe
Directorio de inicio: C:\Python27
Argumentos: c:\WinService.py
3 - verifique los servicios creados en services.msc
Enfoque de secuencias de comandos (sin GUI)
Esto es útil si su servicio debe ser parte de un procedimiento automatizado y no interactivo que puede estar fuera de su control, como un script de instalación o por lotes. Se supone que los comandos se ejecutan con privilegios administrativos.
Para mayor comodidad, los comandos se describen aquí simplemente haciendo referencia a la utilidad como nssm.exe
. Sin embargo, es aconsejable hacer referencia a él de manera más explícita en las secuencias de comandos con su ruta completa c:\path\to\nssm.exe
, ya que es un ejecutable autónomo que puede estar ubicado en una ruta privada que el sistema no conoce.
1. Instalar el servicio
Debe especificar un nombre para el servicio, la ruta al ejecutable de Python adecuado y la ruta al script:
nssm.exe install ProjectService "c:\path\to\python.exe" "c:\path\to\project\app\main.py"
Más explícitamente:
nssm.exe install ProjectService
nssm.exe set ProjectService Application "c:\path\to\python.exe"
nssm.exe set ProjectService AppParameters "c:\path\to\project\app\main.py"
Alternativamente, es posible que desee que su aplicación Python se inicie como un módulo de Python. Un enfoque sencillo es decirle a nssm que necesita cambiar al directorio de inicio adecuado, como lo haría usted mismo al iniciar desde un shell de comandos:
nssm.exe install ProjectService "c:\path\to\python.exe" "-m app.main"
nssm.exe set ProjectService AppDirectory "c:\path\to\project"
Este enfoque funciona bien con entornos virtuales e instalaciones de Python autónomas (integradas). Sólo asegúrese de haber resuelto adecuadamente cualquier problema de ruta en esos entornos con los métodos habituales. nssm tiene una forma de configurar variables de entorno (por ejemplo, PYTHONPATH) si es necesario y también puede iniciar scripts por lotes.
2. Para iniciar el servicio
nssm.exe start ProjectService
3. Para detener el servicio
nssm.exe stop ProjectService
4. Para eliminar el servicio , especifique el confirm
parámetro para omitir la confirmación interactiva.
nssm.exe remove ProjectService confirm
Aunque voté a favor de la respuesta elegida hace un par de semanas, mientras tanto luché mucho más con este tema. Parece que tener una instalación especial de Python y usar módulos especiales para ejecutar un script como servicio es simplemente la forma incorrecta. ¿Qué pasa con la portabilidad y demás?
Me topé con el maravilloso Non-sucking Service Manager , que hizo que manejar los servicios de Windows fuera realmente sencillo y sensato. Pensé que como podía pasar opciones a un servicio instalado, también podía seleccionar mi ejecutable de Python y pasar mi script como una opción.
Todavía no he probado esta solución, pero lo haré ahora mismo y actualizaré esta publicación a lo largo del proceso. También estoy interesado en usar virtualenvs en Windows, por lo que tarde o temprano podría crear un tutorial y vincularlo aquí.
La forma más sencilla de lograr esto es utilizar el comando nativo sc.exe:
sc create PythonApp binPath= "C:\Python34\Python.exe --C:\tmp\pythonscript.py"
Referencias:
- https://technet.microsoft.com/en-us/library/cc990289(v=ws.11).aspx
- Al crear un servicio con sc.exe, ¿cómo pasar parámetros de contexto?