1
0
mirror of https://github.com/moparisthebest/SickRage synced 2024-12-13 19:42:20 -05:00

New event queue system in place, currently handles shutdown and restart calls.

Fixed ctrl-c issues with new event queue system.
Added a sleep timer to the NameParser class to help lower cpu usage spikes.
This commit is contained in:
echel0n 2014-07-08 15:17:34 -07:00
parent 0866bcc344
commit 74f73bcc34
8 changed files with 123 additions and 98 deletions

View File

@ -21,6 +21,7 @@
from __future__ import with_statement from __future__ import with_statement
import time import time
import signal
import sys import sys
import shutil import shutil
import subprocess import subprocess
@ -52,12 +53,12 @@ if sys.hexversion >= 0x020600F0:
import locale import locale
import datetime import datetime
import threading import threading
import signal
import traceback import traceback
import getopt import getopt
import sickbeard import sickbeard
from sickbeard.event_queue import Events
from sickbeard import db from sickbeard import db
from sickbeard.tv import TVShow from sickbeard.tv import TVShow
from sickbeard import logger, network_timezones, failed_history, name_cache from sickbeard import logger, network_timezones, failed_history, name_cache
@ -68,14 +69,16 @@ from sickbeard.databases.mainDB import MAX_DB_VERSION
from lib.configobj import ConfigObj from lib.configobj import ConfigObj
throwaway = datetime.datetime.strptime('20110101', '%Y%m%d')
signal.signal(signal.SIGINT, sickbeard.sig_handler) signal.signal(signal.SIGINT, sickbeard.sig_handler)
signal.signal(signal.SIGTERM, sickbeard.sig_handler) signal.signal(signal.SIGTERM, sickbeard.sig_handler)
throwaway = datetime.datetime.strptime('20110101', '%Y%m%d')
class SickRage(object): class SickRage(object):
def __init__(self): def __init__(self):
sickbeard.events = Events(self.shutdown)
self.webserver = None self.webserver = None
self.runAsDaemon = False self.runAsDaemon = False
self.CREATEPID = False self.CREATEPID = False
@ -330,7 +333,8 @@ class SickRage(object):
if sickbeard.LAUNCH_BROWSER and not (self.noLaunch or self.runAsDaemon): if sickbeard.LAUNCH_BROWSER and not (self.noLaunch or self.runAsDaemon):
sickbeard.launchBrowser(self.startPort) sickbeard.launchBrowser(self.startPort)
while(sickbeard.started): # main loop
while(True):
time.sleep(1) time.sleep(1)
def daemonize(self): def daemonize(self):
@ -431,28 +435,24 @@ class SickRage(object):
except: except:
return False return False
if __name__ == "__main__": def shutdown(self, type):
if sys.hexversion >= 0x020600F0: if sickbeard.started:
freeze_support() # stop all tasks
sickbeard.halt()
sr = None
try:
# init sickrage
sr = SickRage()
# start sickrage
sr.start()
# shutdown web server # shutdown web server
sr.webserver.shutDown() if self.webserver:
sr.webserver.join() self.webserver.shutDown()
sr.webserver = None self.webserver = None
# save all shows to DB
sickbeard.saveAll()
# if run as daemon delete the pidfile # if run as daemon delete the pidfile
if sr.runAsDaemon and sr.CREATEPID: if self.runAsDaemon and self.CREATEPID:
sr.remove_pid_file(sr.PIDFILE) self.remove_pid_file(self.PIDFILE)
if not sickbeard.shutdown: if type == sickbeard.events.SystemEvent.RESTART:
install_type = sickbeard.versionCheckScheduler.action.install_type install_type = sickbeard.versionCheckScheduler.action.install_type
popen_list = [] popen_list = []
@ -465,7 +465,8 @@ if __name__ == "__main__":
popen_list = [os.path.join(sickbeard.PROG_DIR, 'updater.exe'), str(sickbeard.PID), sys.executable] popen_list = [os.path.join(sickbeard.PROG_DIR, 'updater.exe'), str(sickbeard.PID), sys.executable]
else: else:
logger.log(u"Unknown SB launch method, please file a bug report about this", logger.ERROR) logger.log(u"Unknown SB launch method, please file a bug report about this", logger.ERROR)
popen_list = [sys.executable, os.path.join(sickbeard.PROG_DIR, 'updater.py'), str(sickbeard.PID), sys.executable, popen_list = [sys.executable, os.path.join(sickbeard.PROG_DIR, 'updater.py'), str(sickbeard.PID),
sys.executable,
sickbeard.MY_FULLNAME] sickbeard.MY_FULLNAME]
if popen_list: if popen_list:
@ -476,11 +477,12 @@ if __name__ == "__main__":
logger.close() logger.close()
subprocess.Popen(popen_list, cwd=os.getcwd()) subprocess.Popen(popen_list, cwd=os.getcwd())
# exit process # system exit
os._exit(0) os._exit(0)
except:
if sr: if __name__ == "__main__":
logger.log(traceback.format_exc(), logger.ERROR) if sys.hexversion >= 0x020600F0:
else: freeze_support()
print(traceback.format_exc())
sys.exit(1) # start sickrage
SickRage().start()

