Properly handle exceptions in periodic loops
This commit is contained in:
parent
f11708d463
commit
4e97c717f5
|
@ -104,4 +104,7 @@ class invalidUserException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class wrongChannelException(Exception):
|
class wrongChannelException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class periodicLoopException(Exception):
|
||||||
pass
|
pass
|
|
@ -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,21 +79,34 @@ class matchList:
|
||||||
This method starts an infinite loop, call it only once!
|
This method starts an infinite loop, call it only once!
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
log.debug("Checking empty matches")
|
try:
|
||||||
t = int(time.time())
|
log.debug("Checking empty matches")
|
||||||
emptyMatches = []
|
t = int(time.time())
|
||||||
|
emptyMatches = []
|
||||||
|
exceptions = []
|
||||||
|
|
||||||
# Collect all empty matches
|
# Collect all empty matches
|
||||||
for key, m in self.matches.items():
|
for key, m in self.matches.items():
|
||||||
if [x for x in m.slots if x.user is not None]:
|
if [x for x in m.slots if x.user is not None]:
|
||||||
continue
|
continue
|
||||||
if t - m.createTime >= 120:
|
if t - m.createTime >= 120:
|
||||||
log.debug("Match #{} marked for cleanup".format(m.matchID))
|
log.debug("Match #{} marked for cleanup".format(m.matchID))
|
||||||
emptyMatches.append(m.matchID)
|
emptyMatches.append(m.matchID)
|
||||||
|
|
||||||
# Dispose all empty matches
|
# Dispose all empty matches
|
||||||
for matchID in emptyMatches:
|
for matchID in emptyMatches:
|
||||||
self.disposeMatch(matchID)
|
try:
|
||||||
|
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."
|
||||||
|
)
|
||||||
|
|
||||||
# Schedule a new check (endless loop)
|
# Re-raise exception if needed
|
||||||
threading.Timer(30, self.cleanupLoop).start()
|
if exceptions:
|
||||||
|
raise periodicLoopException(exceptions)
|
||||||
|
finally:
|
||||||
|
# Schedule a new check (endless loop)
|
||||||
|
threading.Timer(30, self.cleanupLoop).start()
|
||||||
|
|
|
@ -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,27 +182,41 @@ class tokenList:
|
||||||
CALL THIS FUNCTION ONLY ONCE!
|
CALL THIS FUNCTION ONLY ONCE!
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
log.debug("Checking timed out clients")
|
try:
|
||||||
timedOutTokens = [] # timed out users
|
log.debug("Checking timed out clients")
|
||||||
timeoutLimit = int(time.time()) - 100
|
exceptions = []
|
||||||
for key, value in self.tokens.items():
|
timedOutTokens = [] # timed out users
|
||||||
# Check timeout (fokabot is ignored)
|
timeoutLimit = int(time.time()) - 100
|
||||||
if value.pingTime < timeoutLimit and value.userID != 999 and not value.irc and not value.tournament:
|
for key, value in self.tokens.items():
|
||||||
# That user has timed out, add to disconnected tokens
|
# Check timeout (fokabot is ignored)
|
||||||
# We can't delete it while iterating or items() throws an error
|
if value.pingTime < timeoutLimit and value.userID != 999 and not value.irc and not value.tournament:
|
||||||
timedOutTokens.append(key)
|
# That user has timed out, add to disconnected tokens
|
||||||
|
# We can't delete it while iterating or items() throws an error
|
||||||
|
timedOutTokens.append(key)
|
||||||
|
|
||||||
# Delete timed out users from self.tokens
|
# Delete timed out users from self.tokens
|
||||||
# i is token string (dictionary key)
|
# i is token string (dictionary key)
|
||||||
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."))
|
||||||
logoutEvent.handle(self.tokens[i], None)
|
try:
|
||||||
del timedOutTokens
|
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
|
||||||
|
|
||||||
# Schedule a new check (endless loop)
|
# Re-raise exceptions if needed
|
||||||
threading.Timer(100, self.usersTimeoutCheckLoop).start()
|
if exceptions:
|
||||||
|
raise periodicLoopException(exceptions)
|
||||||
|
finally:
|
||||||
|
# Schedule a new check (endless loop)
|
||||||
|
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,12 +225,13 @@ class tokenList:
|
||||||
|
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
# Reset spamRate for every token
|
try:
|
||||||
for _, value in self.tokens.items():
|
# Reset spamRate for every token
|
||||||
value.spamRate = 0
|
for _, value in self.tokens.items():
|
||||||
|
value.spamRate = 0
|
||||||
# Schedule a new check (endless loop)
|
finally:
|
||||||
threading.Timer(10, self.spamProtectionResetLoop).start()
|
# Schedule a new check (endless loop)
|
||||||
|
threading.Timer(10, self.spamProtectionResetLoop).start()
|
||||||
|
|
||||||
def deleteBanchoSessions(self):
|
def deleteBanchoSessions(self):
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in New Issue
Block a user