2015-12-09 14 views
7

Tôi có một ứng dụng Flask, đang chạy trong Apache, dựa trên PyMySQL. Ứng dụng cung cấp một loạt các lệnh REST. Nó đang chạy dưới Python 3.PyMySQL trong Flask/Apache đôi khi trả lại kết quả rỗng

Nếu không cung cấp toàn bộ nguồn, chương trình được cấu trúc như:

#!flask/bin/python 
import json 
import pymysql 
from flask import * 

# Used to hopefully share the connection if the process isn't restarted 
mysql_connection = None 

# Gets the mysql_connection, or opens it 
GetStoreCnx(): 
    global mysql_connection 
    if (mysql_connection != None): 
     store_connection_string = "" 
     # Get the connection string from the config file 
     with open('config/storedb.json', 'r') as f: 
      store_connection_string = json.load(f) 
     mysql_connection = pymysql.connect(**store_connection_string) 
    return mysql_connection; 


class Server(Flask): 
    def __init__(self, *args, **kwargs): 
     super().__init__(*args, **kwargs) 

# Return results via REST 
@app.route('/results1', methods=['GET']) 
def get_result1(): 
    cnx = GetStoreCnx(); 
    cursor = cnx.cursor(); 
    query = """ 
     SELECT 
      result_name, 
      successful 
     FROM 
      results 
     """ 
    cursor.execute(query) 
    cnx.commit() 
    result = cursor.fetchall() 
    return json.dumps(result) 

# Run server, if needed 
if __name__ == '__main__': 
    app.run(host='0.0.0.0', debug=True) 

Có một vài nghỉ ngơi nhiều hơn gọi - nhưng tất cả đều về cơ bản làm điều tương tự (ví dụ: - nhận kết nối, tạo con trỏ, chạy truy vấn chọn cơ bản - đôi khi có nhiều hơn 2 trường, thực hiện truy vấn, tìm nạp kết quả và trả về kết quả là đối tượng JSON). Các cam kết không cần thiết, nhưng nó có vẻ là một vấn đề đang chạy với PyMySQL đã dẫn đến việc nhận dữ liệu cũ.

Vấn đề là các cuộc gọi REST đôi khi trả lại các tập JSON rỗng (ví dụ: []), Điều tra thêm cho thấy rằng lệnh gọi thực thi đôi khi trả lại kết quả hoàn toàn trống nhưng không ném ngoại lệ. Điều này xảy ra thường xuyên - nhưng không phải lúc nào cũng vậy. Một số cuộc gọi thực hiện thành công các giá trị trả lại. Khi tôi cố gắng giữ cuộc gọi đi cho đến khi nó trả về kết quả (như:

while(cursor.execute(query) < 1): 
    pass 

) quá trình này đi vào một vòng lặp vô tận, cuối cùng (nhanh chóng) ngăn chặn apache từ phục vụ bất kỳ yêu cầu nhiều hơn nữa.

Máy chủ (hiện tại) chỉ phục vụ khoảng 5 cuộc gọi một giây. Vấn đề không xuất hiện nếu tôi sử dụng máy chủ phát triển.

Có cách nào để tôi có thể ngăn chặn lỗi này không? Nó là một lỗi trong PyMySQL? Là một cái gì đó tôi đang làm ngăn chặn các kết nối chính xác với MySQL?

Trả lời

1

Bạn đang tạo một kết nối mysql toàn cầu được sử dụng bởi ứng dụng của bạn, hovever pymysql tuyên bố một threadsafety trong tổng số 1, mà theo các dbapi2 specification có nghĩa là:

1 Threads may share the module, but not connections. 

Khi các yêu cầu conncurrent trong bình sẽ được phục vụ bởi khác nhau chủ đề bạn không nên chia sẻ kết nối. Lý do bạn không gặp bất kỳ vấn đề nào khi sử dụng máy chủ phát triển là nó chạy một luồng đơn.

Để tránh điều này bạn có thể một trong hai:

  • tạo một kết nối mới cho mỗi chủ đề, lưu trữ nó như chủ đề địa phương để sử dụng tiếp
  • tạo một kết nối mới cho mỗi yêu cầu, lưu nó trong flask.g để biết thêm sử dụng

Để làm như vậy chức năng GetStoreCnx của bạn có thể thay đổi như thế này:

import threading 
thread_local = threading.local() 

def GetStoreCnx():   
    if not hasattr(thread_local, 'mysql_connection'): 
     store_connection_string = "" 
     # Get the connection string from the config file 
     with open('config/storedb.json', 'r') as f: 
      store_connection_string = json.load(f) 
     mysql_connection = pymysql.connect(**store_connection_string) 
     thread_local.mysql_connection = mysql_connection 
    return thread_local.mysql_connection; 

SQLAlchemy thực hiện điều gì đó tương tự với scoped_session() của nó. Điều này cũng sẽ hoạt động với flask.g thay vì thread_local cho một kết nối theo yêu cầu.

Các vấn đề liên quan