2016-11-10 21 views
0

我建立了一个微型网站服务,但是我发现它挂了很多。通过挂起我的意思是所有的请求将会超时,当它挂起时,我可以看到该过程在服务器上运行良好,像往常一样使用大约15MB的内存。我认为这是一个非常有趣的问题,代码非常简单,请告诉我我做错了什么。蟒蛇微型网站服务总是挂起

app = Bottle() 
# static routing 
@app.route('/') 
def server_static_home(): 
    return static_file('index.html', root='client/') 

@app.route('/<filename>') 
def server_static(filename): 
    return static_file(filename, root='client/') 

@app.get('/api/data') 
def getData(): 
    data = {} 
    arrayToReturn = [] 
    with open("data.txt", "r") as dataFile: 
     entryArray = json.load(dataFile) 
     for entry in entryArray: 
      if not entry['deleted']: 
       arrayToReturn.append(entry) 
     data["array"] = arrayToReturn 

    return data 

@app.put('/api/data') 
def changeEntry(): 

    jsonObj = request.json 
    with open("data.txt", "r+") as dataFile: 
     entryArray = json.load(dataFile) 
     for entry in entryArray: 
      if entry['id'] == jsonObj['id']: 
       entry['val'] = jsonObj['val'] 
     dataFile.seek(0) 
     json.dump(entryArray, dataFile, indent=4) 
     dataFile.truncate() 

    return {"success":True} 

run_simple('0.0.0.0', 80, app, use_reloader=True) 

基本上mydomain.com是我index.html并加载必要的JS,CSS文件,这就是静态路由部分是做路线。一旦页面被加载,一个ajax GET请求被激发到/api/data来加载数据,当我修改数据时,它会触发另一个请求到/api/data修改数据的ajax Put请求。

如何重现

这很容易复制的窍门,我只需要访问mydomain.com并刷新页面10-30倍迅速,那么它会停止响应。但是我永远无法在本地重现这一点,我的刷新速度如此之快,data.txt在我的本地机器上也是如此。

更新

原来它不是具有读/写文件,但与试图写管道破裂问题的问题。发送请求的客户端在收到所有数据之前关闭连接。我正在寻找解决方案...

+0

如果您在使用附带瓶框架开发服务器的东西,我注意到,水管坏的错误实际上是不可避免的,给予足够的运行时间(它毕竟是一个开发服务器)。如果这适用于您,我建议切换到在更多生产就绪服务器上运行Bottle应用程序。使用Bottle与cherrypy亲自取得了非常好的效果。 – user3351605

回答

3

它看起来像你试图打开和读取每个PUT请求相同的data.txt文件。最终,您将遇到这种体系结构的并发问题,因为您将尝试打开并写入同一文件的多个请求。

最好的解决方案是将数据保存到数据库(如MySQL,Postgres,Mongodb),而不是写入磁盘上的平面文件。

但是,如果您必须写入一个平面文件,那么您应该为每个请求写入不同的文件,其中文件的名称可以是jsonObj['id'],这样可以避免多个请求尝试读取/写入的问题到同一个文件在同一时间。

+0

由于服务非常简单,我不想为它使用任何数据库。我正在阅读和修改json格式文本文件中的条目,所以我不认为我可以写入单独的文件,然后读取数据将非常复杂。 – Arch1tect

+0

此外,我认为问题是'GET'请求不是'PUT',因为我不需要修改数据来重现问题,刷新只会触发读取数据的GET请求。 – Arch1tect

1

读取和写入您的data.txt文件将成为Calvin提及的竞争条件受害者。数据库在python中非常容易,特别是像SqlAlchemy这样的库。但是,如果你坚持,你也可以使用全局字典和锁,假设你的web服务器不是作为多个进程运行。像

entryArray = {} 
mylock = threading.Lock() 
@app.put('/api/data') 
def changeEntry(): 

    jsonObj = request.json 
    with mylock.lock: 
     for entry in entryArray: 
      if entry['id'] == jsonObj['id']: 
       entry['val'] = jsonObj['val'] 
+0

我喜欢这个,我现在就试试!谢谢! – Arch1tect

+0

我现在不认为它是竞争条件,它似乎默认为单线程 - http://werkzeug.pocoo.org/docs/0.11/serving/ – Arch1tect