mein Browsergame liefert mir derzeit immer wieder gerne einen `OperationalError`:
Offenbar schließt er die Transaktion nicht richtig ab und das Feld bleibt gelockt.OperationalError: (OperationalError) (1205, 'Lock wait timeout exceeded; try restarting transaction') 'UPDATE `Character` SET weapon_id=%s WHERE `Character`.id = %s' (10L, 1L)
Hintergrund: Mit der use-Methode der Character-Instanz wird self.weapon = item ausgeführt:
Code: Alles auswählen
if isinstance(item, Weapon):
if item.twohanded:
# reset offhand
self.offhand = None
self.weapon = item
# other stuff via elif
Verwende ich use um z.B. self.armor (Armor(Item)) zu setzen, habe ich den Fehler nicht. Der einzige Unterschied im Code ist dort, dass kein self.offhand oder ähnliches überprüft werden muss (bei der Waffe brauche ich es um zu verhindern, dass man Zweihandwaffe und Schild trägt).
Wenn ich dann versuche eine weitere Datenbankabfrage zu erzeugen (z.B. ein Select) erhalte ich:
Spätestens an der Stelle wird es unangenehm -.-' Kille ich den Server, ist das Problem weg. Allerdings lässt es sich nach wenigen Sekunden reproduzieren. Wenn ich ein Seitenladen abbreche, meldet bottle mir in der Konsole eine abgefangene Broken pipe (soweit klar). Offensichtlich wird dabei der Thread (der für die Anfrage zuständig ist) gekillt. Allerdings bleibt die Datenbankaktion (z.B. mitten im gelockten Update) stehen und lässt das Feld gelockt. Was kann ich dagegen tun?This Session's transaction has been rolled back due to a previous exception during flush. To begin a new transaction with this Session, first issue Session.rollback(). Original exception was: (OperationalError) (1205, 'Lock wait timeout exceeded; try restarting transaction') 'UPDATE Character SET weapon_id=%s WHERE Character.id = %s' (10L, 1L)

Führe ich die gleichen Aktionen in der Python-Konsole aus, läuft alles fehlerfrei: keine Transaktionen blockieren oder sonstwas.
Um inhaltliche Denkfehler zu vermeiden, hier mein das Grobkonzept für das Zusammenspiel von bottle-Routen und DB-Transaktionen. Die bottle-Routen laufen inhaltlich so ab:
- versuche Authentifizierung anhand Session-ID (account.sid von Account(Entity)), sonst Umleitung auf Fehlerseite
- führe die entsprechenden Dinge mit der Character-Instanz der eigenen Account-Instanz durch (account.character dient als Referenz) z.B. die ItemID aus dem Post lesen, das entsprechende Item dazu durch ein Query finden, prüfen ob item in character.inventory und dann character.use(item).
- wenn alles erfolgreich, dann session.commit() und das entsprechende Template zurückgeben (gefüllt mit den Daten)
- wenn was schiefgeht: session.rollback() und den Fehler-Traceback in ne Log-File schreiben.
Code: Alles auswählen
@post(u'/game/inventory/:sid/use/')
def game_inventory_use(sid):
try:
player = Player.AuthPost(sid)
item_id = int(request.POST[u'item_id'])
# try use item
item = Item.query.filter_by(id=item_id).first()
if item is None or item not in player.character.inventory:
return u'Ungültiges Item'
try:
player.character.use(item)
return 'Nichts geschieht.'
except Report as e:
session.commit()
return unicode(e) # event
except Exception as e:
if isinstance(e, HTTPResponse): raise
session.rollback()
syslog.log(e)
redirect(u'/internal_error/')
- AuthPost führt die Authentifizierung durch (Umleitung erfolgt innerhalb der Methode)
- das Try-Except-Block hat den Hintergrund, dass ich "Spielereignisse" (wie "Christian verwendet Kurzschwert.") von einer Funktion (mit einem zufälligen der gegebenen Texte) aus Report(Exception) erzeugen lassen (auch um aus der Funktion "schneller"). Ich habe mich gegen return entschieden, da ich return für "Nicht-Spielereignisse" verwende (sry wenn's unverständlich ist wegen der Exception
). Auf jeden Fall führt es (wenn ich einen string returne) zum gleichen Problem; scheint also nicht daran zu liegen
- das Abfangen aller weiteren Exceptions dient dem Loggen von Fehlern. Dazu hab ich ne Logger-Klasse die thread-safe in eine Datei schreibt. (das mit dem isinstance(e, HTTPResponse) brauche ich um bottle's redirects nicht fälschlicher Weise abzufangen, die sind offensichtlich auch von Exception abgeleitet)