Search code examples
pythonmysqlpythonanywhere

Error 4 when using mysql with pythonanywhere


So I've continued my python game as from my previous question

Socket issue when using threads

and I've come into another issue, this time with MySQL, which is alongside my hosting server on Pythonanywhere.com. The error is as follows:

Traceback (most recent call last):
  File "/usr/local/lib/python3.4/dist-packages/mysql/connector/network.py", line 191, in recv_plain
    chunk = self.sock.recv(1)
InterruptedError: [Errno 4] Interrupted system call

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.4/dist-packages/flask/app.py", line 1817, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/local/lib/python3.4/dist-packages/flask/app.py", line 1477, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/usr/local/lib/python3.4/dist-packages/flask/app.py", line 1381, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/usr/local/lib/python3.4/dist-packages/flask/_compat.py", line 33, in reraise
    raise value
  File "/usr/local/lib/python3.4/dist-packages/flask/app.py", line 1475, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python3.4/dist-packages/flask/app.py", line 1461, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/home/elvishknight1/mysite/flask_app.py", line 81, in intro
    c.execute("SELECT * FROM players WHERE name=%s", (ID,))
  File "/usr/local/lib/python3.4/dist-packages/mysql/connector/cursor.py", line 515, in execute
    self._handle_result(self._connection.cmd_query(stmt))
  File "/usr/local/lib/python3.4/dist-packages/mysql/connector/connection.py", line 684, in cmd_query
    result = self._handle_result(self._send_cmd(ServerCmd.QUERY, query))
  File "/usr/local/lib/python3.4/dist-packages/mysql/connector/connection.py", line 476, in _send_cmd
    return self._socket.recv()
  File "/usr/local/lib/python3.4/dist-packages/mysql/connector/network.py", line 212, in recv_plain
    errno=2055, values=(self.get_address(), _strioerror(err)))
mysql.connector.errors.OperationalError: 2055: Lost connection to MySQL server at 'mysql.server:3306', system error: 4 Interrupted system call
2014-12-18 16:27:13,712 :Exception on /chat/ [GET]
Traceback (most recent call last):
  File "/usr/local/lib/python3.4/dist-packages/mysql/connector/network.py", line 189, in recv_plain
    packet = self.sock.recv(1)
InterruptedError: [Errno 4] Interrupted system call

duplicates of the above cover the error log as more get requests are made by the server

