Refactored WSGIServer handling

Restart of gevent server now working
This commit is contained in:
OzzieIsaacs 2018-07-09 18:47:36 +02:00
parent a298470479
commit 404b29b979
5 changed files with 134 additions and 90 deletions

44
cps.py
View File

@ -10,44 +10,12 @@ sys.path.append(base_path)
sys.path.append(os.path.join(base_path, 'cps')) sys.path.append(os.path.join(base_path, 'cps'))
sys.path.append(os.path.join(base_path, 'vendor')) sys.path.append(os.path.join(base_path, 'vendor'))
from cps import web from cps.server import Server
try:
from gevent.pywsgi import WSGIServer
gevent_present = True
except ImportError:
from tornado.wsgi import WSGIContainer
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
gevent_present = False
if __name__ == '__main__': if __name__ == '__main__':
if gevent_present: Server.startServer()
web.app.logger.info('Attempting to start gevent')
web.start_gevent()
else:
web.app.logger.info('Starting Tornado webserver')
# Max Buffersize set to 200MB
if web.ub.config.get_config_certfile() and web.ub.config.get_config_keyfile():
ssl={"certfile": web.ub.config.get_config_certfile(),
"keyfile": web.ub.config.get_config_keyfile()}
else:
ssl=None
http_server = HTTPServer(WSGIContainer(web.app),
max_buffer_size = 209700000,
ssl_options=ssl)
http_server.listen(web.ub.config.config_port)
IOLoop.instance().start()
IOLoop.instance().close(True)
if web.helper.global_task == 0:
web.app.logger.info("Performing restart of Calibre-web")
if os.name == 'nt':
arguments = ["\"" + sys.executable + "\""]
for e in sys.argv:
arguments.append("\"" + e + "\"")
os.execv(sys.executable, arguments)
else:
os.execl(sys.executable, sys.executable, *sys.argv)
else:
web.app.logger.info("Performing shutdown of Calibre-web")
sys.exit(0)

View File

@ -36,12 +36,12 @@ import threading
import shutil import shutil
import requests import requests
import zipfile import zipfile
from tornado.ioloop import IOLoop
try: try:
import gdriveutils as gd import gdriveutils as gd
except ImportError: except ImportError:
pass pass
import web import web
import server
try: try:
import unidecode import unidecode
@ -50,7 +50,6 @@ except ImportError:
use_unidecode = False use_unidecode = False
# Global variables # Global variables
global_task = None
updater_thread = None updater_thread = None
RET_SUCCESS = 1 RET_SUCCESS = 1
@ -388,7 +387,6 @@ class Updater(threading.Thread):
self.status = 0 self.status = 0
def run(self): def run(self):
global global_task
self.status = 1 self.status = 1
r = requests.get('https://api.github.com/repos/janeczku/calibre-web/zipball/master', stream=True) r = requests.get('https://api.github.com/repos/janeczku/calibre-web/zipball/master', stream=True)
fname = re.findall("filename=(.+)", r.headers['content-disposition'])[0] fname = re.findall("filename=(.+)", r.headers['content-disposition'])[0]
@ -400,19 +398,13 @@ class Updater(threading.Thread):
self.status = 4 self.status = 4
self.update_source(os.path.join(tmp_dir, os.path.splitext(fname)[0]), ub.config.get_main_dir) self.update_source(os.path.join(tmp_dir, os.path.splitext(fname)[0]), ub.config.get_main_dir)
self.status = 5 self.status = 5
global_task = 0
db.session.close() db.session.close()
db.engine.dispose() db.engine.dispose()
ub.session.close() ub.session.close()
ub.engine.dispose() ub.engine.dispose()
self.status = 6 self.status = 6
server.Server.setRestartTyp(True)
if web.gevent_server: server.Server.stopServer()
web.gevent_server.stop()
else:
# stop tornado server
server = IOLoop.instance()
server.add_callback(server.stop)
self.status = 7 self.status = 7
def get_update_status(self): def get_update_status(self):

103
cps/server.py Normal file
View File