View File

@ -49,7 +49,6 @@ from sickbeard.common import SD, SKIPPED, NAMING_REPEAT
from sickbeard.databases import mainDB, cache_db, failed_db from sickbeard.databases import mainDB, cache_db, failed_db
from lib.configobj import ConfigObj from lib.configobj import ConfigObj
from tornado.ioloop import IOLoop
import xml.etree.ElementTree as ElementTree import xml.etree.ElementTree as ElementTree
PID = None PID = None
@ -75,6 +74,9 @@ PIDFILE = ''
DAEMON = None DAEMON = None
NO_RESIZE = False NO_RESIZE = False
# system events
events = None
dailySearchScheduler = None dailySearchScheduler = None
backlogSearchScheduler = None backlogSearchScheduler = None
showUpdateScheduler = None showUpdateScheduler = None
@ -103,7 +105,6 @@ CUR_COMMIT_HASH = None
INIT_LOCK = Lock() INIT_LOCK = Lock()
started = False started = False
shutdown = False
ACTUAL_LOG_DIR = None ACTUAL_LOG_DIR = None
LOG_DIR = None LOG_DIR = None
@ -1166,7 +1167,7 @@ def halt():
showUpdateScheduler, versionCheckScheduler, showQueueScheduler, \ showUpdateScheduler, versionCheckScheduler, showQueueScheduler, \
properFinderScheduler, autoPostProcesserScheduler, searchQueueScheduler, \ properFinderScheduler, autoPostProcesserScheduler, searchQueueScheduler, \
subtitlesFinderScheduler, traktCheckerScheduler, \ subtitlesFinderScheduler, traktCheckerScheduler, \
dailySearchScheduler, started dailySearchScheduler, events, started
with INIT_LOCK: with INIT_LOCK:
@ -1174,7 +1175,12 @@ def halt():
logger.log(u"Aborting all threads") logger.log(u"Aborting all threads")
# abort all the threads events.alive = False
logger.log(u"Waiting for the EVENTS thread to exit")
try:
events.join(10)
except:
pass
dailySearchScheduler.abort = True dailySearchScheduler.abort = True
logger.log(u"Waiting for the DAILYSEARCH thread to exit") logger.log(u"Waiting for the DAILYSEARCH thread to exit")
@ -1261,7 +1267,7 @@ def halt():
def sig_handler(signum=None, frame=None): def sig_handler(signum=None, frame=None):
if type(signum) != type(None): if type(signum) != type(None):
logger.log(u"Signal %i caught, saving and exiting..." % int(signum)) logger.log(u"Signal %i caught, saving and exiting..." % int(signum))
saveAndShutdown() events.put(events.SystemEvent.SHUTDOWN)
def saveAll(): def saveAll():
global showList global showList
@ -1275,32 +1281,6 @@ def saveAll():
logger.log(u"Saving config file to disk") logger.log(u"Saving config file to disk")
save_config() save_config()
def saveAndShutdown(restart=False):
global shutdown, started
# flag restart/shutdown
if not restart:
shutdown = True
# proceed with shutdown
started = False
def invoke_command(to_call, *args, **kwargs):
def delegate():
to_call(*args, **kwargs)
logger.log(u"Placed invoked command: " + repr(delegate) + " for " + repr(to_call) + " with " + repr(
args) + " and " + repr(kwargs), logger.DEBUG)
IOLoop.current().add_callback(delegate)
def invoke_restart(soft=True):
invoke_command(restart, soft=soft)
def invoke_shutdown():
invoke_command(saveAndShutdown, False)
def restart(soft=True): def restart(soft=True):
if soft: if soft:
halt() halt()
@ -1308,7 +1288,7 @@ def restart(soft=True):
logger.log(u"Re-initializing all data") logger.log(u"Re-initializing all data")
initialize() initialize()
else: else:
saveAndShutdown(True) events.put(events.SystemEvent.RESTART)
def save_config(): def save_config():

45
sickbeard/event_queue.py Normal file
View File

@ -0,0 +1,45 @@
from threading import Thread
from Queue import Queue, Empty
from tornado.ioloop import IOLoop
class Event:
def __init__(self, type):
self._type = type
@property
def type(self):
return self._type
class Events(Thread):
def __init__(self, callback):
super(Events, self).__init__()
self.queue = Queue()
self.daemon = True
self.alive = True
self.callback = callback
self.name = "EVENT-QUEUE"
# auto-start
self.start()
def put(self, type):
self.queue.put_nowait(type)
def run(self):
while(self.alive):
try:
# get event type
type = self.queue.get(True, 1)
# perform callback if we got a event type
self.callback(type)
# event completed
self.queue.task_done()
except Empty:
type = None
# System Events
class SystemEvent(Event):
RESTART = "RESTART"
SHUTDOWN = "SHUTDOWN"

