簡體   English   中英

當 aiohttp.ClientSession 異步失敗時如何重試任務

[英]How to retry the task when aiohttp.ClientSession fails in async

我很難理解這種行為,因為我是 Python 中的異步函數的新手。

我正在嘗試創建這個簡單的下載工具,我有這個 function

async def download_all_pages(sites):
    print('Running download all pages')
    try:
        async with aiohttp.ClientSession() as session:
            tasks = [asyncio.ensure_future(safe_download_page(session,url)) for url in sites]
            await asyncio.gather(*tasks, return_exceptions = True)
            try:
                await asyncio.sleep(0.25)
            except asyncio.CancelledError:
                print("Got CancelledError")
    except (aiohttp.ServerDisconnectedError, aiohttp.ClientResponseError,aiohttp.ClientConnectorError) as s:
        print("Oops, the server connection was dropped before we finished.")
        print(s)

我像下面這樣初始化這個 function:

try:
    loop.run_until_complete(download_all_pages([url+'/'+str(i) for i in range(1, nb_pages+1)]))
    loop.run_until_complete(download_all_sites([result['href'] for result in results]))
finally:
    loop.run_until_complete(loop.shutdown_asyncgens())
    loop.close()
print('Finished at '+str(datetime.timestamp(datetime.now())))

每當我遇到錯誤時,在這個例子中主要是 aiohttp.ServerDisconnectedError; output 顯示

Oops, the server connection was dropped before we finished.
Server disconnected
Finished at 1606440807.007339
Task was destroyed but it is pending!
Task was destroyed but it is pending!
Task was destroyed but it is pending!
Task was destroyed but it is pending!
Task was destroyed but it is pending!
Task was destroyed but it is pending!

......只有一百萬個Task was destroyed but it is pending!

所以當這個錯誤發生時,我不希望 function 完成,因為還有很多任務要完成; 因此錯誤任務被破壞,但它正在等待處理! .

正如你所看到的,它甚至在調用loop.run_until_complete(download_all_sites([result['href'])之前調用了print('Finished at' ) ;它似乎完全退出了整個腳本。 (編輯:我認為我發現了為什么會發生這種情況。由於上面的 try:,因為它失敗了,所以它直接進入 finally: 子句,因此破壞了待處理的任務。仍然存在如何避免整個斷開連接問題的問題)

您知道如何安全地重試出現 aiohttp.ServerDisconnectedError 錯誤的任務嗎?

這與不使用if __name__ == "__main__":有關系嗎?

這與不使用if __name__ == "__main__":有關系嗎?

它與不使用if __name__ == "__main__" 它與沒有在正確的地方處理異常有關。 asyncio.gather()啟動給定任務並返回其結果的元組。 如果這些任務中的任何一個引發異常, gather()會立即引發相同的異常,而無需等待其余任務完成。

您應該處理未顯示的 function 中的異常, safe_download_page 在此處使用try ,捕獲可以從中恢復的與 aiohttp 相關的異常,然后重試並重試(必要時使用循環,在迭代之間休眠)以防出錯。 像這樣的東西(未經測試):

async def download_all_pages(sites):
    print('Running download all pages')
    async with aiohttp.ClientSession() as session:
        tasks = [asyncio.ensure_future(safe_download_page(session,url)) for url in sites]
        await asyncio.gather(*tasks)
        try:
            await asyncio.sleep(0.25)
        except asyncio.CancelledError:
            print("Got CancelledError")

async def safe_download_page(session, url):
    while True:
        try:
            async with sem:
                await download_page(session, url)
                break
        except (aiohttp.ServerDisconnectedError, aiohttp.ClientResponseError,aiohttp.ClientConnectorError) as s:
            print("Oops, the server connection was dropped on ", url, ": ", s)
            await asyncio.sleep(1)  # don't hammer the server

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM