Properly handle exceptions in periodic loops

This commit is contained in:
Giuseppe Guerra 2018-08-12 17:18:12 +02:00
parent f11708d463
commit 4e97c717f5
3 changed files with 77 additions and 39 deletions

View File

@ -105,3 +105,6 @@ class invalidUserException(Exception):
class wrongChannelException(Exception): class wrongChannelException(Exception):
pass pass
class periodicLoopException(Exception):
pass

View File

@ -1,6 +1,8 @@
import threading import threading
import time import time
from common.sentry import sentry
from constants.exceptions import periodicLoopException
from objects import match from objects import match
from objects import glob from objects import glob
from constants import serverPackets from constants import serverPackets
@ -67,6 +69,7 @@ class matchList:
del self.matches[matchID] del self.matches[matchID]
log.info("MPROOM{}: Room disposed manually".format(_match.matchID)) log.info("MPROOM{}: Room disposed manually".format(_match.matchID))
@sentry.capture()
def cleanupLoop(self): def cleanupLoop(self):
""" """
Start match cleanup loop. Start match cleanup loop.
@ -76,9 +79,11 @@ class matchList:
This method starts an infinite loop, call it only once! This method starts an infinite loop, call it only once!
:return: :return:
""" """
try:
log.debug("Checking empty matches") log.debug("Checking empty matches")
t = int(time.time()) t = int(time.time())
emptyMatches = [] emptyMatches = []
exceptions = []
# Collect all empty matches # Collect all empty matches
for key, m in self.matches.items(): for key, m in self.matches.items():
@ -90,7 +95,18 @@ class matchList:
# Dispose all empty matches # Dispose all empty matches
for matchID in emptyMatches: for matchID in emptyMatches:
try:
self.disposeMatch(matchID) self.disposeMatch(matchID)
except Exception as e:
exceptions.append(e)
log.error(
"Something wrong happened while disposing a timed out match. Reporting to Sentry when "
"the loop ends."
)
# Re-raise exception if needed
if exceptions:
raise periodicLoopException(exceptions)
finally:
# Schedule a new check (endless loop) # Schedule a new check (endless loop)
threading.Timer(30, self.cleanupLoop).start() threading.Timer(30, self.cleanupLoop).start()

View File

@ -5,11 +5,14 @@ import redis
from common.ripple import userUtils from common.ripple import userUtils
from common.log import logUtils as log from common.log import logUtils as log
from common.sentry import sentry
from constants import serverPackets from constants import serverPackets
from constants.exceptions import periodicLoopException
from events import logoutEvent from events import logoutEvent
from objects import glob from objects import glob
from objects import osuToken from objects import osuToken
class tokenList: class tokenList:
def __init__(self): def __init__(self):
self.tokens = {} self.tokens = {}
@ -171,6 +174,7 @@ class tokenList:
for _, value in self.tokens.items(): for _, value in self.tokens.items():
value.enqueue(packet) value.enqueue(packet)
@sentry.capture()
def usersTimeoutCheckLoop(self): def usersTimeoutCheckLoop(self):
""" """
Start timed out users disconnect loop. Start timed out users disconnect loop.
@ -178,7 +182,9 @@ class tokenList:
CALL THIS FUNCTION ONLY ONCE! CALL THIS FUNCTION ONLY ONCE!
:return: :return:
""" """
try:
log.debug("Checking timed out clients") log.debug("Checking timed out clients")
exceptions = []
timedOutTokens = [] # timed out users timedOutTokens = [] # timed out users
timeoutLimit = int(time.time()) - 100 timeoutLimit = int(time.time()) - 100
for key, value in self.tokens.items(): for key, value in self.tokens.items():
@ -193,12 +199,24 @@ class tokenList:
for i in timedOutTokens: for i in timedOutTokens:
log.debug("{} timed out!!".format(self.tokens[i].username)) log.debug("{} timed out!!".format(self.tokens[i].username))
self.tokens[i].enqueue(serverPackets.notification("Your connection to the server timed out.")) self.tokens[i].enqueue(serverPackets.notification("Your connection to the server timed out."))
try:
logoutEvent.handle(self.tokens[i], None) logoutEvent.handle(self.tokens[i], None)
except Exception as e:
exceptions.append(e)
log.error(
"Something wrong happened while disconnecting a timed out client. Reporting to Sentry "
"when the loop ends."
)
del timedOutTokens del timedOutTokens
# Re-raise exceptions if needed
if exceptions:
raise periodicLoopException(exceptions)
finally:
# Schedule a new check (endless loop) # Schedule a new check (endless loop)
threading.Timer(100, self.usersTimeoutCheckLoop).start() threading.Timer(100, self.usersTimeoutCheckLoop).start()
@sentry.capture()
def spamProtectionResetLoop(self): def spamProtectionResetLoop(self):
""" """
Start spam protection reset loop. Start spam protection reset loop.
@ -207,10 +225,11 @@ class tokenList:
:return: :return:
""" """
try:
# Reset spamRate for every token # Reset spamRate for every token
for _, value in self.tokens.items(): for _, value in self.tokens.items():
value.spamRate = 0 value.spamRate = 0
finally:
# Schedule a new check (endless loop) # Schedule a new check (endless loop)
threading.Timer(10, self.spamProtectionResetLoop).start() threading.Timer(10, self.spamProtectionResetLoop).start()