તમારું asyncio task કામ ચાલુ હોય ત્યારે અટકી શકે છે
ઘણા Python સર્વિસીસ બેકગ્રાઉન્ડ વર્ક ચલાવવા માટે આ પેટર્નનો ઉપયોગ કરે છે:
async def create_order(order):
await save(order)
asyncio.create_task(send_webhook(order))
return {"status": "created"}
ધ્યેય ક્લાયન્ટને રાહ ન જોવડાવ્યા વિના વેબહૂક (webhook) મોકલવાનો છે. આ ડેવલપમેન્ટમાં કામ કરે છે. પ્રોડક્શનમાં, તે અચાનક નિષ્ફળ જાય છે.
સમસ્યા ગાર્બેજ કલેક્શન (garbage collection) ની છે.
જ્યારે તમે asyncio.create_task ને કોલ કરો છો અને પરિણામને સેવ નથી કરતા, ત્યારે તે task ગાર્બેજ કલેક્શન માટે પાત્ર બની જાય છે. ઇવેન્ટ લૂપ (event loop) ફક્ત tasks માટે 'weak references' રાખે છે. જો બીજું કંઈ પણ તે task તરફ નિર્દેશિત ન કરતું હોય, તો Python તેને હજુ ચાલુ હોય તે દરમિયાન જ reclaim કરી શકે છે.
તમારું કામ અચાનક અટકી જાય છે. તમારા ટ્રેકરમાં કોઈ ભૂલ (error) દેખાતી નથી. કોડ એકદમ પરફેક્ટ હોય છે. task ફક્ત ગાયબ થઈ જાય છે.
તમને તમારા 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 task ને જીવંત રાખે છે. કામ પૂરું થયા પછી callback તેને દૂર કરે છે. આ મેમરી લીક (memory leaks) ને અટકાવે છે અને ગાર્બેજ કલેક્ટરને તમારા tasks ને બંધ કરતા રોકે છે.
Python 3.11 અને તેનાથી નવા વર્ઝન માટે, તમે TaskGroups નો ઉપયોગ કરી શકો છો. TaskGroup તેની અંદરના દરેક task માટે 'strong references' રાખે છે. નોંધ લેશો કે TaskGroup બ્લોકમાંથી બહાર નીકળતા પહેલા તમામ tasks પૂરા થાય તેની રાહ જોશે. જો તમારે યુઝરને જવાબ આપતા પહેલા કામ પૂર્ણ કરવું જરૂરી હોય, તો આનો ઉપયોગ કરો.
ભારે બેકગ્રાઉન્ડ વર્ક માટે, supervisor pattern નો ઉપયોગ કરો:
- સ્ટાર્ટઅપ વખતે એક લાંબા સમય સુધી ચાલતું (long-lived) task બનાવો.
- તેને કામ મોકલવા માટે queue નો ઉપયોગ કરો.
- request handler ફક્ત queue માં આઇટમ્સ ઉમેરે છે.
આ સુનિશ્ચિત કરે છે કે તમારું કામ સુરક્ષિત રહે છે અને તમને પછીથી retries ઉમેરવાની સુવિધા આપે છે.
Python માં, તમારે તમારા tasks ના માલિક બનવું પડશે. જો તમે તેનો રેફરન્સ નહીં રાખો, તો runtime તેમને સુરક્ષિત રાખશે નહીં.
Source: https://dev.to/r9v/your-asyncio-task-can-be-garbage-collected-mid-flight-3kg1
