I have a Django app that I'm trying to run via Cherrypy on Windows Server. I have below code in the service creation script.
import os
import sys
service_directory = os.path.dirname(__file__)
source_directory = os.path.abspath(service_directory)
os.chdir(source_directory)
venv_base = os.path.abspath(os.path.join(source_directory, ".venv"))
print(venv_base)
sys.path.append(".")
old_os_path = os.environ['PATH']
os.environ['PATH'] = os.path.join(venv_base, "Scripts")+ os.pathsep + old_os_path
site_packages = os.path.join(venv_base, "Lib", "site-packages")
prev_sys_path = list(sys.path)
import site
site.addsitedir(site_packages)
sys.real_prefix = sys.prefix
sys.prefix = venv_base
new_sys_path = list()
for item in list(sys.path):
if item not in prev_sys_path:
new_sys_path.append(item)
sys.path.remove(item)
sys.path[:0] = new_sys_path
import pathlib
import subprocess
import traceback
import servicemanager
import win32event
import win32service
import win32serviceutil
from win32api import SetConsoleCtrlHandler
class AppServerSvc(win32serviceutil.ServiceFramework):
"""
Service Create class
"""
_svc_name_ = "MyService" # service name
_svc_display_name_ = "MyService" # display name
def __init__(self, args):
"""
Constructor
"""
win32serviceutil.ServiceFramework.__init__(self, args)
SetConsoleCtrlHandler(lambda x: True, True)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
def SvcStop(self):
"""
Function to stop the windows service
"""
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
self.proc.terminate()
def SvcDoRun(self):
"""
Function to create and start the windows service
"""
self.ReportServiceStatus(win32service.SERVICE_START_PENDING)
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_, ''))
try:
self.main()
except Exception as exp_msg:
servicemanager.LogErrorMsg(traceback.format_exc())
os._exit(-1)
def main(self):
"""
Script to run as the windows service
"""
#env_file.load(f'{os.path.join(pathlib.Path(__file__).parent.absolute(), "config.env")}')
#settings.set_env_variables()
self.ReportServiceStatus(win32service.SERVICE_RUNNING)
self.proc = subprocess.Popen(f"python"
f" {os.path.join(pathlib.Path(__file__).parent.absolute(), 'cherryd.py')} 1"
, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
stdin=subprocess.DEVNULL)
stdout, stderr = self.proc.communicate()
print(stdout)
if (self.proc.poll() == 0):
servicemanager.LogMsg(f"Successfully started the process with PID: {self.proc.pid}")
else:
servicemanager.LogErrorMsg(f"Failed to start the services")
if __name__ == '__main__':
# Start of the process
win32serviceutil.HandleCommandLine(AppServerSvc)
I'm able to install this service using python service.py install, no issues here.
When I start the service python service.py start I get error Error starting service: The service did not respond to the start or control request in a timely fashion.
When I do python service.py debug, everything works normal and I'm able to access the app using FQDN. Why does the service not work when started normally and work only during debug mode.
Have read multiple posts on similar errors but nothing helped. I'm using Python 3.8 and have added the venv Scripts directory to PATH as well. Can someone please help.
Update
Started the service with my user account and it worked, still don't understand how it worked in debug mode.
Related
I want to run some Python code as a service on Windows. I use Python 3.6 by the way.
I have put together (from various sources) this generalized windows daemon class. When I run it, it works well. However, when I subclass this to use in a service that contains some actual useful code, the service is not started but returns immediately with error The service did not respond to the start or control request in a timely fashion.
So - see example below - windows_daemon.py works, but new_service.py does not.
Can anyone see why my python service does not start on windows when I subclass it?
windows_daemon.py
import time
import sys
import logging
import logging.handlers
import traceback
import win32serviceutil
import win32service
import win32event
import servicemanager
import os
def handle(instance):
win32serviceutil.HandleCommandLine(instance)
class windows_daemon(win32serviceutil.ServiceFramework):
# you can NET START/STOP the service by the following name
_svc_name_ = "Daemon"
# this text shows up as the service name in the Service
# Control Manager (SCM)
_svc_display_name_ = "Windows daemon"
# this text shows up as the description in the SCM
_svc_description_ = "This service controls some stuff"
# list dependencies
_svc_deps_ = ["EventLog"]
def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self,args)
# create an event to listen for stop requests on
self.hWaitStop = win32event.CreateEvent(None,0,0,None)
self.Alive = True
self.host = os.environ['COMPUTERNAME'].lower()
self.pid = os.getpid()
self.name = self._svc_display_name_
self.rootlogger = logging.getLogger()
#self.logger = logging.getLogger("{}".format(self.name))
self.rootlogger.setLevel(logging.DEBUG)
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
handler = logging.handlers.RotatingFileHandler("{0}\log\{1}.log".format(os.path.dirname(os.path.realpath(__file__)), self.name), maxBytes = 1000000, backupCount = 5)
handler.setFormatter(formatter)
self.rootlogger.addHandler(handler)
self.logger = logging.getLogger("service")
# called when we're being shut down
def SvcStop(self):
self.logger.info("stopping service")
# tell the SCM we're shutting down
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
# fire the stop event
win32event.SetEvent(self.hWaitStop)
self.Alive = False
# core logic of the service
def SvcDoRun(self):
self.ReportServiceStatus(win32service.SERVICE_RUNNING)
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_, ''))
self.logger.debug("starting service")
self.timeout = 100
try:
self.main()
self.logger.debug("no exception in main")
exitcode = 0
except Exception as e:
#could also debug to Windows event log
#servicemanager.LogErrorMsg(traceback.format_exc())
#servicemanager.LogErrorMsg("{}".format(e))
try:
self.logger.error(e)
self.logger.error(traceback.format_exc())
except Exception as e:
pass
# servicemanager.LogErrorMsg("{}".format(e))
#return some value other than 0 to os so that service knows to restart
self.logger.error("some exception in main")
exitcode = -1
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STOPPED,
(self._svc_name_, ''))
self.ReportServiceStatus(win32service.SERVICE_STOPPED)
self.logger.info("stopped with exit code {}".format(exitcode))
os._exit(exitcode)
def check_for_signals(self, timeout = 100):
rc = win32event.WaitForSingleObject(self.hWaitStop, self.timeout)
def main(self):
# override in subclass
print("this is function main() that should be subclassed")
#time.sleep(1)
pass
if __name__ == '__main__':
handle(windows_daemon)
print("you should subclass windows_daemon from this module")
new_service.py
from windows_daemon import windows_daemon, handle
import time
import sys
import win32serviceutil
class New_service(windows_daemon):
# you can NET START/STOP the service by the following name
_svc_name_ = "NEW"
# this text shows up as the service name in the Service
# Control Manager (SCM)
_svc_display_name_ = "New service"
# this text shows up as the description in the SCM
_svc_description_ = "This service exists as a template for new services"
# override dependencies?
# _svc_deps_ = ["EventLog"]
def __init__(self, args):
print(super())
super().__init__(args)
def main(self):
time.sleep(10)
if __name__ == '__main__':
sys.frozen = 'windows_exe'
handle(New_service)
Apparently, this line caused the problem. I found that by learning about the python debugging module (pdb) and using it to investigate.
sys.frozen = 'windows_exe'
When I removed this line, the new_service.py also ran. Hope this helps someone in the future.
I need to run my python app as windows service.
I'm able to do that using commands,python fservice.py install
python fservice.py start
Now, i want to create exe for my app using py2exe.
I've followed code from this question: link
setup.py
from distutils.core import setup
import py2exe
import sys
if len(sys.argv) == 1:
sys.argv.append("py2exe")
sys.argv.append("-q")
class Target:
def __init__(self, **kw):
self.__dict__.update(kw)
# for the versioninfo resources
self.version = "0.0.1"
self.company_name = "flotomate"
self.copyright = "no copyright"
self.name = "flotomate"
myservice = Target(
# used for the versioninfo resource
description = "flotomate",
# what to build. For a service, the module name (not the
# filename) must be specified!
modules = ["fservice"]
)
setup(
service = [myservice]
)
fservice.py
import sys
import servicemanager
import win32serviceutil
import win32service
import win32event
import win32api
from pagent import app
class fservice(win32serviceutil.ServiceFramework):
_svc_name_ = 'flotomate' #here is now the name you would input as an arg for instart
_svc_display_name_ = 'flotomate' #arg for instart
_svc_description_ = 'flotomate'# arg from instart
def __init__(self, *args):
win32serviceutil.ServiceFramework.__init__(self, *args)
self.log('init')
self.stop_event = win32event.CreateEvent(None, 0, 0, None)
#logs into the system event log
def log(self, msg):
import servicemanager
servicemanager.LogInfoMsg(str(msg))
def sleep(self, minute):
win32api.Sleep((minute*1000), True)
def SvcDoRun(self):
self.ReportServiceStatus(win32service.SERVICE_START_PENDING)
try:
self.ReportServiceStatus(win32service.SERVICE_RUNNING)
self.log('start')
self.start()
self.log('wait')
win32event.WaitForSingleObject(self.stop_event, win32event.INFINITE)
self.log('done')
except Exception:
self.SvcStop()
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
self.stop()
win32event.SetEvent(self.stop_event)
self.ReportServiceStatus(win32service.SERVICE_STOPPED)
def start(self):
app.run(host='0.0.0.0',port=4999)
# to be overridden
def stop(self):
pass
if __name__ == '__main__':
if len(sys.argv) == 1:
servicemanager.Initialize()
servicemanager.PrepareToHostSingle(fservice)
servicemanager.StartServiceCtrlDispatcher()
else:
win32serviceutil.HandleCommandLine(fservice)
I'm creating exe using command,python setup.py py2exe
but, when i try to install the service using fservice.exe --install
I get this error
Traceback (most recent call last):
File "boot_service.py", line 37, in <module>
AttributeError: 'module' object has no attribute 'Initialize
boot_service.py of py2exe
I'm using Python 2.7.6 and py2exe-0.6.9
I encountered the same problem. I don't know whether you found the solution yet
In my case, the reason would be that servicemanager is not included in the compiled package. It seems the installed servicemanager library in python issues conflict.
To solve this problem, I uninstall servicemanager if it is unused or manually copy servicemanager.pyd to folder dist and servicemager.pyc to dist\library.zip. If there is a folder named servicemanager in dist\library.zip, just delete it.
If you already had a better solution, please share it ^^
I've implemented a windows service, this service has no problem before compiling with pyinstaller but after that on service start command it gives 1053 error.
Windows service code:
import sys
import win32service
import win32event
import socket
import win32api
import win32serviceutil
class AppServerSvc(win32serviceutil.ServiceFramework):
_svc_name_ = "test"
_svc_display_name_ = "test"
_stoped = False
def __init__(self, *args):
win32serviceutil.ServiceFramework.__init__(self, *args)
self.stop_event = win32event.CreateEvent(None, 0, 0, None)
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
self._stoped = True
def SvcDoRun(self):
self.ReportServiceStatus(win32service.SERVICE_RUNNING)
self.main()
def main(self):
while True:
if self._stoped:
break
pass
if __name__ == '__main__':
win32serviceutil.HandleCommandLine(AppServerSvc)
Finally i solved this problem, there was a broken link to one of references in windows service. This is the right config for py2exe which solved my problem:
opts = {'py2exe': {
'dll_excludes': ['libzmq.pyd', 'OLEAUT32.dll', 'USER32.dll', 'SHELL32.dll', 'ole32.dll',
'MSVCP90.dll', 'ADVAPI32.dll', 'NETAPI32.dll', 'WS2_32.dll', 'GDI32.dll',
'VERSION.dll', 'KERNEL32.dll', 'WINSPOOL.DRV', 'mfc90.dll', 'ntdll.dll'],
'includes': ['UserList', 'UserString', 'commands', 'zmq.backend.cython'],
'dist_dir': "dist"
}}
setup(service=[service], options=opts, zipfile=None,data_files=[(os.path.join(os.getcwd(), 'dist'), (zmq.libzmq.__file__,))])
To use my win32serviceutil.ServiceFramework class in an exe pyInstaller produced, I needed to add a few .pyd files to the directory containing the exe e.g. win32service.pyd and win32event.pyd. Assuming you've used the standard install paths for your libraries, these files are found here:
C:\Python27\Lib\site-packages\win32
I coded out a windows service in python to write some text to a file continuously and installed it and ran it and it works fine. Now if I try to convert my python windows service script into an executable (.exe) using py2exe. The .exe installs fine as a service but when I try to start it I get the error "The server did not respond to the start ......in timely fashion". Is this got something to do with py2exe destroying information in my python script. How do I go around this? (I am trying to convert it to a .exe because I want to distribute it).
My python script is as follows:
import win32service
import win32serviceutil
import win32event
class clear_queue(win32serviceutil.ServiceFramework):
_svc_name_ = "avant"
_svc_display_name_ = "avant"
_svc_description_ = "Elegant file writer"
def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self,args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
def SvcDoRun(self):
import servicemanager;
fil = open("C:/Users/u/Desktop/c99/user.txt",'r+');
rc = win32event.WaitForSingleObject(self.hWaitStop, 64)
while rc != win32event.WAIT_OBJECT_0:
fil.write("george\n");
rc = win32event.WaitForSingleObject(self.hWaitStop, 64)
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
if __name__ == '__main__':
win32serviceutil.HandleCommandLine(clear_queue)
Looking at the example at http://tools.cherrypy.org/wiki/WindowsService, it looks like you need to add self.ReportServiceStatus(win32service.SERVICE_STOPPED) as the final line of the SvcStop method.
below is my code that I am trying to turn into a windows service. You'll see test.py as the call it makes and all this is a short script that writes into a log file (as a test).
The code is there to make it a windows service and it does that fine, but when I run it nothing writes into the log file. Help greatly appreciated. Below is the code:
import win32service
import win32serviceutil
import win32api
import win32con
import win32event
import win32evtlogutil
import os, sys, string, time
class aservice(win32serviceutil.ServiceFramework):
_svc_name_ = "MyServiceShortName"
_svc_display_name_ = "A python test"
_svc_description_ = "Writing to a log"
def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
def SvcDoRun(self):
import servicemanager
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,servicemanager.PYS_SERVICE_STARTED,(self._svc_name_, ''))
self.timeout = 1000 #1 seconds
# This is how long the service will wait to run / refresh itself (see script below)
while 1:
# Wait for service stop signal, if I timeout, loop again
rc = win32event.WaitForSingleObject(self.hWaitStop, self.timeout)
# Check to see if self.hWaitStop happened
if rc == win32event.WAIT_OBJECT_0:
# Stop signal encountered
servicemanager.LogInfoMsg("SomeShortNameVersion - STOPPED!") #For Event Log
break
else:
#what to run
try:
file_path = "test.py"
execfile(file_path)
except:
pass
#end of what to run
def ctrlHandler(ctrlType):
return True
if __name__ == '__main__':
win32api.SetConsoleCtrlHandler(ctrlHandler, True)
win32serviceutil.HandleCommandLine(aservice)
Edit: Thought for the sake of it I'd include my test.py file's code, it has unnecessary imports but will get the job done if you run it alone.
import win32service
import win32serviceutil
import win32api
import win32con
import win32event
import win32evtlogutil
import os
logfile = open("log.txt", "a") #open file to log restart timestamp
logfile.write("\nthat's good!!!!")
logfile.close()
Okay so I figured it out and would like to come back and post in case anyone else is dealing with this, all though this was a tad unique.
You have to specify your file path if you are within a windows service, duh... but it wasn't done and I pulled my hair out for no reason.
file_path = "test.py"
should have been
file_path = r"c:\users\...\test.py"
Be careful when using '\' for windows file paths. They must be escaped like '\\' or the string must be declared as raw string ('r'). Using the unix like slash '/' separators works also but may look odd for windows users.