View File

@ -16,6 +16,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with SickRage. If not, see <http://www.gnu.org/licenses/>. # along with SickRage. If not, see <http://www.gnu.org/licenses/>.
import time
import re import re
import datetime import datetime
import os.path import os.path
@ -133,6 +134,8 @@ class NameParser(object):
if self.showObj: if self.showObj:
break break
else: else:
time.sleep(0.05)
raise InvalidShowException( raise InvalidShowException(
"Unable to parse " + name.encode(sickbeard.SYS_ENCODING, 'xmlcharrefreplace')) "Unable to parse " + name.encode(sickbeard.SYS_ENCODING, 'xmlcharrefreplace'))
@ -251,6 +254,8 @@ class NameParser(object):
result.score += 1 result.score += 1
matches.append(result) matches.append(result)
time.sleep(0.05)
if len(matches): if len(matches):
result = max(sorted(matches, reverse=True, key=lambda x: x.which_regex), key=lambda x: x.score) result = max(sorted(matches, reverse=True, key=lambda x: x.which_regex), key=lambda x: x.score)

View File

@ -64,7 +64,7 @@ class CheckVersion():
if sickbeard.versionCheckScheduler.action.update(): if sickbeard.versionCheckScheduler.action.update():
logger.log(u"Update was successful!") logger.log(u"Update was successful!")
ui.notifications.message('Update was successful') ui.notifications.message('Update was successful')
threading.Timer(2, sickbeard.invoke_restart, [False]).start() sickbeard.events.put(sickbeard.events.SystemEvent.RESTART)
def find_install_type(self): def find_install_type(self):
""" """

View File

@ -1524,7 +1524,7 @@ class CMD_SickBeardRestart(ApiCall):
def run(self): def run(self):
""" restart sickbeard """ """ restart sickbeard """
threading.Timer(2, sickbeard.invoke_restart, [False]).start() sickbeard.events.put(sickbeard.events.SystemEvent.RESTART)
return _responds(RESULT_SUCCESS, msg="SickRage is restarting...") return _responds(RESULT_SUCCESS, msg="SickRage is restarting...")
@ -1701,7 +1701,7 @@ class CMD_SickBeardShutdown(ApiCall):
def run(self): def run(self):
""" shutdown sickbeard """ """ shutdown sickbeard """
threading.Timer(2, sickbeard.invoke_shutdown).start() sickbeard.events.put(sickbeard.events.SystemEvent.SHUTDOWN)
return _responds(RESULT_SUCCESS, msg="SickRage is shutting down...") return _responds(RESULT_SUCCESS, msg="SickRage is shutting down...")

View File

@ -3434,7 +3434,7 @@ class Home(MainHandler):
if str(pid) != str(sickbeard.PID): if str(pid) != str(sickbeard.PID):
redirect("/home/") redirect("/home/")
threading.Timer(2, sickbeard.invoke_shutdown).start() sickbeard.events.put(sickbeard.events.SystemEvent.SHUTDOWN)
title = "Shutting down" title = "Shutting down"
message = "SickRage is shutting down..." message = "SickRage is shutting down..."
@ -3450,7 +3450,7 @@ class Home(MainHandler):
t.submenu = HomeMenu() t.submenu = HomeMenu()
# restart # restart
threading.Timer(5, sickbeard.invoke_restart, [False]).start() sickbeard.events.put(sickbeard.events.SystemEvent.RESTART)
return _munge(t) return _munge(t)
@ -3462,7 +3462,7 @@ class Home(MainHandler):
updated = sickbeard.versionCheckScheduler.action.update() # @UndefinedVariable updated = sickbeard.versionCheckScheduler.action.update() # @UndefinedVariable
if updated: if updated:
# do a hard restart # do a hard restart
threading.Timer(2, sickbeard.invoke_restart, [False]).start() sickbeard.events.put(sickbeard.events.SystemEvent.RESTART)
t = PageTemplate(headers=self.request.headers, file="restart_bare.tmpl") t = PageTemplate(headers=self.request.headers, file="restart_bare.tmpl")
return _munge(t) return _munge(t)

View File

@ -122,13 +122,6 @@ class SRWebServer(threading.Thread):
try: try:
self.io_loop.start() self.io_loop.start()
self.io_loop.close(True) self.io_loop.close(True)
# stop all tasks
sickbeard.halt()
# save all shows to DB
sickbeard.saveAll()
except ValueError: except ValueError:
# Ignore errors like "ValueError: I/O operation on closed kqueue fd". These might be thrown during a reload. # Ignore errors like "ValueError: I/O operation on closed kqueue fd". These might be thrown during a reload.
pass pass