windows平台把python程序制作成windows服务并开机启动(实践的坑)

简介


通常在windows平台上开发完python服务后,需要通过引用虚拟环境后再运行,或者使用IDE软件启动,但如果想做成开机启动的本地服务,每次都这样启动就太麻烦了。 

该文档介绍这个方法是把python程序制作成一个windows,启停特别方便,而且还可以设置开机启动。虚拟环境依赖的库也不需要考虑,只要在构建的时候在虚拟环境下构建,就会自动将依赖的库打包进去。


1、首先,有一段大家通用的代码,可以将python程序制作成服务。直接拷贝使用即可,在SvcDoRun函数内写上拉起自己服务的代码。


# -*- coding:utf-8 -*-

import win32serviceutil

import win32service

import win32event

import sys

import os

#设置编码

reload(sys)

sys.setdefaultencoding('utf-8')

#windows服务中显示的名字

class zlsService(win32serviceutil.ServiceFramework):

_svc_name_ ='web_movie' ###可以根据自己喜好修改

    _svc_display_name_ ='web_movie'  ###可以根据自己喜好修改

    _svc_description_ ='web_movie'  ###可以根据自己喜好修改

    def __init__(self,args):

win32serviceutil.ServiceFramework.__init__(self,args)

self.stop_event = win32event.CreateEvent(None,0,0,None)

self.run =True

    def SvcDoRun(self):

# 这里是你的启动代码,由于我的是flask框架程序,只需要把我的主文件from过来即可。

from web_movieimport app

app.run()

def SvcStop(self):

self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)

win32event.SetEvent(self.stop_event)

self.ReportServiceStatus(win32service.SERVICE_STOPPED)

self.run =False

if __name__ =='__main__':

import sys

import servicemanager

if len(sys.argv) ==1:

try:

evtsrc_dll = os.path.abspath(servicemanager.__file__)

servicemanager.PrepareToHostSingle(zlsService)#如果修改过名字,名字要统一

            servicemanager.Initialize('zlsService',evtsrc_dll)#如果修改过名字,名字要统一

            servicemanager.StartServiceCtrlDispatcher()

except win32service.erroras details:

import winerror

if details == winerror.ERROR_FAILED_SERVICE_CONTROLLER_CONNECT:

win32serviceutil.usage()

else:

win32serviceutil.HandleCommandLine(zlsService)#如果修改过名字,名字要统一


2、安装构建环境需要用的库,在虚拟环境内安装即可。


pip install PyInstaller==3.4

pip install pywin32==224


3、编写构建bat,其实就几个cmd命令,但是为了方便调试,我还是写成了一个脚本。


:: 停止运行的服务

sc stop web_movie

:: 删除这个服务

sc delete web_movie

:: 等个几秒钟,服务刚停止,文件不会马上释放,不然文件不让删除

TIMEOUT /T 3

:: 删除旧版本构建的内容

rmdir /s/q dist

rmdir /s/q build

del PythonService.spec

:: 构建现在的程序,这里有个坑,由于templates目录和static目录和代码不是直接引用,在pyinstaller构建的时候会忽略,导致服务无法运行,后面详细介绍。

pyinstaller -F --add-data "templates;templates" --add-data "static;static" PythonService.py

:: 将构建好的exe程序安装到系统服务

dist\PythonService.exe install

:: 启动服务

sc start web_movie


4、这时候在任务管理器里面就可以看到已经运行的服务了


5、如果不能启动,排查方法


如果启动后立即停止,或者弹窗说“服务没有及时响应启动或控制请求”,这时候可以查看windows的计算机管理界面应用日志,来看详细信息。

6、我遇到的坑


Traceback (most recent call last):

File "site-packages\win32\lib\win32serviceutil.py", line 839, in SvcRun

File "PythonService.py", line 28, in SvcDoRun

File "site-packages\flask\app.py", line 943, in run

File "site-packages\werkzeug\serving.py", line 812, in run_simple

File "site-packages\werkzeug\_reloader.py", line 267, in run_with_reloader

ValueError: signal only works in main thread

上面这个报错使我的代码出现过得,经过我的各种最小化测试,发现这个错误是加载配置项的时候就会出现,最终定位到了我的一行配置文件。

DEBUG =True,这一行配置让我排查了整整一天。


7、我遇到的坑


修复了上面的问题,我的的服务终于起来了,但是又发现,在浏览器里面竟然无法访问。如下提示:

Internal Server Error

The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.

这个问题也让我苦恼了很久,在我最小化测试的时候,缩减到仅剩一个hello world都无法正常显示,但是创建一个新的flask项目就可以正常显示,经过我细心的diff这两个项目,

发现我在return的时候使用了render_template模板,然而这个目录在pyinstaller的时候,并没有打包进来,然后这一切都明白了,就是因为在构建的时候没有将这个目录添加进来,

导致项目启动后无法使用模板文件。

修复方法就是bat文件内写的,添加上静态目录的编译就可以了。

pyinstaller -F --add-data "templates;templates" --add-data "static;static" PythonService.py

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 0 前言 = 瞎说 能写web的语言有好多。python算是难度较低,入门较快的脚本语言。Django是pytho...
    hubery24阅读 2,070评论 0 3
  • 接口测试自动化的优点: 1,web自动化说起来很多人都会直接想到UI自动化这个设计,很少有人直接第一个概念是接口自...
    路边看雪的小男孩阅读 4,951评论 1 26
  • [TOC] 最开始写程序的时候,都是一个文件里输入几行源码(python 的一个 web 框架bottle就特别强...
    人世间阅读 5,662评论 1 10
  • 心理线(PSY)是一个比较“冷门”的技术指标, 投资者对它的实际运用不多,甚至连钱龙动态分析软件里也没有心理线,可...
    朱水火阅读 257评论 0 1
  • spearman秩相关系数 pearson线性相关系数要求连续变量的取值服从正态分布。不服从正态分布的变量、分类或...
    AliceGYY阅读 700评论 0 0