@@ -59,6 +59,8 @@ class TwitterGraphQLAPI:
5959
6060 # Twitter アカウント ID ごとのシングルトンインスタンスを管理する辞書
6161 __instances : ClassVar [dict [int , TwitterGraphQLAPI ]] = {}
62+ # __instances へのアクセスを保護するためのロック
63+ __instances_lock : ClassVar [asyncio .Lock ] = asyncio .Lock ()
6264
6365 # 必ず Twitter アカウント ID ごとに1つのインスタンスになるように (Singleton)
6466 def __new__ (cls , twitter_account : TwitterAccount ) -> TwitterGraphQLAPI :
@@ -146,24 +148,26 @@ async def removeInstance(cls, twitter_account_id: int) -> None:
146148 twitter_account_id (int): 削除する Twitter アカウントの ID
147149 """
148150
149- if twitter_account_id in cls .__instances :
150- instance = cls .__instances [twitter_account_id ]
151- # シャットダウンタスクをキャンセル
152- ## 複数の同時リクエスト完了時の競合状態を防ぐため、ロックで保護する
153- async with instance ._shutdown_task_lock :
154- if instance ._shutdown_task is not None :
155- if not instance ._shutdown_task .done ():
156- instance ._shutdown_task .cancel ()
157- instance ._shutdown_task = None
158- # ヘッドレスブラウザをシャットダウン
159- ## browser.shutdown() が例外を投げた場合でもレジストリエントリは確実に削除する必要があるため、try/except で囲む
160- if instance ._browser is not None and instance ._browser .is_setup_complete is True :
161- try :
162- await instance ._browser .shutdown ()
163- except Exception as ex :
164- logging .error (f'Failed to shutdown browser for Twitter account { twitter_account_id } :' , exc_info = ex )
165- # レジストリエントリを削除
166- del cls .__instances [twitter_account_id ]
151+ # __instances へのアクセスを保護するため、ロックで保護する
152+ async with cls .__instances_lock :
153+ if twitter_account_id in cls .__instances :
154+ instance = cls .__instances [twitter_account_id ]
155+ # シャットダウンタスクをキャンセル
156+ ## 複数の同時リクエスト完了時の競合状態を防ぐため、ロックで保護する
157+ async with instance ._shutdown_task_lock :
158+ if instance ._shutdown_task is not None :
159+ if not instance ._shutdown_task .done ():
160+ instance ._shutdown_task .cancel ()
161+ instance ._shutdown_task = None
162+ # ヘッドレスブラウザをシャットダウン
163+ ## browser.shutdown() が例外を投げた場合でもレジストリエントリは確実に削除する必要があるため、try/except で囲む
164+ if instance ._browser is not None and instance ._browser .is_setup_complete is True :
165+ try :
166+ await instance ._browser .shutdown ()
167+ except Exception as ex :
168+ logging .error (f'Failed to shutdown browser for Twitter account { twitter_account_id } :' , exc_info = ex )
169+ # レジストリエントリを削除
170+ del cls .__instances [twitter_account_id ]
167171
168172 async def __scheduleShutdownTask (self ) -> None :
169173 """
0 commit comments