तुमचे asyncio टास्क काम करत असतानाच नष्ट होऊ शकतात
अनेक Python सेवा बॅकग्राउंड वर्क चालवण्यासाठी या पॅटर्नचा वापर करतात:
async def create_order(order):
await save(order)
asyncio.create_task(send_webhook(order))
return {"status": "created"}
क्लायंटला वाट पाहायला न लावता वेबहुक (webhook) पाठवणे हे याचे उद्दिष्ट आहे. हे डेव्हलपमेंटमध्ये व्यवस्थित चालते. परंतु, प्रोडक्शनमध्ये (production) हे यादृच्छिकपणे (randomly) फेल होते.
समस्या garbage collection मध्ये आहे.
जेव्हा तुम्ही asyncio.create_task कॉल करता आणि त्याचे रिझल्ट सेव्ह करत नाही, तेव्हा ते टास्क garbage collection साठी पात्र ठरते. इव्हेंट लूप (event loop) टास्कसाठी फक्त weak references ठेवतो. जर इतर कशानेही त्या टास्ककडे निर्देश (point) केला नसेल, तर Python ते टास्क चालू असतानाच रिकलेम (reclaim) करू शकते.
तुमचे काम अचानक थांबते. तुमच्या ट्रॅकरमध्ये कोणतीही एरर दिसत नाही. कोड अगदी परफेक्ट असतो. टास्क फक्त गायब होतो.
तुम्हाला तुमच्या stderr मध्ये असा लॉग दिसू शकतो:
Task was destroyed but it is pending!
ही एरर शोधणे कठीण असते कारण ती प्रत्यक्ष बिघाडानंतर बराच वेळ निघून गेल्यावर समोर येते.
हे कसे सुधारावे:
रेफरन्स धरून ठेवण्यासाठी background task set वापरा.
background_tasks = set()
def fire_and_forget(coro):
task = asyncio.create_task(coro)
background_tasks.add(task)
task.add_done_callback(background_tasks.discard)
return task
हा set टास्क जिवंत ठेवतो. काम पूर्ण झाल्यावर callback त्याला काढून टाकते. यामुळे memory leaks टाळले जातात आणि garbage collector ला तुमचे टास्क नष्ट करण्यापासून रोखता येते.
Python 3.11 आणि त्यापुढील आवृत्त्यांसाठी, तुम्ही TaskGroups वापरू शकता. TaskGroup त्याच्या आत असलेल्या प्रत्येक टास्कसाठी strong references धरून ठेवतो. लक्षात ठेवा की, TaskGroup ब्लॉक बाहेर पडण्यापूर्वी सर्व टास्क पूर्ण होण्याची वाट पाहतो. जर युजरला प्रतिसाद देण्यापूर्वी काम पूर्ण होणे आवश्यक असेल, तर याचा वापर करा.
जड (heavy) बॅकग्राउंड वर्कसाठी, supervisor pattern वापरा:
- स्टार्टअपला एक दीर्घकाळ टिकणारे (long-lived) टास्क तयार करा.
- त्याला काम पाठवण्यासाठी queue वापरा.
- रिक्वेस्ट हँडलर फक्त queue मध्ये आयटम्स जोडतो.
यामुळे तुमचे काम सुरक्षित राहते आणि तुम्हाला नंतर retries जोडण्याची सुविधा मिळते.
Python मध्ये, तुम्हाला तुमच्या टास्कची जबाबदारी घ्यावी लागते. जर तुम्ही त्याचा रेफरन्स धरून ठेवला नाही, तर रनटाइम त्यांचे संरक्षण करणार नाही.
Source: https://dev.to/r9v/your-asyncio-task-can-be-garbage-collected-mid-flight-3kg1
