# Runbook लिखना

आप किसी Runbook को उसके **चरण** पेज पर चरणों की क्रमबद्ध सूची के रूप में लिखते हैं। यह पेज बताता है कि Runbook कैसे बनाएँ, सात तरह के चरणों में से हर एक को कैसे सेट करें, और विफलताएँ व अनुमोदन किसी रन की दिशा कैसे बदलते हैं।

:::cards
- [Runbook बनाना](#runbook-बनाना): खाली Runbook से सहेजे गए चरणों तक।
- [चरण के प्रकार](#चरण-के-प्रकार): Manual, JavaScript, HTTP request, Bash, SSH, kubectl और AI।
- [विफलता प्रबंधन और अनुमोदन](#विफलता-प्रबंधन-और-अनुमोदन): जब कोई चरण विफल होता है या अनुमोदन की प्रतीक्षा करता है तो क्या होता है।
- [एक पूरा उदाहरण](#एक-पूरा-उदाहरण): पाँच चरणों में डेटाबेस फ़ेलओवर।
:::

## शुरू करने से पहले

- **Runbook लिखने वाली भूमिका।** Project Owner, Project Admin और Runbook Admin Runbook बनाते हैं और उनके चरण सहेजते हैं। विस्तृत अनुमतियों के साथ आपको **Create Runbook** और **Edit Runbook** चाहिए। [अनुमतियाँ](/docs/runbooks/configuration#अनुमतियाँ) देखें।
- **Bash, SSH और kubectl चरणों के लिए एक Runner।** ये चरण आपके अपने इंफ्रास्ट्रक्चर में एक [Runner](/docs/runbooks/agents) पर चलते हैं, कभी Status200 Worker पर नहीं। पहले एक इंस्टॉल करें। जो चरण कोई Runner नहीं चुनता, वह [प्रोजेक्ट के डिफ़ॉल्ट Runner](/docs/runbooks/agents#प्रोजेक्ट-का-डिफ़ॉल्ट-runner) पर चलता है, अगर आपने कोई सेट किया है; वरना JavaScript चरण एक [ग्लोबल Runner](/docs/runbooks/agents#ग्लोबल-runner) पर चलता है।
- **SSH और kubectl चरणों के लिए एक सीक्रेट वेरिएबल।** जिस कुंजी, पासवर्ड या kubeconfig से कोई चरण साइन इन करता है, वह एक सीक्रेट [runbook वेरिएबल](/docs/runbooks/variables) है। वेरिएबल Project Owner और Project Admin बनाते हैं, और Runbook Admin अपने लिखे चरणों में उन्हें चुनता है। kubectl चरण इसके बजाय Runner की अपनी एक्सेस इस्तेमाल कर सकता है।
- **AI चरणों के लिए एक LLM प्रदाता।** [LLM प्रदाता](/docs/ai/llm-provider) देखें।

## Runbook बनाना

:::steps
### रनबुक खोलें

**उत्पाद → रनबुक** खोलें। Runbook **डैशबोर्ड और ऑटोमेशन** समूह में हैं।

### नया Runbook बनाएँ

**Runbook बनाएँ** पर क्लिक करें, एक **नाम** और चाहें तो Runbook किस काम के लिए है इसका **विवरण** दर्ज करें। **और फ़ील्ड** के नीचे **सक्षम** स्विच है, जो डिफ़ॉल्ट रूप से चालू होता है, और **लेबल** हैं। नया Runbook अपने **चरण** पेज पर खुलता है।

### चरण जोड़ें

**Start your runbook** के नीचे पहले चरण का प्रकार चुनें; आख़िरी चरण के नीचे **Add another step** वही सात प्रकार देता है। हर चरण अपने **शीर्षक** और अपने प्रकार की ज़रूरत की चीज़ों के साथ खुलता है; बाक़ी, जैसे उसका **विवरण** और टाइमआउट, **और फ़ील्ड** के नीचे समेटा रहता है। जब Runbook में एक चरण हो जाता है, तो कार्ड के ऊपर **चरण जोड़ें** एक Manual चरण जोड़ता है।

### चरणों को क्रम में रखें

चरण **क्रम से** चलते हैं। क्रम बदलने के लिए किसी चरण को उसके हेडर के बाईं ओर के हैंडल से खींचें; कीबोर्ड से हैंडल पर फ़ोकस करें, Space दबाएँ, ऐरो कुंजियों से चरण को खिसकाएँ और फिर Space दबाएँ।

### चरण सहेजें

**Save Steps** पर क्लिक करें। तब तक एडिटर **सहेजे नहीं गए बदलाव** दिखाता है। सहेजने के बाद आपको **सहेजा गया** दिखता है और Runbook [चलाने](/docs/runbooks/running) के लिए तैयार है।
:::

## चरण की बनावट

हर चरण में ये फ़ील्ड होते हैं। स्वचालित चरण अपना **शीर्षक** और अपने प्रकार की सेटिंग्स दिखाता है, और बाक़ी को **और फ़ील्ड** के नीचे समेट देता है, जो बताता है कि उनमें से क्या सेट है:

| फ़ील्ड | उद्देश्य |
| --- | --- |
| **शीर्षक** | एक छोटा लेबल, जो चरणों की सूची और हर रन में दिखता है। |
| **विवरण** | प्रतिक्रिया देने वाले के लिए वैकल्पिक संदर्भ, Markdown में, **और फ़ील्ड** के नीचे। Manual चरण पर यही वे **निर्देश** हैं जिन्हें व्यक्ति पढ़ता और मानता है, और ये शीर्षक के नीचे दिखते हैं। |
| **विफलता पर जारी रखें** | केवल स्वचालित चरण। चालू होने पर, विफल चरण रन को नहीं रोकता: अगला चरण फिर भी चलता है। |
| **अनुमोदन आवश्यक करें** | केवल स्वचालित चरण। चालू होने पर, रन इस चरण से पहले तब तक रुका रहता है जब तक कोई इसे अनुमोदित न करे, और उसके बाद ही इसे चलाता है। स्विच का नाम **यह चरण चलाने से पहले अनुमोदन आवश्यक करें** है, और चरण के हेडर में **अनुमोदन आवश्यक** दिखता है। |
| प्रकार के अनुसार सेटिंग्स | स्क्रिप्ट, URL, Runner, सीक्रेट वेरिएबल या प्रॉम्प्ट। [चरण के प्रकार](#चरण-के-प्रकार) देखें। |

## चरण के प्रकार

| प्रकार | कहाँ चलता है | क्या चाहिए |
| --- | --- | --- |
| [Manual](#manual) | एक व्यक्ति | कुछ नहीं |
| [JavaScript](#javascript) | एक Runner | एक Runner |
| [HTTP request](#http-request) | Status200 Worker | कुछ नहीं |
| [Bash](#bash) | एक Runner | एक Runner |
| [SSH](#ssh) | एक Runner | एक Runner और साइन इन के लिए एक सीक्रेट वेरिएबल |
| [kubectl](#kubectl) | एक Runner | एक Runner, और एक kubeconfig वेरिएबल या Runner की अपनी एक्सेस |
| [AI](#ai) | Status200 Worker | एक LLM प्रदाता |

नीचे के हर स्वचालित चरण में, चरण के **और फ़ील्ड** में सबसे पहले उसका **Runner** है, Runner पर चलने वाले चरण के लिए, फिर **अनुमोदन आवश्यक करें** और **विफलता पर जारी रखें** हैं, फिर चरण की अपनी सेटिंग्स - HTTP request चरण के हेडर, SSH चरण का पोर्ट और की पासफ़्रेज़, AI चरण का प्रदाता और संदर्भ स्विच - और आख़िर में **विवरण** और टाइमआउट। मुड़ा हुआ होने पर यह चरण के Runner का नाम बताता है, ताकि आप चरण खोले बिना देख सकें कि वह कहाँ चलता है।

### Manual

किसी व्यक्ति के लिए चेकलिस्ट का एक आइटम: इसके **निर्देश** बताते हैं कि क्या करना या जाँचना है। Manual चरण पर पहुँचकर रन रुक जाता है और `WaitingForManualStep` (**आपकी प्रतीक्षा में**) में तब तक रहता है जब तक कोई **पूरा चिह्नित करें** या **छोड़ें** पर क्लिक न करे। किसी व्यक्ति की प्रतीक्षा कर रहा रन कभी टाइमआउट नहीं होता। Manual चरण में अनुमोदन स्विच नहीं होता: वह पहले से ही किसी व्यक्ति के लिए रन रोकता है।

इसका इस्तेमाल उन कामों के लिए करें जिन्हें केवल इंसान जाँच या कर सकता है: "लोड बैलेंसर डैशबोर्ड में पुष्टि करें कि ट्रैफ़िक सेकेंडरी रीजन पर चला गया है।"

### JavaScript

JavaScript का एक स्निपेट, जो Status200 Worker पर नहीं, बल्कि एक [Runbook एजेंट](/docs/runbooks/agents) पर `isolated-vm` सैंडबॉक्स में चलता है: आपके किसी Runner पर, या चरण कोई न चुने तो एक [ग्लोबल Runner](/docs/runbooks/agents#ग्लोबल-runner) पर।

| फ़ील्ड | यह क्या करता है | डिफ़ॉल्ट |
| --- | --- | --- |
| **Runner** | **और फ़ील्ड** में। वह Runner जो चरण चलाता है: **ग्लोबल Runner**, या आपका कोई Runner। केवल आपका चुना हुआ Runner जॉब क्लेम कर सकता है; **ग्लोबल Runner** वाले चरण को कोई भी ग्लोबल Runner क्लेम कर सकता है। | [प्रोजेक्ट का डिफ़ॉल्ट Runner](/docs/runbooks/agents#प्रोजेक्ट-का-डिफ़ॉल्ट-runner), अगर आपने कोई सेट किया है; वरना **ग्लोबल Runner**, जब कोई हो |
| **Script** | चलाने के लिए JavaScript। किसी मान को दर्ज करने के लिए उसे `return` करें; `console.log` की हर पंक्ति भी दर्ज होती है। थ्रो की गई त्रुटि चरण को विफल कर देती है। | — |
| **निष्पादन टाइमआउट** | सैंडबॉक्स हटाने से पहले Runner स्निपेट को कितनी देर चलने देता है। ग्लोबल Runner उसे अधिक से अधिक 5 मिनट चलने देता है। | 30 सेकंड |
| **उठाने का टाइमआउट** | Worker कितनी देर तक Runner के जॉब क्लेम करने की प्रतीक्षा करता है। | 2 मिनट |

```javascript
const start = Date.now();
// ... your logic ...
console.log("replica lag checked");
return { durationMs: Date.now() - start };
```

सैंडबॉक्स में 128 MB मेमोरी है और फ़ाइल सिस्टम या प्रोसेस तक कोई पहुँच नहीं है। यह `axios` से HTTP अनुरोध भेज सकता है, लेकिन केवल सार्वजनिक पतों पर: किसी निजी नेटवर्क, Runner के अपने होस्ट या क्लाउड मेटाडेटा एंडपॉइंट पर अनुरोध अस्वीकार कर दिया जाता है। अपने नेटवर्क की किसी सेवा तक पहुँचने के लिए `curl` वाले [Bash](#bash) चरण का इस्तेमाल करें।

### HTTP request

Status200 Worker द्वारा किया गया एक आउटबाउंड HTTP कॉल। किसी Runner की ज़रूरत नहीं।

| फ़ील्ड | यह क्या करता है | डिफ़ॉल्ट |
| --- | --- | --- |
| **Method** | `GET`, `POST`, `PUT`, `PATCH`, `DELETE` या `HEAD`। | `GET` |
| **URL** | कॉल करने वाला एंडपॉइंट। | ख़ाली |
| **Headers (JSON)** | **और फ़ील्ड** के नीचे। एक JSON ऑब्जेक्ट, जैसे `{ "Authorization": "Bearer ..." }`। जो हेडर मान्य JSON नहीं हैं, वे चरण को विफल कर देते हैं। | कोई नहीं |
| **Body** | `POST`, `PUT`, `PATCH` और `DELETE` के लिए दिखता है। JSON के रूप में पार्स हो सके तो JSON के रूप में भेजा जाता है, नहीं तो टेक्स्ट के रूप में। | कोई नहीं |
| **Request timeout** | चरण विफल होने से पहले एंडपॉइंट के जवाब की कितनी देर प्रतीक्षा करनी है। | 30 सेकंड |

चरण `2xx` या `3xx` जवाब पर सफल होता है और बाक़ी किसी भी जवाब पर `HTTP <status>` त्रुटि के साथ विफल होता है। रीडायरेक्ट फ़ॉलो नहीं किए जाते। जवाब की स्थिति, हेडर और बॉडी 50 KB तक दर्ज होते हैं।

> [!NOTE]
> Worker कभी लूपबैक या लिंक-लोकल पतों को कॉल नहीं करता, जैसे क्लाउड मेटाडेटा एंडपॉइंट। Status200 Cloud पर यह केवल सार्वजनिक पतों को कॉल करता है। सेल्फ़-होस्टेड Status200 निजी नेटवर्क तक भी पहुँचता है, जब तक `DATA_SOURCE_BLOCK_PRIVATE_ADDRESSES` का मान `true` न हो। Status200 Cloud से अपने नेटवर्क की किसी सेवा को कॉल करने के लिए `curl` वाले [Bash](#bash) चरण का इस्तेमाल करें।

इसके लिए उपयोगी: PagerDuty घटना खोलना, Slack webhook पर पोस्ट करना, अपने क्लाउड प्रदाता या अपने सार्वजनिक API को कॉल करना।

### Bash

एक bash स्क्रिप्ट, जो आपके अपने इंफ्रास्ट्रक्चर में एक [Runbook एजेंट](/docs/runbooks/agents) पर `bash -c <script>` से चलती है। Bash कभी Status200 Worker पर नहीं चलता।

| फ़ील्ड | यह क्या करता है | डिफ़ॉल्ट |
| --- | --- | --- |
| **Runner** | **और फ़ील्ड** में। वह Runner जो चरण चलाता है। केवल वही Runner जॉब क्लेम कर सकता है। ग्लोबल Runner सिर्फ़ JavaScript चरण चलाते हैं। | प्रोजेक्ट का डिफ़ॉल्ट Runner, अगर आपने कोई सेट किया है |
| **Bash स्क्रिप्ट** | स्क्रिप्ट। आउटपुट (stdout और stderr) 50 KB तक दर्ज होता है, और शून्य के अलावा कोई भी एग्ज़िट कोड चरण को विफल कर देता है। | — |
| **निष्पादन टाइमआउट** | `SIGKILL` से रोकने से पहले Runner स्क्रिप्ट को कितनी देर चलने देता है। जिन चरणों को वाजिब तौर पर मिनट लगते हैं, उनके लिए इसे बढ़ाएँ। | 30 सेकंड |
| **उठाने का टाइमआउट** | Worker कितनी देर तक Runner के जॉब क्लेम करने की प्रतीक्षा करता है। | 2 मिनट |

स्क्रिप्ट Runner के कंटेनर में चलती है, उन टूल के साथ जो उसकी इमेज में आते हैं, जैसे `curl`, `wget` और `ssh` क्लाइंट, और उस होस्ट की नेटवर्क पहुँच के साथ जिस पर वह चल रही है। उदाहरण के लिए, किसी ऐसी सेवा की जाँच करना जिस तक केवल आपका नेटवर्क पहुँच सकता है:

```bash
set -euo pipefail
HTTP_CODE=$(curl -s -o /tmp/resp.txt -w "%{http_code}" "http://payments.internal:8080/health")
echo "HTTP $HTTP_CODE"
cat /tmp/resp.txt
if [[ "$HTTP_CODE" != "200" ]]; then
  echo "Health check failed"
  exit 1
fi
```

अगर रन इस चरण तक पहुँचते समय चुना गया Runner ऑफ़लाइन है, तो चरण **claim timeout** (डिफ़ॉल्ट 2 मिनट) तक प्रतीक्षा करता है और फिर टाइमआउट से विफल हो जाता है। Bash चरण पर भरोसा करने से पहले **रनबुक → Runbook एजेंट** में एक एजेंट जोड़ें।

> [!TIP]
> पासवर्ड और टोकन को स्क्रिप्ट से बाहर रखें। उन्हें सीक्रेट [runbook वेरिएबल](/docs/runbooks/variables) के रूप में सहेजें और जहाँ मान जाना है वहाँ `{{global.variables.NAME}}` लिखें: Runner को मान भरी हुई स्क्रिप्ट मिलती है, और चरण के आउटपुट में उसकी जगह `[REDACTED]` दिखता है।

### SSH

SSH से किसी मशीन पर साइन इन करें और वहाँ एक bash स्क्रिप्ट चलाएँ। कनेक्शन Runner खोलता है, इसलिए मशीन तक सिर्फ़ Runner से पहुँचा जा सकना काफ़ी है, और जिस कुंजी या पासवर्ड से चरण साइन इन करता है वह एक सीक्रेट [runbook वेरिएबल](/docs/runbooks/variables) है, जो चरण में कभी नहीं लिखा जाता।

| फ़ील्ड | यह क्या करता है |
| --- | --- |
| **Runner** | **और फ़ील्ड** में। वह Runner जो कनेक्शन खोलता है। उसे नेटवर्क पर मशीन तक पहुँचना चाहिए। जो चरण कोई Runner नहीं चुनता, वह प्रोजेक्ट के डिफ़ॉल्ट Runner पर चलता है। |
| **SSH किस पर** | उपयोगकर्ता और मशीन, जैसे आप उन्हें `ssh` के बाद लिखते: `deploy@10.0.4.21`। |
| **इससे साइन इन करें** | निजी कुंजी या पासवर्ड वाला सीक्रेट वेरिएबल; मान ही बताता है कि वह कौन-सा है। केवल सीक्रेट वेरिएबल दिखाए जाते हैं, और जब चरण का Runner चुना गया वेरिएबल इस्तेमाल नहीं कर सकता तो चरण बताता है। |
| **Bash स्क्रिप्ट** | मशीन पर उस उपयोगकर्ता के रूप में `bash` से चलती है जिससे चरण साइन इन करता है। आउटपुट 50 KB तक दर्ज होता है, और शून्य के अलावा कोई भी एग्ज़िट कोड चरण को विफल कर देता है। |
| **पोर्ट** | **और फ़ील्ड** के नीचे। खाली छोड़ने पर 22। |
| **की पासफ़्रेज़** | **और फ़ील्ड** के नीचे। पासफ़्रेज़ वाली कुंजी का पासफ़्रेज़ रखने वाला सीक्रेट वेरिएबल। |
| **निष्पादन टाइमआउट** | कनेक्ट करना, साइन इन करना और स्क्रिप्ट चलाना साथ मिलाकर गिना जाता है, ताकि अटकी हुई स्क्रिप्ट चरण को खुला न रख सके। डिफ़ॉल्ट 30 सेकंड। |
| **उठाने का टाइमआउट** | Worker कितनी देर तक Runner के जॉब क्लेम करने की प्रतीक्षा करता है। डिफ़ॉल्ट 2 मिनट। |

उदाहरण के लिए, किसी सेवा को रीस्टार्ट करने और यह दिखाने के लिए कि वह फिर से चल रही है:

```bash
sudo systemctl restart nginx
systemctl status nginx --no-pager
```

### kubectl

किसी क्लस्टर पर kubectl कमांड चलाएँ। स्क्रिप्ट Runner पर bash से चलती है, जिसमें `kubectl` शामिल है, और `KUBECONFIG` क्लस्टर की ओर इशारा करता है: कोई भी kubectl कमांड काम करता है, और उसके आसपास का कोई भी bash भी।

| फ़ील्ड | यह क्या करता है |
| --- | --- |
| **Runner** | **और फ़ील्ड** में। वह Runner जो kubectl चलाता है। उसे क्लस्टर के API सर्वर तक पहुँचना चाहिए। जो चरण कोई Runner नहीं चुनता, वह प्रोजेक्ट के डिफ़ॉल्ट Runner पर चलता है। |
| **Kubeconfig** | क्लस्टर के kubeconfig वाला सीक्रेट वेरिएबल, या **Runner की अपनी एक्सेस**: Runner का अपना kubeconfig, या क्लस्टर में चलने पर उसका सर्विस अकाउंट। Runner kubeconfig को ऐसी फ़ाइल में लिखता है जिसे केवल वही पढ़ सकता है, और स्क्रिप्ट ख़त्म होने पर उसे हटा देता है। |
| **Script** | kubectl कमांड। आउटपुट 50 KB तक दर्ज होता है, और शून्य के अलावा कोई भी एग्ज़िट कोड चरण को विफल कर देता है। |
| **निष्पादन टाइमआउट** | Runner स्क्रिप्ट को `SIGKILL` से रोकने से पहले कितनी देर चलने देता है। डिफ़ॉल्ट 30 सेकंड। |
| **उठाने का टाइमआउट** | Worker कितनी देर तक Runner के जॉब क्लेम करने की प्रतीक्षा करता है। डिफ़ॉल्ट 2 मिनट। |

उदाहरण के लिए, किसी deployment को रीस्टार्ट करने और उसके नए पॉड तैयार होने तक इंतज़ार करने के लिए:

```bash
kubectl rollout restart deployment/checkout-api --namespace checkout
kubectl rollout status deployment/checkout-api --namespace checkout --timeout=120s
```

हर स्क्रिप्ट के नीचे **उदाहरण — डालने के लिए क्लिक करें** ऐसी आम स्क्रिप्ट भर देता है। kubeconfig के उपयोगकर्ता को केवल वही दें जो आपकी स्क्रिप्ट करती हैं: उन namespace में एक Role जहाँ वे काम करती हैं, उन verb के साथ जिन्हें वे इस्तेमाल करती हैं। अगर API सर्वर कोई कमांड अस्वीकार करता है, तो kubectl का अपना संदेश चरण के आउटपुट में होता है, इसलिए अनुमति की विफलता बताती है कि कौन-सा role binding बढ़ाना है।

### AI

रन के बीच में AI से विश्लेषण, सारांश या निर्णय माँगें। जवाब निष्पादन पर उस चरण का आउटपुट बन जाता है। AI चरण Status200 Worker पर चलते हैं; किसी Runner की ज़रूरत नहीं।

| फ़ील्ड | यह क्या करता है |
| --- | --- |
| **Prompt** | AI को क्या करना है। उदाहरण: "पिछले चरणों का आउटपुट देखें और बताएँ कि सुधार जारी रखना सुरक्षित है या नहीं।" |
| **LLM provider** | वैकल्पिक। **प्रोजेक्ट डिफ़ॉल्ट** प्रोजेक्ट का डिफ़ॉल्ट प्रदाता इस्तेमाल करता है। जब चरण को कोई ख़ास मॉडल चाहिए, जैसे ऐसे डेटा के लिए सेल्फ़-होस्टेड मॉडल जिसे आपके नेटवर्क से बाहर नहीं जाना चाहिए, तो एक प्रदाता तय करें। [LLM प्रदाता](/docs/ai/llm-provider) देखें। |
| **Include previous step context** | चालू होने पर, AI इस चरण से पहले चले सभी चरणों के बारे में सब कुछ देखता है: शीर्षक, प्रकार, स्थिति, आउटपुट और त्रुटि संदेश। उसे हर चरण के आउटपुट के 4,000 अक्षर तक मिलते हैं। |
| **Include trigger context** | चालू होने पर, AI देखता है कि रन किसने शुरू किया: जुड़ी हुई घटना, अलर्ट या अनुसूचित रखरखाव इवेंट (विवरण, गंभीरता, मौजूदा स्थिति, प्रभावित मॉनिटर, मूल कारण, स्थिति टाइमलाइन और सार्वजनिक नोट), या वह व्यक्ति जिसने Runbook को मैन्युअल रूप से चलाया। |

किसी इंसान को प्रक्रिया में बनाए रखने के लिए, AI चरण के बाद वाले चरण पर **अनुमोदन आवश्यक करें** चालू करें: AI विश्लेषण करता है, एक व्यक्ति उसका जवाब पढ़ता है, और सुधार वाला चरण तभी चलता है जब वह व्यक्ति उसे अनुमोदित करे।

**AI क्या कभी नहीं देखता।** AI चरण का जवाब निष्पादन पर चरण के आउटपुट के रूप में सहेजा जाता है, और निष्पादन को Runbook पढ़ने की अनुमति वाला कोई भी व्यक्ति पढ़ सकता है, जो घटना देखने वालों से बड़ा समूह है। इसलिए ट्रिगर संदर्भ में **निजी आंतरिक नोट** और **Slack और Microsoft Teams के चैनल संदेश** शामिल नहीं होते। पिछले चरणों के आउटपुट को सीक्रेट (टोकन, की, क्रेडेंशियल) के लिए स्कैन किया जाता है, और मॉडल को भेजने से पहले उन्हें छिपा दिया जाता है। एम्बेड की गई इमेज और लंबा एन्कोडेड डेटा, जैसे किसी घटना के विवरण में चिपकाया गया स्क्रीनशॉट, भी छोड़ दिया जाता है और उसकी जगह एक छोटा नोट रहता है।

AI चरणों को किसी भी दूसरी AI सुविधा की तरह मापा और बिल किया जाता है। चरण कारण बताने वाले संदेश के साथ विफल होता है जब उसका कोई प्रॉम्प्ट न हो, प्रोजेक्ट के लिए AI सुविधाएँ बंद हों, कोई LLM प्रदाता उपलब्ध न हो, या तय किया गया प्रदाता अब प्रोजेक्ट के लिए उपलब्ध न हो। अगर बाक़ी Runbook फिर भी चलना चाहिए, तो **विफलता पर जारी रखें** चालू करें।

## विफलता प्रबंधन और अनुमोदन

```mermaid title="किसी स्वचालित चरण पर क्या होता है"
flowchart TB
    reach["रन किसी स्वचालित<br/>चरण पर पहुँचता है"] --> approval{"अनुमोदन आवश्यक<br/>करें चालू है?"}
    approval -->|"हाँ"| wait["रन किसी व्यक्ति के अनुमोदन<br/>की प्रतीक्षा करता है"]
    wait -->|"अनुमोदित"| run["चरण चलता है"]
    approval -->|"नहीं"| run
    wait -->|"छोड़ा गया"| next["अगला चरण"]
    run --> ok{"सफल हुआ?"}
    ok -->|"हाँ"| next
    ok -->|"नहीं"| cont{"विफलता पर जारी<br/>रखें चालू है?"}
    cont -->|"हाँ"| next
    cont -->|"नहीं"| failed["रन विफल होकर रुक जाता है"]
```

डिफ़ॉल्ट रूप से विफल चरण रन को रोक देता है और निष्पादन को `Failed` के रूप में चिह्नित करता है, चरण की त्रुटि को कारण बनाकर। **विफलता पर जारी रखें** चालू होने पर विफलता दर्ज होती है और अगला चरण चलता है, जो "ये तीन चीज़ें आज़माओ, फिर सूचना दो" जैसे Runbook के लिए ठीक है।

**अनुमोदन आवश्यक करें** किसी चरण के चलने से पहले लागू होता है, चाहे उससे पहले कुछ भी हुआ हो: रन तब तक रुकता है जब तक कोई **अनुमोदित करें और चलाएँ** पर क्लिक न करे, और तब चरण चलता है, या **छोड़ें** पर, और तब वह कभी नहीं चलता। इसे उस चरण के लिए चालू करें जो कुछ बदलता है - रीस्टार्ट, फ़ेलओवर, स्केल-डाउन - ताकि कोई व्यक्ति पहले देख ले कि उससे पहले के चरणों ने क्या पाया। अनुमोदन चरण का होता है, इसलिए चरण को खिसकाने पर वह भी साथ खिसकता है।

:::note
API और Terraform में यह स्विच चरण का `requireApprovalBeforeRunning` है। चरण का `requireApproval`, जिसे Runbook अनुमोदनों के उनके द्वारा सुरक्षित चरण पर जाने से पहले लिखते थे, अब भी काम करता है और उसका अर्थ वही है: उस चरण के बाद अनुमोदन। Status200 इसे अगले चरण से पहले के अनुमोदन के रूप में पढ़ता है, या, अंतिम चरण के बाद होने पर, अंत में **Approve the result** नाम वाले Manual चरण के रूप में।
:::

## सहेजना और संपादित करना

चरणों में बदलाव तब लागू होते हैं जब आप **Save Steps** पर क्लिक करते हैं। हर रन उस स्नैपशॉट से काम करता है जो उसके शुरू होने पर लिया गया था, इसलिए चल रहे निष्पादन अपने शुरुआती चरण ही रखते हैं, और संपादन कभी पिछले रन का इतिहास नहीं बदलता।

## एक पूरा उदाहरण

"DB primary unreachable" के लिए एक Runbook:

| # | प्रकार | यह क्या करता है |
| --- | --- | --- |
| 1 | JavaScript | आपकी कॉन्फ़िगरेशन सेवा से मौजूदा प्राइमरी होस्ट लाएँ और उसे लॉग करें। |
| 2 | Manual | "पुष्टि करें कि सेकेंडरी पर रेप्लिकेशन लैग 5 सेकंड से कम है।" |
| 3 | HTTP request | आपके फ़ेलओवर ऑर्केस्ट्रेटर API को `POST`। |
| 4 | Manual | "जाँचें कि राइट अब नए प्राइमरी पर जा रहे हैं।" |
| 5 | HTTP request | Slack webhook पर ऑल-क्लियर संदेश का `POST`। |

प्रतिक्रिया देने वाला चरण 1 को चलते देखता है, चरण 2 पर टिक करता है, चरण 3 को चलते देखता है, चरण 4 पर टिक करता है, और रन चरण 5 के साथ ख़त्म होता है। हर चरण का आउटपुट पोस्टमॉर्टम के लिए दर्ज होता है।

## अगले कदम

:::cards
- [Runbook चलाना](/docs/runbooks/running): एक रन शुरू करें, और उसके चरण पूरे करें, अनुमोदित करें या छोड़ें।
- [Runbook नियम](/docs/runbooks/rules): मेल खाने वाली घटनाओं पर इस Runbook को अपने-आप शुरू करें।
- [Runbook एजेंट](/docs/runbooks/agents): वह Runner इंस्टॉल करें जिसकी आपके स्क्रिप्ट चरणों को ज़रूरत है।
- [Runbook वेरिएबल](/docs/runbooks/variables): होस्ट, कुंजियाँ, पासवर्ड और kubeconfig अपने चरणों से बाहर रखें।
:::
