જ્યારે તમે Node.js સાથે ડેવલપમેન્ટ કરી રહ્યા હોવ, ત્યારે શરૂઆતમાં એરર હેન્ડલિંગ ખૂબ જ સરળ લાગે છે. તમે એક રૂટને try-catch માં લપેટી દો છો, 500 સ્ટેટસ કોડ મોકલો છો, અને ક્લાયન્ટ નક્કી કરે છે કે આગળ શું કરવું. આ મોડેલ HTTP માટે બરાબર કામ કરે છે, પરંતુ જે ક્ષણે તમે બેકગ્રાઉન્ડ જોબ્સમાં જશો, તે તૂટી પડે છે. ક્યુ સિસ્ટમમાં, કોઈ ક્લાયન્ટ રાહ જોતો હોતો નથી. ત્યાં ફક્ત એક વર્કર, એક પેલોડ અને Redis, RabbitMQ, અથવા SQS માં ક્યાંક વધતો જતો રીટ્રાય કાઉન્ટર હોય છે. જો તમે ફેઈલ્યોરને તે જ રીતે હેન્ડલ કરશો જે રીતે તમે ફેઈલ થયેલા વેબ રિક્વેસ્ટને હેન્ડલ કરો છો, તો તમે માત્ર એક ટ્રાન્ઝેક્શન ગુમાવશો એટલું જ નહીં, પરંતુ તમે તમારી આખી પાઇપલાઇનને અટકાવી દેશો, કમ્પ્યુટ પાવર વેડફશો અથવા એક જ પોઈઝન્ડ મેસેજ પર તમારા વર્કર્સને વારંવાર ક્રેશ કરશો.
બેકગ્રાઉન્ડ જોબ્સમાં HTTP માઇન્ડસેટ નિષ્ફળ જાય છે
રિક્વેસ્ટ-રિસ્પોન્સ સાયકલમાં, ફીડબેક લૂપ તાત્કાલિક હોય છે. વપરાશકર્તા બટન પર ક્લિક કરે છે, સર્વર એરર ફેંકે છે, અને વપરાશકર્તાને ફેઈલ્યોર સ્ક્રીન દેખાય છે. ક્લીનઅપ સરળ છે. ક્યુ વર્કર અલગ રહે છે. તે એક જોબ ખેંચે છે, તેના પર સેકન્ડો કે મિનિટો સુધી કામ કરે છે, અને પછી સફળતાનું એક્નોલેજમેન્ટ આપે છે. જો વચ્ચે કંઈક ખોટું થાય છે, તો ક્યુને ખબર નથી હોતી કે કેમ. તેને ફક્ત એટલું જ ખબર છે કે એક્નોલેજમેન્ટ ક્યારેય મળ્યું નથી. તમારી કોન્ફિગરેશનના આધારે, તે ફરીથી પ્રયાસ (retry) કરશે, કદાચ અનંતકાળ સુધી. એક ખોટી રીતે બનાવેલ (malformed) પેલોડ સેંકડો વખત વર્કર્સ વચ્ચે અથડાઈ શકે છે, જેનાથી CPU વેડફાય છે અને ખરેખર પ્રોસેસિંગની જરૂર હોય તેવી કાયદેસરની જોબ્સ પાછળ તે છુપાઈ જાય છે.
બે પ્રકારના ફેઈલ્યોર (Failures)
સ્થિતિસ્થાપક (resilient) ક્યુઝનો પહેલો નિયમ એ છે કે દરેક એરરને એકસરખી રીતે લેવાનું બંધ કરો. એરર આવે તે ક્ષણે તમારે તેને બે જૂથોમાં વહેંચવી જોઈએ.
રીટ્રાય કરી શકાય તેવા ફેઈલ્યોર ક્ષણિક (transient) હોય છે. નેટવર્ક ટાઈમઆઉટ, થર્ડ-પાર્ટી API માંથી આવતી રેટ લિમિટ્સ, અથવા ડેટાબેઝ કનેક્શન જે પોલ (pool) ક્ષણિક રીતે ખાલી હોવાને કારણે રીસેટ થયું હોય તેવું વિચારો. આ દબાણ હેઠળ રહેલા જીવંત સિસ્ટમના લક્ષણો છે. તે હવેથી બે મિનિટ પછીના આગામી પ્રયાસમાં સફળ થઈ શકે છે.
કાયમી (Permanent) ફેઈલ્યોર એ 'પોઈઝન્ડ પિલ્સ' (poison pills) છે. આમાં malformed payloads, schema validation errors, અથવા કોઈ અપસ્ટ્રીમ સર્વિસે તેનો કોન્ટ્રાક્ટ બદલવાને કારણે ખૂટેલા જરૂરી ફિલ્ડ્સનો સમાવેશ થાય છે. આને ફરીથી પ્રયાસ કરવો એ માત્ર બગાડ છે. તેઓ સો વાર પ્રયાસ કરવા છતાં સમાન રીતે જ નિષ્ફળ જશે.
જો તમારો catch બ્લોક આ બંને વચ્ચેનો તફાવત જાણી શકતો નથી, તો તમારી ક્યુ અંધારામાં ઉડી રહી છે.
પેટર્ન 1: Catch બ્લોકમાં એરર્સનું વર્ગીકરણ કરો
તમારા વર્કરના catch બ્લોકને ફાઇલમાં સૌથી વિચારપૂર્વક લખાયેલો કોડ હોવો જોઈએ. જ્યારે કોઈ એરર આવે, ત્યારે તરત જ તેની તપાસ કરો. શું એરર કોડ ECONNRESET છે અથવા ટાઈમઆઉટ છે? તેને રીટ્રાય માટે ક્યુમાં મૂકો. શું તે SyntaxError છે, Joi વેલિડેશન રિજેક્શન છે, અથવા કોઈ ફોરેન કી કન્સ્ટ્રેઈન્ટ ખૂટે છે? તેને સીધું ડેડ-લેટર ક્યુ (DLQ) માં ખસેડો, અને તેને તમારી રીટ્રાય લિમિટમાં ગણશો નહીં.
મોટાભાગની Node.js ક્યુ લાઇબ્રેરીઓ, જેમાં BullMQ અને Bee Queue નો સમાવેશ થાય છે, તમને કસ્ટમ બેકઓફ વ્યૂહરચનાઓ (backoff strategies) અને એરર હૂક્સ વ્યાખ્યાયિત કરવા દે છે. તેનો ઉપયોગ કરો. કાયમી એરર ક્યારેય ડિફોલ્ટ રીતે ત્રણ વાર ઊંઘીને રીટ્રાય ન કરવી જોઈએ. તેને મુખ્ય ક્યુમાંથી બહાર કાઢી લેવી જોઈએ જેથી તમારી બાકીની જોબ્સ વહેતી રહે. DLQ ચોક્કસ પેલોડ અને એરર કોન્ટેક્સ્ટને સાચવે છે, જે તમને બગ પેચ કર્યા પછી અથવા સ્કીમા સુધાર્યા પછી જોબને પછીથી ફરીથી ચલાવવાની (replay) મંજૂરી આપે છે.
પેટર્ન 2: જિટર (Jitter) સાથે એક્સપોનેન્શિયલ બેકઓફ
તરત જ રીટ્રાય કરવું એ આક્રમક છે. જો ડાઉનસ્ટ્રીમ ડેટાબેઝ પહેલેથી જ લોડ હેઠળ હાંફી રહ્યો હોય, તો પચાસ વર્કર્સ દ્વારા દર બે સેકન્ડે તેને ફરીથી હિટ કરવાથી તે સંપૂર્ણપણે ઠપ્પ થઈ જશે. તમારે પાછા હટવાની અને સિસ્ટમને રિકવર થવા માટે જગ્યા આપવાની જરૂર છે.
એક્સપોનેન્શિયલ બેકઓફનો ઉપયોગ કરો. પ્રથમ ફેઈલ્યોર પર, એક સેકન્ડ રાહ જુઓ. બીજા પર, બે સેકન્ડ. પછી ચાર, પછી આઠ, પાંચ મિનિટ જેવી વ્યાજબી મર્યાદા સુધી. પરંતુ માત્ર ટાઈમિંગ પૂરતું નથી. જો દરેક ફેઈલ થયેલ જોબ બરાબર એક જ અંતરાલનો ઉપયોગ કરે છે, તો બેકઓફ સમાપ્ત થતાં તે બધી જ અથડાઈ જશે. તે સિંક્રનાઇઝ્ડ તરંગ, જેને ક્યારેક 'થન્ડરિંગ હર્ડ' (thundering herd) કહેવામાં આવે છે, તે રિકવર થતી સર્વિસ પર વધુ પડતું દબાણ લાવી શકે છે.
જિટર (jitter) ઉમેરો. તમારા ગણતરી કરેલા વિલંબને (delay) રેન્ડમ ટકાવારી દ્વારા બદલો, કદાચ દસ થી વીસ ટકા. ચાર સેકન્ડ 4.2 અથવા 4.7 બની જાય છે. આ સાદું રેન્ડમનેસ રીટ્રાય સ્પાઇકને ફેલાવી દે છે અને તમારા ઇન્ફ્રાસ્ટ્રક્ચરને તરંગોમાં પછાડતા બચાવે છે.
પેટર્ન 3: આઈડેમપોટન્સી (Idempotency) માટે ડિઝાઇન કરો
અહીં ક્યુ ઇન્ફ્રાસ્ટ્રક્ચર બિઝનેસ લોજિક સાથે મળે છે. એક એવી જોબની કલ્પના કરો જે પેમેન્ટ પ્રોવાઈડર દ્વારા ગ્રાહક પાસેથી ચાર્જ લે છે. વર્કર સફળતાપૂર્વક ચાર્જ પોસ્ટ કરે છે, પરંતુ તે તમારા ડેટાબેઝમાં સફળતાની નોંધ લે તે પહેલાં અથવા જોબને એક્નોલેજ કરે તે પહેલાં કનેક્શન કપાઈ જાય છે. ક્યુ ફેઈલ્યોર જુએ છે. તે રીટ્રાય કરે છે. ગ્રાહક પાસેથી બે વાર ચાર્જ લેવામાં આવે છે.
Node.js માં, દરેક સાઇડ ઇફેક્ટને (side effect) આઈડેમપોટેન્ટ (idempotent) બનાવીને આનાથી બચો. જોબ ID અથવા બિઝનેસ-વિશિષ્ટ ઓળખકર્તા (identifier) પરથી આઈડેમપોટેન્સી કી (idempotency key) જનરેટ કરો. તમે ચાર્જ બનાવતા પહેલા અથવા ઈમેલ મોકલતા પહેલા અથવા ઇન્વેન્ટરી એડજસ્ટ કરતા પહેલા, તપાસો કે તે કામ પહેલેથી જ થઈ ગયું છે કે નહીં. તે કી તમારા ડેટાબેઝ અને કોઈપણ થર્ડ-પાર્ટી API ને (જે તેને સ્વીકારે છે) પાસ કરો. તમારા જોબ્સને એવી રીતે સ્ટ્રક્ચર કરો કે જેથી સમાન પેલોડ (payload) ને દસ વાર ચલાવવાથી તે એક વાર ચલાવવા જેટલું જ પરિણામ આપે. આ એક આદત નાણાકીય અને ડેટા-ઇન્ટિગ્રિટી (data-integrity) બગ્સની આખી શ્રેણીને દૂર કરે છે.
પેટર્ન 4: તમારી ડેડ-લેટર ક્યૂ (Dead-Letter Queue) ને ડેશબોર્ડની જેમ ગણો
DLQ એ કોઈ કબ્રસ્તાન નથી જ્યાં ખરાબ જોબ્સ ભૂલી જવા માટે જાય છે. તે એક ઓપરેશનલ ટૂલ છે, અને તે તમારી સૌથી વધુ દેખરેખ રાખવામાં આવતી સપાટીઓ (surfaces) માંથી એક હોવું જોઈએ.
જ્યારે DLQ ની ઊંડાઈ (depth) વધે ત્યારે એલર્ટ્સ સેટ કરો. DLQ માં એક સિંગલ મેસેજ પણ ઘણીવાર એનો અર્થ છે કે તમારું વેલિડેશન લોજિક (validation logic) તૂટી ગયું છે, અપસ્ટ્રીમ સ્કીમા (upstream schema) બદલાઈ ગયું છે, અથવા ડાઉનસ્ટ્રીમ સર્વિસ (downstream service) એવો કચરો (garbage) મોકલી રહી છે જેને તમે હવે ઓળખી શકતા નથી. ગ્રાહકો ફરિયાદ કરવાનું શરૂ કરે તે પહેલાં તમારે આ સંકેતો (signals) પકડવા જોઈએ. એક એવું ડેશબોર્ડ બનાવો જે તમને રો (raw) પેલોડ, સ્ટેક ટ્રેસ (stack trace) અને ટાઈમસ્ટેમ્પની તપાસ કરવાની મંજૂરી આપે. એક રનબુક (runbook) તૈયાર રાખો: નિષ્ફળતાની તપાસ કરો, કોડને પેચ કરો, અને પછી મેસેજને યોગ્ય ક્રમમાં ફરીથી પ્લે (replay) કરો. જો તમારી ક્યૂ ઇમ્પ્લીમેન્ટેશન (queue implementation) તેને સપોર્ટ કરતી હોય, તો એબ્સોલ્યુટ કાઉન્ટની સાથે ગ્રોથ રેટ (growth rate) પર પણ એલર્ટ સેટ કરો, કારણ કે એક ખરાબ ડિપ્લોય (deploy) મિનિટોમાં DLQ ને ભરી શકે છે.
પેટર્ન 5: જ્યારે શંકા હોય, ત્યારે પ્રોસેસને ક્રેશ કરી દો
Node.js એક V8 આઇસોલેટ (isolate) ની અંદર સિંગલ ઇવેન્ટ લૂપ (event loop) પર ચાલે છે. એક અનહેન્ડલ્ડ પ્રોમિસ રિજેક્શન (unhandled promise rejection) અથવા an
