दस्तावेज़ पर जाएँ
PHP

पुनः प्रयास और idempotency

क्या retry होता है, क्या जानबूझकर नहीं, और क्यों retry किया गया send दोहरा नहीं सकता।

भेजना

क्लाइंट हर send (emails->send, emails->sendBatch, templates->send और broadcasts->send) पर एक Idempotency-Key जोड़ता है, जो प्रति कॉल एक बार oe- और एक रैंडम UUID के रूप में बनती है, और उस कॉल के पुनः प्रयास उसी को दोबारा इस्तेमाल करते हैं। API कुछ भी भेजने से पहले उस कुंजी पर दावा कर लेता है, इसलिए पुनः प्रयास दूसरा संदेश भेजने के बजाय मूल संदेश को replay करता है, जबकि जानबूझकर की गई दो send कॉल फिर भी दो बार भेजती हैं। ये अलग इरादे हैं और अलग ही रहते हैं।

इस गारंटी को प्रोसेस के पार ले जाने के लिए अपनी idempotencyKey: पास करें, ताकि जो जॉब क्रैश होकर दोबारा चला वह अपने sends दोहराने के बजाय उन्हें replay करे। replay replayed को true रखकर और सहेजे गए संदेश को उसकी मौजूदा स्थिति में लौटाकर जवाब देता है।

idempotency.php
$invoiceId = 'inv_2026_09_4192'; $sent = $client->emails->send([    'from' => '[email protected]',    'to' => '[email protected]',    'subject' => 'Your September invoice',    'text' => 'Invoice attached.',], idempotencyKey: 'invoice:' . $invoiceId); echo $sent['id'], ' ', ($sent['replayed'] ?? false) ? 'replayed' : 'sent', PHP_EOL;

इसे उस चीज़ से निकालें जिसने send को ज़रूरी बनाया। घड़ी से कभी नहीं। किसी कुंजी को अलग बॉडी के साथ दोबारा इस्तेमाल करने पर चुपचाप replay होने के बजाय 422 idempotency_key_reuse के साथ अस्वीकार किया जाता है। कुंजी अक्षरों, अंकों, _, ., : या - के 1 से 255 वर्णों की होती है, और इसके अलावा कुछ भी 400 invalid_idempotency_key है।

बाकी सब

हर GET पर पुनः प्रयास होता है। किसी write पर पुनः प्रयास केवल तभी होता है जब दूसरी हूबहू वही रिक्वेस्ट पहली से कुछ अलग मायने रख ही न सके, और send इस कसौटी पर खरा उतरता है क्योंकि उसकी idempotency कुंजी दोहराव को replay में बदल देती है।