@ -0,0 +1,103 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from socket import error as SocketError
import sys
import os
try:
from gevent.pywsgi import WSGIServer
from gevent import monkey
from gevent.pool import Pool
from gevent import __version__ as geventVersion
gevent_present = True
except ImportError:
from tornado.wsgi import WSGIContainer
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
from tornado import version as tornadoVersion
gevent_present = False
import web
class server:
wsgiserver = None
restart= False
def __init__(self):
pass
def start_gevent(self):
try:
ssl_args = dict()
if web.ub.config.get_config_certfile() and web.ub.config.get_config_keyfile():
ssl_args = {"certfile": web.ub.config.get_config_certfile(),
"keyfile": web.ub.config.get_config_keyfile()}
if os.name == 'nt':
self.wsgiserver= WSGIServer(('0.0.0.0', web.ub.config.config_port), web.app, spawn=Pool(), **ssl_args)
else:
self.wsgiserver = WSGIServer(('', web.ub.config.config_port), web.app, spawn=Pool(), **ssl_args)
self.wsgiserver.serve_forever()
except SocketError:
web.app.logger.info('Unable to listen on \'\', trying on IPv4 only...')
self.wsgiserver = WSGIServer(('0.0.0.0', web.ub.config.config_port), web.app, spawn=Pool(), **ssl_args)
self.wsgiserver.serve_forever()
except:
pass
def startServer(self):
if gevent_present:
web.app.logger.info('Starting Gevent server')
# leave subprocess out to allow forking for fetchers and processors
monkey.patch_all(subprocess=False)
self.start_gevent()
else:
web.app.logger.info('Starting Tornado server')
if web.ub.config.get_config_certfile() and web.ub.config.get_config_keyfile():
ssl={"certfile": web.ub.config.get_config_certfile(),
"keyfile": web.ub.config.get_config_keyfile()}
else:
ssl=None
# Max Buffersize set to 200MB
http_server = HTTPServer(WSGIContainer(web.app),
max_buffer_size = 209700000,
ssl_options=ssl)
http_server.listen(web.ub.config.config_port)
self.wsgiserver=IOLoop.instance()
self.wsgiserver.start() # wait for stop signal
self.wsgiserver.close(True)
if self.restart == True:
web.app.logger.info("Performing restart of Calibre-web")
if os.name == 'nt':
arguments = ["\"" + sys.executable + "\""]
for e in sys.argv:
arguments.append("\"" + e + "\"")
os.execv(sys.executable, arguments)
else:
os.execl(sys.executable, sys.executable, *sys.argv)
else:
web.app.logger.info("Performing shutdown of Calibre-web")
sys.exit(0)
def setRestartTyp(self,starttyp):
self.restart=starttyp
def stopServer(self):
if gevent_present:
self.wsgiserver.close()
else:
self.wsgiserver.add_callback(self.wsgiserver.stop)
def getNameVersion(self):
if gevent_present:
return {'gevent':geventVersion}
else:
return {'tornado':tornadoVersion}
# Start Instance of Server
Server=server()

View File

@ -38,6 +38,18 @@
<th>Python</th> <th>Python</th>
<td>{{versions['PythonVersion']}}</td> <td>{{versions['PythonVersion']}}</td>
</tr> </tr>
{% if 'tornado' in versions %}
<tr>
<th>Tornado web server</th>
<td>v{{versions['tornado']}}</td>
</tr>
{% endif %}
{% if 'gevent' in versions %}
<tr>
<th>Gevent web server</th>
<td>v{{versions['gevent']}}</td>
</tr>
{% endif %}
<tr> <tr>
<th>Kindlegen</th> <th>Kindlegen</th>
<td>{{versions['KindlegenVersion']}}</td> <td>{{versions['KindlegenVersion']}}</td>
@ -70,10 +82,6 @@
<th>Flask Principal</th> <th>Flask Principal</th>
<td>v{{versions['flask_principal']}}</td> <td>v{{versions['flask_principal']}}</td>
</tr> </tr>
<tr>
<th>Tornado web server</th>
<td>v{{versions['tornado']}}</td>
</tr>
<tr> <tr>
<th>ISO639 Languages</th> <th>ISO639 Languages</th>
<td>v{{versions['iso639']}}</td> <td>v{{versions['iso639']}}</td>

View File

