我有一個使用Google Cloud SQL實例存儲數據的Google App Engine應用程序。我需要我的實例能夠通過平安的調用一次爲數百個客戶端提供服務,這些調用每個都會導致一個或幾個數據庫查詢。我已經包裝了需要數據庫訪問的方法,並將句柄存儲到os.environ中的數據庫連接中。基本上我是如何做到的,請參閱this SO問題/答案。來自App Engine的Google Cloud SQL的連接限制以及如何最佳地重用DB連接?
然而,只要幾百客戶端連接到我的應用程序和觸發器數據庫調用,我開始在谷歌應用程序引擎的錯誤日誌收到這些錯誤(和我的應用程序返回500,當然):
could not connect: ApplicationError: 1033 Instance has too many concurrent requests: 100 Traceback (most recent call last): File "/base/python27_run
有經驗的Google App Engine和Google Cloud SQL用戶的任何提示?提前致謝。
下面是我身邊的方法使用的裝飾需要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.')
你有線程:在app.yaml中真的嗎? – proppy
@proppy是的,我喜歡。謝謝。 – JJC
使用'threadsafe:true'不能很好地使用os.environ,因爲連接不能在線程之間共享。有關線程安全解決方案,請參閱我的回答http://stackoverflow.com/a/10438622/1373093。 –