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:
parent
0866bcc344
commit
74f73bcc34
60
SickBeard.py
60
SickBeard.py
@ -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()
|
@ -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
45
sickbeard/event_queue.py
Normal 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"
|
@ -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)
|
||||||
|
|
||||||
|
@ -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):
|
||||||
"""
|
"""
|
||||||
|
@ -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...")
|
||||||
|
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user