பயனர் 'send' பொத்தானை வேகமாகத் தட்டும்போது, பாட் ஒரே பதிலை இரண்டு அல்லது மூன்று முறை வழங்கத் தொடங்கியது. பயனர்கள் AI சிந்திக்கத் தொடங்குவதற்கு முன்பே பல செய்திகளை அனுப்பும் அளவுக்கு வேகமாகத் தட்டச்சு செய்தவர்களுக்கு மட்டுமே இந்த இரட்டிப்புத் தன்மை காணப்பட்டது; இந்தத் தவறு உற்பத்திச் சூழலில் (production) நீண்ட காலமாகத் தெரியாமல் மறைந்திருந்தது, ஏனெனில் இந்தத் தவறு நடக்கும் வாய்ப்பு மிகக் குறைவு. முன்கூட்டியே விடுவிக்கப்பட்ட ஒரு தரவுத்தள லாக் (database lock) – எடுக்கப்பட்ட சில மில்லி விநாடிகளுக்குப் பிறகு விடுவிக்கப்பட்டது – உரையாடலைப் பாதுகாப்பற்றதாக்கியது, இதனால் பல செயல்முறைகள் (processes) ஒரே தூண்டுதலுக்குப் பதிலளிக்க வழிவகுத்தது.
லாக் ஏன் தோல்வியடைந்தது
குறியீடு (code) ஒரே ஒரு தரவுத்தள அழைப்பில் ஒரு லாக்-ஐப் பெற்றது, பின்னர் உடனடியாகக் கட்டுப்பாட்டை கோரிக்கை கையாளும் பகுதிக்கு (request handler) ஒப்படைத்தது. லாக்-இன் ஆயுட்காலம் மில்லி விநாடிகளில் இருந்தது, இது AI மாதிரி ஒரு பதிலை உருவாக்கத் தேவைப்படும் நேரத்தை விட மிகக் குறைவானது. மாதிரி தனது வேலையைத் தொடங்கும் போது, லாக் ஏற்கனவே மறைந்துவிட்டதால், இரண்டாவது கோரிக்கை அதே உரையாடல் பதிவைப் பெற்று மற்றொரு பதிலை வழங்குவதைத் தடுக்க எதுவுமில்லை.
இரண்டு அறிகுறிகள் வெளிப்பட்டன:
- ஒரே மாதிரியான பதில்கள் அடுத்தடுத்து அனுப்பப்பட்டன.
- ஒரே கேள்விக்குச் சற்று மாற்றியமைக்கப்பட்ட பதில்கள் வந்தன, ஏனெனில் ஒவ்வொரு செயல்முறையும் பயனரின் அதே உள்ளீட்டிலிருந்து தனக்கென ஒரு தூண்டுதலை (prompt) உருவாக்கின.
பெரும்பாலான பயனர்கள் செய்திகளுக்கு இடையே இடைவெளி விடுவதால், இந்தத் தவறு கவனிக்கப்படாமல் இருந்தது. வேகமாகத் தட்டச்சு செய்பவர்கள் மட்டுமே இந்த ரேஸ் கண்டிஷனை (race condition) தூண்டினர், மேலும் இத்தகைய நிகழ்வுகள் அரிதாகவே நடந்தன.
முழுமையற்ற தீர்வு பலன் அளிக்கவில்லை
வேகமான உள்ளீடுகளைத் தணிக்க (debounce) ஒரு செய்தியைப் பெற்ற பிறகு சிறிய காலதாமதத்தைச் சேர்ப்பதே முதல் தீர்வாக இருந்தது. இரண்டு செய்திகள் மிக விரைவாக வரும்போது இது உதவியது, ஆனால் AI இன்னும் உரையை உருவாக்கித்துக் கொண்டிருக்கும்போதே மூன்றாவது செய்தி வந்தால் அது தோல்வியடைந்தது.
டைமர்கள் (timers) மற்றும் உரையாடல் தரவுகள் ஒரே சேமிப்புப் பகுதியில் (storage bucket) இருந்தபோது இரண்டாவது சிக்கல் உருவானது. பாட் ஒரு கோரிக்கையைச் செயலாக்கி முடித்தவுடன், அது டைமர் பதிவை மேலெழுதி (overwrite), அதன் சொந்த கவுண்ட்டவுனைத் தானே அழித்துவிட்டது. எந்தெந்த செய்திகளுக்கு ஏற்கனவே பதிலளிக்கப்பட்டது என்பதைக் கண்டறியும் திறனை அமைப்பு இழந்தது, இது மேலும் இரட்டிப்புப் பதில்கள் உருவாக வழிவகுத்தது.
ஒரு நம்பகமான பாதுகாப்பை உருவாக்குதல்: பதிப்பு எண்ணிகள், தனிமைப்படுத்தப்பட்ட டைமர்கள் மற்றும் ஒரு லீஸ் (lease)
குழு மூன்று தூண்களைச் சுற்றிச் செயல்பாட்டை மறுவடிவமைப்பு செய்தது:
- பதிப்பு எண்ணி (Version counter) – ஒவ்வொரு வரும் செய்தியும் உரையாடலுடன் சேமிக்கப்பட்டுள்ள ஒரு எண்ணியை (counter) அதிகரிக்கும். ஒரு பதில் உருவாக்கப்பட்டு வரும் நிலையில், எத்தனை செய்திகள் வந்துள்ளன என்பதை இந்த எண்ணி அமைப்புக்குத் தெரிவிக்கும், இதன் மூலம் புதிய உள்ளீட்டைக் கண்டறிவது எளிதாகிறது.
- தனிப்பயன் டிபவுன்ஸ் விண்டோ (Dedicated debounce window) – டைமர்கள் இப்போது உரையாடல் தரவுகளிலிருந்து தனிமைப்படுத்தப்பட்ட ஒரு தனி சேமிப்புப் பகுதியில் உள்ளன. டிபவுன்ஸ் கால அளவின் மீது ஒரு வரம்பு (hard cap) விதிக்கப்பட்டுள்ளதால், ஒரு பயனர் பாட்டைத் தொடர்ந்து தடுத்து நிறுத்த முடியாது.
- செஷன் லீஸ் (Session lease) – அசல் லாக், ஒரு தெளிவான காலாவதித் முத்திரையுடன் (expiry timestamp) கூடிய லீஸால் (lease) மாற்றப்பட்டுள்ளது. இந்த லீஸ் ஒரு compare-and-swap (CAS) செயல்பாட்டைப் பயன்படுத்திப் பெறப்படுகிறது: செயல்முறை தற்போதைய லீஸ் மதிப்பை வாசிக்கிறது, பழைய மதிப்பு சரியாக இருந்தால் மட்டுமே புதிய மதிப்பை எழுதுகிறது, இதன் மூலம் உரையாடலுக்கான பிரத்யேக உரிமையைப் பெறுகிறது. ஒரு செயல்முறை செயலிழந்தால் (crash), லீஸ் தானாகவே காலாவதியாகி, அடுத்த கையாளருக்காக உரையாடலை விடுவிக்கிறது.
புதிய பைப்லைன் எவ்வாறு செயல்படுகிறது
- செய்தி வருகை (Message arrival) – அமைப்பு பதிப்பு எண்ணியை அதிகரித்து, டிபவுன்ஸ் டைமரை (re)செட் செய்கிறது. இது AI-ஐத் தொடங்குவதற்கு முன்பே உடனடியாகப் பயனருக்குத் திரும்புகிறது.
- டைமர் காலாவதி (Timer expiration) – டைமர் கையாளும் பகுதி லீஸைப் பெற முயற்சிக்கும். CAS வெற்றி பெற்றால், கையாளும் பகுதி தொடரும்; இல்லையெனில், மற்றொரு செயல்முறை ஏற்கனவே உரையாடலைக் கொண்டிருப்பதை அறிந்து அது பின்வாங்கும்.
- புதிய உள்ளீட்டைச் சரிபார்த்தல் (Check for new input) – கையாளும் பகுதி தற்போதைய பதிப்பு எண்ணியை, டைமர் தொடங்கியபோது பதிவு செய்த மதிப்புடன் ஒப்பிடுகிறது. எண்ணி அதிகரித்திருந்தால், நிலுவையில் உள்ள செய்திகளை ஒரே தூண்டுதலாக (prompt) ஒருங்கிணைக்கிறது.
- பதிலைத் தயாரித்தல் (Generate a reply) – AI மாதிரி ஒருமுறை இயங்கி, சமீபத்திய அனைத்து பயனர் உள்ளீடுகளையும் உள்ளடக்கிய ஒரு ஒற்றைப் பதிலைத் தருகிறது.
- இறுதிச் சரிபார்ப்பு (Final sanity check) – பதில் அனுப்பப்படுவதற்குச் சற்று முன்பு, கையாளும் பகுதி பதிப்பு எண்ணியை மீண்டும் வாசிக்கிறது. உருவாக்கும் போது புதிய செய்தி வந்திருந்தால், அந்தப் பதில் நிராகரிக்கப்பட்டு, செயல்முறை டைமரை மீண்டும் தொடங்குகிறது; இதன் மூலம் பழைய பதில் பயனருக்குச் சென்றடைவது தவிர்க்கப்படுகிறது.
இந்த அணுகுமுறை இரட்டிப்புப் பதில்களைத் தவிர்க்கிறது, உரையாடல் எவ்வளவு நேரம் தள்ளிப்போகலாம் என்பதைக் கட்டுப்படுத்துகிறது, மேலும் லீஸ் தானாகவே காலாவதியாவதால் செயல்முறை செயலிழப்புகளிலிருந்து தானாகவே மீண்டு வருகிறது.
பாடம்
கிரிட்டிக்கல் செக்ஷன் (critical section) தொடங்குவதற்கு முன்பே மறைந்துவிடும் ஒரு லாக், எந்தப் பாதுகாப்பையும் வழங்குவதில்லை. ஒரு தற்காலிக தரவுத்தள லாக்-க்குப் பதிலாக, காலாவதியாகும் தெளிவான லீஸ் மற்றும் உரையாடல் தரவுகளிலிருந்து தனிமைப்படுத்தப்பட்ட டைமர்களைப் பயன்படுத்துவதன் மூலம், பயனர்கள் மின்னல் வேகத்தில் தட்டச்சு செய்தாலும், பாட் இப்போது ஒரு துல்லியமான, புதுப்பிக்கப்பட்ட பதிலைத் தருவதை உறுதி செய்கிறது. இந்த நிகழ்வு ஒரு காலத்தால் அழியாத பாடத்தை வலியுறுத்துகிறது: ஒரே நேரத்தில் நடக்கும் செயல்பாடுகளுக்கான பாதுகாப்பு முறைகள் (concurrency safeguards), அவை பாதுகாக்கும் வேலையை விட நீண்ட காலம் நீடிக்க வேண்டும், இல்லையெனில் அவை பிழைகள் ஊடுருவ அனுமதிக்கும் கண்ணுக்குத் தெரியாத தடைகளாக மாறிவிடும்.
