【问题标题】:How do I terminate a flask app that's running as a service?如何终止作为服务运行的烧瓶应用程序?
【发布时间】:2014-06-26 14:31:32
【问题描述】:

感谢Is it possible to run a Python script as a service in Windows? If possible, how?,我能够让我的烧瓶应用程序作为服务运行,但是在停止它时我不能。我必须终止任务管理器中的进程。

这是我的 run.py,我通过 run.py install 将它变成了一个服务:

from app import app

from multiprocessing import Process
import win32serviceutil
import win32service
import win32event
import servicemanager
import socket


class AppServerSvc (win32serviceutil.ServiceFramework):
    _svc_name_ = "CCApp"
    _svc_display_name_ = "CC App"

    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)
        server.terminate()
        server.join()

    def SvcDoRun(self):
        servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                              servicemanager.PYS_SERVICE_STARTED,
                              (self._svc_name_,''))
        self.main()

    def main(self):
        server = Process(app.run(host = '192.168.1.6'))
        server.start()

if __name__ == '__main__':
    win32serviceutil.HandleCommandLine(AppServerSvc)

我从这篇文章中得到了过程的东西:http://librelist.com/browser/flask/2011/1/10/start-stop-flask/#a235e60dcaebaa1e134271e029f801fe,但不幸的是它也不起作用。

事件查看器中的日志文件显示未定义全局变量“服务器”。但是,我将 server 设置为全局变量,但它仍然给我同样的错误。

【问题讨论】:

  • 好的,这有一些问题。 1. server 未在SvcStop 中定义,这就是您收到该错误消息的原因。 2. server = Process(app.run(host = '192.168.1.6')) 没有做你认为的事情。为什么您认为无论如何都需要在单独的进程中运行应用程序?
  • 你是如何将 server 设置为全局变量的?局部变量在 Python 中会自动影响全局变量,因此您可能需要 use the global statement 才能分配给局部范围内的全局变量。
  • @univerio 我只添加了该服务器和进程代码,因为我正在寻找一种方法来终止 SvcStop 中的服务器。烧瓶有 app.run(),但没有 app.stop() 或等效项。
  • @uranusjr 我确实尝试过,通过这样做:global server server = Process(app.run(host= '192.168.1.6'))
  • Flask 监听 SIGINT 以查看它是否应该退出。也许您可以在SvcStop 中向自己发送信号?或者,如果您真的想在单独的进程中运行应用程序,请确保将 target 关键字 arg 设置为 app.run 而不是直接调用 app.run

标签: python windows service flask


【解决方案1】:

您可以在停止 Win32 服务器之前正常停止 Werkzeug Web 服务器。示例:

from flask import request

def shutdown_server():
    func = request.environ.get('werkzeug.server.shutdown')
    if func is None:
        raise RuntimeError('Not running with the Werkzeug Server')
    func()

@app.route('/shutdown', methods=['POST'])
def shutdown():
    shutdown_server()
    return 'Server shutting down...'

如果你把它添加到你的 Flask 服务器中,你可以通过向 /shutdown 发送一个 POST 请求来请求正常关闭服务器。您可以使用 requests 或 urllib2 来执行此操作。根据您的情况,您可能需要保护此路由免受未经授权的访问。

一旦服务器停止,我认为您将没有问题停止 Win32 服务。

注意上面的关闭代码出现在这个Flask snippet中。

【讨论】:

  • 感谢您的回复。我开始实现这一点,但在与朋友交谈时确信欺骗开发服务器作为服务运行并不是我所拥有的最好的想法。无论如何,正如下面发布的那样,我最终设置了一个真实的服务器来托管我的网络应用程序!另外,不得不说是你的博客让我开始编写 Flask。所以,米格尔干杯!
  • 有没有办法获得零返回值?
【解决方案2】:

你也可以欺骗 Flask 让它相信你按下了 Ctrl + C

def shutdown_flask(self):
    from win32api import GenerateConsoleCtrlEvent
    CTRL_C_EVENT = 0
    GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0)

然后只需在您的SvcStop() 中调用shutdown_flask()

try:
    # try to exit gracefully
    self.shutdown_flask()
except Exception as e:
    # force quit
    os._exit(0)

如果 shutdown_flask() 因某种原因失败,os._exit() 会通过停止解释器来确保您的服务将结束(尽管有一个讨厌的警告)。

【讨论】:

    【解决方案3】:

    我建议您使用http://supervisord.org/。实际上不适用于 Windows,但使用 Cygwin,您可以像在 Linux 中一样运行 supervisor,包括作为服务运行。

    对于安装 Supervisord:https://stackoverflow.com/a/18032347/3380763

    安装后必须配置应用,这里举个例子:http://flaviusim.com/blog/Deploying-Flask-with-nginx-uWSGI-and-Supervisor/(不是必须用Nginx加上Supervisor的配置就够了)

    【讨论】:

    • 谢谢。我没有走你建议的路线,但我最终得到了一个带有 nginx 和 uwsgi 的 Ubuntu 服务器。
    猜你喜欢
    • 2018-07-06
    • 2015-07-05
    • 1970-01-01
    • 2016-12-09
    • 1970-01-01
    • 1970-01-01
    • 2018-12-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多