Tôi có ứng dụng Google App Engine sử dụng phiên bản Google Cloud SQL để lưu trữ dữ liệu. Tôi cần trường hợp của tôi để có thể phục vụ hàng trăm khách hàng tại một thời điểm, thông qua các cuộc gọi yên tĩnh, mỗi kết quả trong một hoặc một số truy vấn DB. Tôi đã gói các phương thức cần truy cập DB và lưu trữ xử lý vào kết nối DB trong os.environ. Xem this SO câu hỏi/câu trả lời về cơ bản cách tôi đang thực hiện.Giới hạn kết nối cho Google Cloud SQL từ Máy ứng dụng là gì và cách tốt nhất để sử dụng lại các kết nối DB?
Tuy nhiên, ngay sau khi một vài trăm khách hàng kết nối với ứng dụng và kích hoạt cuộc gọi cơ sở dữ liệu của tôi, tôi bắt đầu nhận được những sai sót trong Google App bản ghi lỗi Engine (và ứng dụng của tôi trả 500, tất nhiên):
could not connect: ApplicationError: 1033 Instance has too many concurrent requests: 100 Traceback (most recent call last): File "/base/python27_run
Bất kỳ mẹo nào từ người dùng có kinh nghiệm về Google App Engine và Google Cloud SQL? Cảm ơn trước.
Dưới đây là các mã cho các trang trí tôi sử dụng xung quanh phương pháp đòi hỏi phải có kết nối DB:
def with_db_cursor(do_commit = False):
""" Decorator for managing DB connection by wrapping around web calls.
Stores connections and open connection count in the os.environ dictionary
between calls. Sets a cursor variable in the wrapped function. Optionally
does a commit. Closes the cursor when wrapped method returns, and closes
the DB connection if there are no outstanding cursors.
If the wrapped method has a keyword argument 'existing_cursor', whose value
is non-False, this wrapper is bypassed, as it is assumed another cursor is
already in force because of an alternate call stack.
Based mostly on post by : Shay Erlichmen
At: https://stackoverflow.com/a/10162674/379037
"""
def method_wrap(method):
def wrap(*args, **kwargs):
if kwargs.get('existing_cursor', False):
#Bypass everything if method called with existing open cursor
vdbg('Shortcircuiting db wrapper due to exisiting_cursor')
return method(None, *args, **kwargs)
conn = os.environ.get("__data_conn")
# Recycling connection for the current request
# For some reason threading.local() didn't work
# and yes os.environ is supposed to be thread safe
if not conn:
conn = _db_connect()
os.environ["__data_conn"] = conn
os.environ["__data_conn_ref"] = 1
dbg('Opening first DB connection via wrapper.')
else:
os.environ["__data_conn_ref"] = (os.environ["__data_conn_ref"] + 1)
vdbg('Reusing existing DB connection. Count using is now: {0}',
os.environ["__data_conn_ref"])
try:
cursor = conn.cursor()
try:
result = method(cursor, *args, **kwargs)
if do_commit or os.environ.get("__data_conn_commit"):
os.environ["__data_conn_commit"] = False
dbg('Wrapper executing DB commit.')
conn.commit()
return result
finally:
cursor.close()
finally:
os.environ["__data_conn_ref"] = (os.environ["__data_conn_ref"] -
1)
vdbg('One less user of DB connection. Count using is now: {0}',
os.environ["__data_conn_ref"])
if os.environ["__data_conn_ref"] == 0:
dbg("No more users of this DB connection. Closing.")
os.environ["__data_conn"] = None
db_close(conn)
return wrap
return method_wrap
def db_close(db_conn):
if db_conn:
try:
db_conn.close()
except:
err('Unable to close the DB connection.',)
raise
else:
err('Tried to close a non-connected DB handle.')
Bạn có chủ đề an toàn: true trong app.yaml? – proppy
@proppy yes, tôi có. Cảm ơn. – JJC
Sử dụng 'threadsafe: true' sẽ không hoạt động tốt với việc sử dụng os.environ vì các kết nối không thể được chia sẻ giữa các luồng. Xem câu trả lời của tôi http://stackoverflow.com/a/10438622/1373093 để biết giải pháp luồng an toàn. –