this is the main app code(apologies if it isn't the most pythonic)

from flask import Flask, render_template, request, jsonify
import mysql.connector
from grid import Grid
from game import Game
import random
from monster import Monster
from descriptions import Descriptions
from calculator import Calculator


app = Flask(__name__)
sql = mysql.connector.connect(user="elvishknight1", password="351797asd", host="mysql.server", database="elvishknight1$Overseer", buffered=True)
c = sql.cursor()
game=Game()
grid=Grid()
monsters = []
x=0
y=0
descriptions=Descriptions()
calculator = Calculator()


@app.route('/')
def index():
    return render_template("intro.html",)

@app.route('/mod/351797Aa')
def moderator():
    return render_template("moderate.html",)

@app.route('/mod/')
def worldMaker():
    grid.makeGrid()
    for x in range(4000):
        dice = random.choice(list(descriptions.monsters.keys()))
        mons = descriptions.monsters[dice]
        monsters.append(Monster(dice, mons[0], mons[1], mons[2], mons[3], mons[4],
        mons[5], mons[6], mons[7],mons[8], random.choice(list(range(200))),
        random.choice(list(range(200)))))

    c.execute("UPDATE players SET status='alive'")
    game.gameStatus="started"
    sql.commit()
    return jsonify(result="ok")
@app.route('/player/')
def playerCount():
    return jsonify(result=game.players)

@app.route('/finish/')
def clear():
    game.gameStatus="working on it"
    c.execute("delete from players")
    grid.clearGrid()
    sql.commit()
    return jsonify(result="cleared")

@app.route('/chat/', methods=["GET"])
def chat():
    chatter=[]
    message = request.args.get('value')
    user = request.args.get('user')
    if(message[0:2]=="::"):
        c.execute("INSERT INTO chatPending(user,message) VALUES(%s,%s)",
        (user,message[2:]))
    else:
        del chatter[:]
        c.execute("SELECT * from chatPending")
        row = c.fetchall()
        for r in row:
            if row is not None:
                chatter.append("<p>" + r[0] + ":: " + r[1] + "</p>")
    sql.commit()
    return jsonify(result=chatter)


@app.route('/load/', methods=["GET"])
def intro():
    status=None
    answer = request.args.get('value')
    ID = request.args.get('ID')
    c.execute("SELECT * FROM players WHERE name=%s", (ID,))
    row = c.fetchone()
    if row is not None:
        status = row[3]
    if(game.gameStatus=="started" or game.players>=200):
        status="access denied"
    if(status == None):
        c.execute("INSERT INTO players (name, status) VALUES('" + answer + "', 'entering name')")
        c.execute("SELECT * FROM players WHERE name=%s",(ID,))
        row = c.fetchone()
        if row is not None:
            status = row[3]
    if(status == 'entering name'):
        data = "<p>What is in your past: choose one: <ul> <li> Chosen </li> <li> Magician </li> <li> Poet </li></ul></p>"
        c.execute("UPDATE players SET status='entering past' WHERE name=%s",(ID,))
        c.execute("SELECT * FROM players WHERE name=%s",(ID,))
        row = c.fetchone()
        if row is not None:
            status = row[3]
    elif(status == 'entering past'):
        data = "<p>What is your class. Choose one: <ul> <li> Warrior </li> <li> Mage </li> <li> Rougue </li> <li> Bard </li></ul></p>"
        c.execute("UPDATE players SET status='entering class' WHERE name=%s", (ID,))
        c.execute("UPDATE players SET past=%s WHERE name=%s",(answer.capitalize(), ID))
        c.execute("SELECT * FROM players WHERE name=%s",(ID,))
        row = c.fetchone()
        if row is not None:
            status = row[3]
    elif(status == 'entering class'):
        data = "<p>What is your secret code?</p>"
        c.execute("UPDATE players SET status='entering code' WHERE name=%s", (ID,))
        c.execute("UPDATE players SET class=%s WHERE name=%s",(answer.capitalize(), ID))
        c.execute("SELECT * FROM players WHERE name=%s",(ID,))
        row = c.fetchone()
        if row is not None:
            status = row[3]
    elif(status == 'entering code'):
        data = "<p>OK all set. Waiting on the moderator!</p>"
        c.execute("UPDATE players SET status='waiting' WHERE name=%s", (ID,))
        c.execute("UPDATE players SET code=%s WHERE name=%s",(answer.capitalize(), ID))
        c.execute("SELECT * FROM players WHERE name=%s",(ID,))
        game.players+=1
        row = c.fetchone()
        if row is not None:
            status = row[3]
            past = row[1]
            Class = row[2]
        stats = calculator.calculateStats(past)
        attacks = []
        attackString=""
        equipmentString=""
        equipment = descriptions.classes[Class.capitalize()]
        for a in list(equipment["lHand"][1]["moves"].keys()):
            attacks.append(a)
        for b in list(equipment["rHand"][1]["moves"].keys()):
            attacks.append(b)
        for att in attacks:
            attackString=attackString + att + ","
        for d in equipment:
                equipmentString = equipmentString + d[0] + ","

        c.execute("UPDATE players SET hp=%s,attack=%s,defense=%s,speed=%s, attacks=%s,"
        + "level=1, experience=0, nextLevel=50, energy=%s,inventory=%s, lHand=%s,rHand=%s,head=%s,hands=%s,chest=%s,legs=%s where name=%s",(stats[0],
        stats[1],stats[2],stats[3],attackString,stats[4],equipmentString,
        equipment["lHand"][0],equipment["rHand"][0],equipment["Head"][0],
        equipment["Hands"][0],equipment["Chest"][0],equipment["Legs"][0],ID))

    elif(status == 'waiting'):
        data = "<p>Still waiting, please be patient.</p>"
    elif(status=="access denied"):
        data = "<p>Sorry. The player queue is full.</p>"
    else:
        data="error"
    sql.commit()
    return jsonify(result=data)

@app.route('/check/')
def checker():
    status=None
    ID = request.args.get('user')
    c.execute("SELECT * FROM players WHERE name=%s", (ID,))
    row = c.fetchone()
    if row is not None:
        status = row[3]
    if(status=="alive"):
        data="<p>Ready! Press >> to begin.</p>"
        head="ok"
    else:
        data=""
        head="not"
    return jsonify(result=data, header=head)

@app.route('/move/')
def move():
    y=0
    x=0
    data=""
    answer = request.args.get('value')
    ID = request.args.get('ID')
    c.execute("SELECT * FROM players WHERE name=%s", (ID,))
    row = c.fetchone()
    if row is not None:
        status = row[3]
        x = row[5]
        y = row[6]
        HP = row[7]
        attack = row[8]
        defense = row[9]
        speed = row[10]
        level = row[13]
        energy = row[17]
        Class = row[2]
        past = row[1]
        attacks = row[11]
        exp = row[14]
        nextLevel = row[15]
    if(answer=="start"):
        c.execute("UPDATE players SET X=%s, y=%s WHERE name=%s",(random.choice(list(range(200))),random.choice(list(range(200))), ID))
        data = "You are on a {} tile <br> {} <br>".format(grid.getLandType(x,y), grid.getDesc(x,y))
    if(status!="dead"):
        if(answer=='profile'):
            data = "You're name is {} <br> You are a {} <br> {} <br> your class is: {} <br> your stats are: <br> Level:{} HP:{} <br> Attack:{} <br> Defense:{} <br> Speed:{} <br> Energy:{}".format(ID,past,descriptions.player_backstory[past.lower()],Class,level,HP,attack,defense,speed,energy)
        elif(answer=="North" or answer=="N" and status!="fighting"):
            if(y>0):
                c.execute("UPDATE players SET y=%s WHERE name=%s", (y-1,ID))
            data = "You are on a {} tile <br> {} <br>".format(grid.getLandType(x,y), grid.getDesc(x,y))
        elif(answer=="East" or answer=="E" and status!="fighting"):
            if(x<199):
                c.execute("UPDATE players SET X=%s WHERE name=%s", (x+1,ID))
                c.execute("SELECT * FROM players WHERE name=%s", (ID,))
                row = c.fetchone()
                if row is not None:
                    x = row[5]
            data = "You are on a {} tile <br> {} <br>".format(grid.getLandType(x,y), grid.getDesc(x,y))
        elif(answer=="South" or answer=="S" and status!="fighting"):
            if(y<199):
                c.execute("UPDATE players SET y=%s WHERE name=%s", (y+1,ID))
                c.execute("SELECT * FROM players WHERE name=%s", (ID,))
                row = c.fetchone()
                if row is not None:
                    y = row[6]
            data = "You are on a {} tile <br> {} <br>".format(grid.getLandType(x,y), grid.getDesc(x,y))
        elif(answer=="West" or answer=="W" and status!="fighting"):
            if(x>0):
                c.execute("UPDATE players SET X=%s WHERE name=%s", (x-1,ID))
                c.execute("SELECT * FROM players WHERE name=%s", (ID,))
                row = c.fetchone()
                if row is not None:
                    x = row[5]
            data = "You are on a {} tile <br> {} <br>".format(grid.getLandType(x,y), grid.getDesc(x,y))
        elif(answer=="Attack"):
            for monster in monsters:
                if(x==monster.X and y==monster.Y):
                    data = data + "The {} wakes up, the battle begins".format(monster.name)
                    c.execute("UPDATE players SET status='fighting' WHERE name=%s",(ID,))
                    monsterImFighting = monster
        elif(answer == "Moves" and status=="fighting"):
            c.execute("SELECT * FROM players WHERE name=%s", (ID,))
            row = c.fetchone()
            if row is not None:
                attacks=row[11]
            listOfAttacks=attacks.split(",")
            for y in listOfAttacks:
                data = data + y.capitalize() + "<br>"
        elif(status=="fighting"):
            for m in monsterImFighting.attacks.keys():
                monsterName = m
                for a in attacks.split(","):
                    if(a == answer):
                        damage = calculator.calculateDamage(attack,monsterImFighting.defense,
                        descriptions.classes[Class.capitalize()][1]["moves"][answer],
                        "normal","thunder")
                        data = data + "you deal {} damage to {}".format(damage,m)
                        monsterImFighting.hitpoints-=damage
                        if(monsterImFighting.hitpoints <=0):
                            data = data + "<br> You killed the {}. You gain {} exp.".format(monsterName,monsterImFighting.drops[0])
                            c.execute("UPDATE players SET experience=%s WHERE name=%s",(exp + monsterImFighting.drops[0],ID))
                            c.excecute("SELECT * FROM players WHERE name=%s",(ID,))
                            row = c.fetchone()
                            if row is not None:
                                exp = row[14]
                                c.excecute("UPDATE players SET status='alive' WHERE name=%s",(ID,))
                            if(exp >= nextLevel):
                                data = data + "You've leveled up!!"
                                c.execute("UPDATE players SET level=%s, attack=%s, defense=%s, speed=%s hp=%s WHERE name=%s",(level + 1,
                                attack + random.choice(list(range(3))),defense + random.choice(list(range(3))),
                                speed + random.choice(list(range(3))), HP +random.choice(list(range(20))),ID))

                        else:
                            shuf = random.choice(list(monsterImFighting.attacks.keys()))
                            damageReturn = calculator.calculateReturnDamage(monsterImFighting.attack, defense, monsterImFighting.attacks[shuf])
                            c.execute("UPDATE players SET hp=%s WHERE name=%s",(HP - damageReturn,ID))
                            data=data + "{} deals {} damage to you".format(monsterName,damageReturn)
                            if(HP<=0):
                                data= data + "You have perished at the hands of a {}".format(monsterName)
                                c.execute("UPDATE players SET status='dead' WHERE name=%s",(HP - damageReturn,ID))

        else:
             data = "You are on a {} tile <br> {} <br>".format(grid.getLandType(x,y), grid.getDesc(x,y))
    else:
        data = "Sorry, but you are dead. Dead people don't move"
    sql.commit()
    return jsonify(result=data, header=status)


@app.route('/event/')
def eventManager():
    data = ""

    ID=request.args.get("ID")
    c.execute("SELECT * FROM players WHERE name=%s", (ID,))
    row = c.fetchone()
    if row is not None:
        x = row[5]
    c.execute("SELECT * FROM players WHERE name=%s", (ID,))
    row = c.fetchone()
    if row is not None:
        y = row[6]
    for monster in monsters:
        if(monster.X == x and monster.Y == y):
            data = "A {} is sleeping nearby!".format(monster.name)
    return jsonify(result=data, header=len(monsters))

I've looked on the web for solutions, and they all mention it has something to do with how many connections you are making to the server at once(at least that's what I'm getting from it) but the solutions seem...inconclusive, particularly on how to deal with this when hosting your app on pythonanywhere.

Any help would be much appreciated!


Solution

  • PythonAnywhere dev here. I really recommend you use MySQL via SQLalchemy rather than directly -- it's a library that sits between your code and the mysql.connector stuff, and it should insulate you from all of the connection management stuff. That applies on PythonAnywhere or any other hosting platform.

    The Flask tutorial has some good hints on using SQLAlchemy.