@ -71,15 +71,12 @@ import subprocess
import re import re
import db import db
from shutil import move, copyfile from shutil import move, copyfile
from tornado.ioloop import IOLoop
import shutil import shutil
import gdriveutils import gdriveutils
import tempfile import tempfile
import hashlib import hashlib
from redirect import redirect_back, is_safe_url from redirect import redirect_back, is_safe_url
from tornado import version as tornadoVersion
from socket import error as SocketError
try: try:
from urllib.parse import quote from urllib.parse import quote
@ -93,13 +90,13 @@ except ImportError:
from flask_login.__about__ import __version__ as flask_loginVersion from flask_login.__about__ import __version__ as flask_loginVersion
import time import time
import server
current_milli_time = lambda: int(round(time.time() * 1000)) current_milli_time = lambda: int(round(time.time() * 1000))
# Global variables # Global variables
gdrive_watch_callback_token = 'target=calibreweb-watch_files' gdrive_watch_callback_token = 'target=calibreweb-watch_files'
global_task = None
ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'epub', 'mobi', 'azw', 'azw3', 'cbr', 'cbz', 'cbt', 'djvu', 'prc', 'doc', 'docx', 'fb2']) ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'epub', 'mobi', 'azw', 'azw3', 'cbr', 'cbz', 'cbt', 'djvu', 'prc', 'doc', 'docx', 'fb2'])
@ -218,8 +215,6 @@ app = (Flask(__name__))
app.wsgi_app = ReverseProxied(app.wsgi_app) app.wsgi_app = ReverseProxied(app.wsgi_app)
cache_buster.init_cache_busting(app) cache_buster.init_cache_busting(app)
gevent_server = None
formatter = logging.Formatter( formatter = logging.Formatter(
"[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s") "[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s")
file_handler = RotatingFileHandler(config.get_config_logfile(), maxBytes=50000, backupCount=2) file_handler = RotatingFileHandler(config.get_config_logfile(), maxBytes=50000, backupCount=2)
@ -1471,7 +1466,8 @@ def stats():
versions['flask'] = flaskVersion versions['flask'] = flaskVersion
versions['flasklogin'] = flask_loginVersion versions['flasklogin'] = flask_loginVersion
versions['flask_principal'] = flask_principalVersion versions['flask_principal'] = flask_principalVersion
versions['tornado'] = tornadoVersion versions.update(server.Server.getNameVersion())
# versions['tornado'] = tornadoVersion
versions['iso639'] = iso639Version versions['iso639'] = iso639Version
versions['requests'] = requests.__version__ versions['requests'] = requests.__version__
versions['pysqlite'] = db.engine.dialect.dbapi.version versions['pysqlite'] = db.engine.dialect.dbapi.version
@ -1640,9 +1636,7 @@ def on_received_watch_confirmation():
@login_required @login_required
@admin_required @admin_required
def shutdown(): def shutdown():
# global global_task
task = int(request.args.get("parameter").strip()) task = int(request.args.get("parameter").strip())
helper.global_task = task
if task == 1 or task == 0: # valid commandos received if task == 1 or task == 0: # valid commandos received
# close all database connections # close all database connections
db.session.close() db.session.close()
@ -1650,15 +1644,15 @@ def shutdown():
ub.session.close() ub.session.close()
ub.engine.dispose() ub.engine.dispose()
# stop gevent server # stop gevent server
# gevent_server.stop()
# stop tornado server
server = IOLoop.instance()
server.add_callback(server.stop)
showtext = {} showtext = {}
if task == 0: if task == 0:
showtext['text'] = _(u'Server restarted, please reload page') showtext['text'] = _(u'Server restarted, please reload page')
server.Server.setRestartTyp(True)
else: else:
showtext['text'] = _(u'Performing shutdown of server, please close window') showtext['text'] = _(u'Performing shutdown of server, please close window')
server.Server.setRestartTyp(False)
server.Server.stopServer()
return json.dumps(showtext) return json.dumps(showtext)
else: else:
if task == 2: if task == 2:
@ -2498,7 +2492,6 @@ def basic_configuration():
def configuration_helper(origin): def configuration_helper(origin):
# global global_task
reboot_required = False reboot_required = False
gdriveError=None gdriveError=None
db_change = False db_change = False
@ -2705,10 +2698,9 @@ def configuration_helper(origin):
# db.engine.dispose() # ToDo verify correct # db.engine.dispose() # ToDo verify correct
ub.session.close() ub.session.close()
ub.engine.dispose() ub.engine.dispose()
# stop tornado server # stop Server
server = IOLoop.instance() server.Server.setRestartTyp(True)
server.add_callback(server.stop) server.Server.stopServer()
helper.global_task = 0
app.logger.info('Reboot required, restarting') app.logger.info('Reboot required, restarting')
if origin: if origin:
success = True success = True
@ -3386,22 +3378,3 @@ def upload():
else: else:
return redirect(url_for("index")) return redirect(url_for("index"))
def start_gevent():
from gevent.pywsgi import WSGIServer
global gevent_server
try:
ssl_args=dict()
if ub.config.get_config_certfile() and ub.config.get_config_keyfile():
ssl_args = {"certfile": ub.config.get_config_certfile(),
"keyfile": ub.config.get_config_keyfile()}
if os.name == 'nt':
gevent_server = WSGIServer(('0.0.0.0', ub.config.config_port), app, **ssl_args)
else:
gevent_server = WSGIServer(('', ub.config.config_port), app, **ssl_args)
gevent_server.serve_forever()
except SocketError:
app.logger.info('Unable to listen on \'\', trying on IPv4 only...')
gevent_server = WSGIServer(('0.0.0.0', ub.config.config_port), app, **ssl_args)
gevent_server.serve_forever()
except:
pass