前一篇介紹了使用happybase連接池未關(guān)閉連接引起B(yǎng)roken pipe異常
這篇繼續(xù)分析褪秀,當(dāng)每次我們使用完連接后手動close依然會存在一個問題。
通常我們使用連接池會在全局變量中實例話一個pool對象溜歪,后續(xù)再通過pool獲取連接進(jìn)行后續(xù)操作许蓖。
當(dāng)我們創(chuàng)建連接池對象后膊爪,happybase會根據(jù)size創(chuàng)建多個connection實例到隊列中嚎莉,同時會將第一個connection連接打開,注釋中提到之所以打開一個連接是為了確保如果出現(xiàn)一些找不到主機(jī)之類的錯誤能第一時間發(fā)現(xiàn)。
class ConnectionPool(object):
def __init__(self, size, **kwargs):
if not isinstance(size, int):
raise TypeError("Pool 'size' arg must be an integer")
if not size > 0:
raise ValueError("Pool 'size' arg must be greater than zero")
logger.debug(
"Initializing connection pool with %d connections", size)
self._lock = threading.Lock()
self._queue = queue.LifoQueue(maxsize=size)
self._thread_connections = threading.local()
connection_kwargs = kwargs
connection_kwargs['autoconnect'] = False
for i in range(size):
connection = Connection(**connection_kwargs)
self._queue.put(connection)
# The first connection is made immediately so that trivial
# mistakes like unresolvable host names are raised immediately.
# Subsequent connections are connected lazily.
with self.connection():
pass
但是問題就出現(xiàn)在這里赃额,當(dāng)我們初始化一個連接池后如果沒有立即使用叫确,那么第一個連接池中的連接會出現(xiàn)被斷開的情況,那么接下來拿到這個連接去操作都會出現(xiàn)broken pipe異常飞盆。
這里只探討對于這個問題可能的解決方法
- 外部使用的時候為方法增加異常重試次乓,連接池中出現(xiàn)異常本身會重置連接
2.第一次不打開連接,如#147處理方案
這個解決新家了一個autoconnect的參數(shù)票腰,當(dāng)autoconnect為False就不執(zhí)行第一個連接城看。但是在connection的異常處理中還是會打開一個連接,這樣也會出現(xiàn)同樣的問題杏慰,所以這里也應(yīng)該加上测柠。
try:
# Open connection, because connections are opened lazily.
# This is a no-op for connections that are already open.
connection.open()
# Return value from the context manager's __enter__()
yield connection
connection.close()
except (TException, socket.error):
# Refresh the underlying Thrift client if an exception
# occurred in the Thrift layer, since we don't know whether
# the connection is still usable.
logger.info("Replacing tainted pool connection")
connection._refresh_thrift_client()
if autoconnect:
connection.open()
3.和1類似,只是在 happybase中處理網(wǎng)絡(luò)異常重置連接后重試#184