कॉलपुनः प्रयासक्यों
हर GETहाँकुछ नहीं बदलता।
emails->send, emails->sendBatch, templates->send, broadcasts->sendहाँidempotency key दोहराव को replay बना देती है।
emails->cancel, emails->reschedule, broadcasts->cancel, forms->pause, forms->resume, threads->restoreहाँकिसी नामित स्थिति का शुद्ध सेट।
threads->update, threads->trashहाँलेबल का सेट। उसे दो बार लगाना एक बार लगाना ही है।
threads->snooze, threads->unsnoozeहाँजागने का क्षण body में होता है, आगमन के समय से नहीं निकाला जाता।
emails->update, labels->update, webhooks->update, settings->update, roles->update, members->update, domains->update, domains->updateAddress, domains->updateAddressForward, contacts->update, audiences->update, keys->update, forms->update, branding->update, threads->updateNote, chats->rename, account->setEmailNotification, account->setPushMuted, appHost->set, workspaces->setActiveहाँनामित फ़ील्ड का शुद्ध सेट।
members->grantAddress, members->grantDomain, rules->reorder, threads->reorderNotesहाँgrant एक upsert है, और क्रम पूरा का पूरा बताया जाता है।
templates->publish, forms->publish, imports->startहाँपहले से प्रकाशित चीज़ को प्रकाशित करने पर, या पहले से शुरू हो चुके import को शुरू करने पर, वह अपरिवर्तित लौटता है।
templates->preview, templates->render, broadcasts->preview, rules->testहाँये render करते हैं, गिनते हैं या मूल्यांकन करते हैं, लिखते कुछ नहीं।
domains->verify, appHost->verify, senders->researchहाँदोहराई गई जाँच उसके किए जाने के समय के सिवा कुछ नहीं बदलती।
contacts->save, contacts->setAudiences, contacts->removePhoto, contacts->block, contacts->unblock, contacts->deleteMany, keys->revoke, files->revokeLink, files->revokeAllLinks, appHost->delete, account->removePhoto, branding->removeImage, domains->removeLogo, domains->removeLogoCertificate, domains->removeAddressPhoto, account->acceptInvitation, account->declineInvitation, forms->approveSubmission, subscriptions->moveहाँहर एक अंतिम परिणाम बताता है, इसलिए दूसरा कॉल वही छोड़ता है जो पहले ने छोड़ा था।
audiences->addContact, audiences->addContacts, audiences->removeContacts, audiences->importContacts, suppressions->add, domains->createAddressहाँदोहराव पहले कॉल का काम पहले से हुआ पाता है और उसे दो बार करने के बजाय उसकी सूचना देता है।
contacts->setPhoto, account->setPhoto, branding->uploadImage, domains->setLogo, domains->setLogoCertificate, domains->setAddressPhoto, imports->uploadChunkहाँदोबारा भेजे गए बाइट्स वह बदल देते हैं जो पहली कोशिश ने संग्रहीत किया था।
drafts->create, labels->create, webhooks->create, templates->create, rules->create, roles->create, tempMail->create, files->uploadनहींretry दो object छोड़ जाता है।
drafts->updateनहींजो id आपने भेजी थी उसे दोबारा इस्तेमाल करने के बजाय हर write के परिणाम से id पढ़ें।
drafts->delete, labels->delete, webhooks->delete, templates->delete, rules->delete, roles->delete, members->remove, members->revokeAddress, tempMail->delete, tempMail->deleteMessageनहींरिस्पॉन्स खो जाने के बाद किया गया retry उस काम को विफल बताता है जो सफल हो चुका था।
webhooks->rotateSecretनहींदूसरा rotation उस secret को रद्द कर देता है जो पहली कोशिश ने लौटाया था।
webhooks->testनहींयह दूसरी बनावटी delivery भेज देता।
webhooks->replayDeliveryनहींयह event को आपके receiver को दूसरी बार भेज देता।
emails->translate, emails->compose, emails->rewrite, emails->suggestSubjectनहींहर एक मॉडल कॉल ख़र्च करता है, इसलिए बिना जवाब वाली रिक्वेस्ट के बाद किया गया पुनः प्रयास वही जवाब दो बार ख़रीदता है।
security->beginStepUp, security->verifyStepUpनहींपुनः प्रयास दूसरा ईमेल भेज सकता है या कोड पर दूसरी कोशिश ख़र्च कर सकता है।
हर दूसरी कॉल जो GET नहीं हैनहींएक ही बार भेजा जाता है, और विफलता दोहराई नहीं बल्कि बताई जाती है।

बैकऑफ़

  • क्लाइंट पर maxRetries: से सीमित, डिफ़ॉल्ट रूप से दो अतिरिक्त प्रयास। maxRetries: 0 पुनः प्रयास बंद कर देता है।
  • केवल नेटवर्क विफलता या 408, 500, 502, 503 या 504 के बाद। 429 तभी retry होता है जब वह Retry-After लिए आए, और यह API उसे नहीं भेजता, इसलिए rate limit सीधे throw करता है। कोई भी दूसरा status तुरंत throw करता है।
  • आधे सेकंड से आठ सेकंड तक घातांकी, jitter के साथ: हर इंतज़ार उस ऊपरी सीमा के आधे और पूरे के बीच का कोई रैंडम बिंदु होता है, ताकि बहाली के समय क्लाइंटों का पूरा बेड़ा फिर से एक साथ न चल पड़े।
  • Retry-After की गति से, उसके दोनों रूपों में: delay-seconds और HTTP-date। जब सर्वर प्रतीक्षा बताता है, तो क्लाइंट backoff करने के बजाय ठीक उतनी ही देर रुकता है।
  • एक मिनट से ज़्यादा माँगने वाले सर्वर को क्लाइंट से सोने को नहीं, रुक जाने को कहना माना जाता है, इसलिए exception retryAfterSeconds के साथ throw होता है। उसके माँगे से जल्दी लौटना उसका पालन नहीं है।
  • टाइमआउट भी किसी दूसरी नेटवर्क विफलता जैसा ही है, इसलिए दोहराने में सुरक्षित कॉल उसके बाद फिर आज़माई जाती है, और timeout: हर प्रयास पर नए सिरे से लागू होता है।
  • ये इंतज़ार कॉल के अंदर sleep और usleep कॉल होते हैं, इसलिए स्क्रिप्ट भी इंतज़ार करती है, और कॉल तभी लौटती है या throw करती है जब उसका आख़िरी प्रयास ख़त्म हो जाए। जिस वेब रिक्वेस्ट पर कोई व्यक्ति इंतज़ार कर रहा हो, उसमें timeout: और maxRetries: कम रखें।