वेबहुक
वेबहुक आपके सिस्टम को बताता है कि रिपॉज़िटरी में कुछ बदला है, ताकि उसे बार-बार पूछना न पड़े। Arkvory worker रिपॉज़िटरी की परिवर्तन फ़ीड की हर घटना के लिए आपके URL पर HTTP POST भेजता है। इसका उपयोग बिल्ड प्रकाशित होने पर डिप्लॉयमेंट शुरू करने, या किसी पथ का नया संस्करण आने पर कैश ताज़ा करने के लिए करें।
सब्सक्रिप्शन प्रशासक एक फ़ाइल में तय करता है। उनके लिए अभी कोई API या कंसोल पेज नहीं है। आप फ़ीड खुद भी पढ़ सकते हैं: GET /api/v1/repositories/<repository>/changes।
डिलीवरी कैसे काम करती है
- एक सब्सक्रिप्शन एक रिपॉज़िटरी को फ़ॉलो करता है और एक URL पर भेजता है।
- घटनाएँ क्रम से, एक-एक करके आती हैं। अगली घटना तब तक रुकती है जब तक रिसीवर
2xxस्थिति से उत्तर न दे। - डिलीवरी कम से कम एक बार होती है। क्रैश या खोए उत्तर के बाद वही घटना दोबारा आ सकती है। हर घटना का एक स्थिर
idहोता है: उसी से डुप्लिकेट हटाएँ। - नया सब्सक्रिप्शन केवल नई घटनाएँ पाता है। उसके बनने से पहले की घटनाएँ नहीं भेजी जातीं।
- बंद रिसीवर केवल अपने सब्सक्रिप्शन को देर करता है। घटना प्रतीक्षा करती है। Arkvory 12 सेकंड बाद फिर कोशिश करता है, ठहराव को एक घंटे तक दोगुना करता है और रिसीवर के फिर उत्तर देने पर घटनाएँ क्रम से भेजता है। अपलोड और डाउनलोड कभी वेबहुक का इंतज़ार नहीं करते।
सब्सक्रिप्शन सेट करें
आपको सर्वर की फ़ाइलों तक पहुँच और worker को पुनः आरंभ करने का अधिकार चाहिए। देखें कॉन्फ़िगरेशन।
- हस्ताक्षर सीक्रेट वाली एक फ़ाइल बनाएँ: कम से कम 16 यादृच्छिक प्रिंट होने योग्य वर्ण, उदाहरण के लिए
/root/ci.secret। रिसीवर को वही सीक्रेट चाहिए। - सब्सक्रिप्शन के साथ
configureचलाएँ। कमांड आपके इनपुट की जाँच करती है, सीक्रेट कोconfig/webhooksमें कॉपी करती है, सब्सक्रिप्शन फ़ाइल और सेटिंग लिखती है, सेवाएँ पुनः आरंभ करती है, और यदि वे तैयार न हों तो पिछला कॉन्फ़िगरेशन बहाल करती है। यह रिसीवर से संपर्क नहीं करती।
sudo arkvory configure --root /opt/proanima-arkvory \
--webhook ci --webhook-repository releases \
--webhook-url https://ci.example.com/hooks/arkvory \
--webhook-secret-file /root/ci.secret \
--webhook-actions artifact.publish- worker लॉग में
webhook.startedदेखें, एक फ़ाइल प्रकाशित करें और अपने रिसीवर को देखें।
कमांड config/webhooks/webhooks.json लिखती है; आप उसे हाथ से भी लिखकर ARKVORY_WEBHOOKS_FILE में दे सकते हैं। सब्सक्रिप्शन बदलने के लिए उसी नाम से कमांड फिर चलाएँ। --webhook-detach ci उसे हटाता है: उसकी फ़ाइलें मिट जाती हैं और उसकी स्थिति भुला दी जाती है। एक कॉल एक सब्सक्रिप्शन बदलती है और दूसरे configure विकल्पों के साथ नहीं मिलाई जा सकती।
फ़ाइल में ये फ़ील्ड हैं:
{
"webhooks": [
{
"id": "ci",
"repository": "releases",
"url": "https://ci.example.com/hooks/arkvory",
"secretFile": "/opt/proanima-arkvory/config/webhooks/ci.secret",
"actions": ["artifact.publish"]
}
]
}| फ़ील्ड | अर्थ |
|---|---|
id | सब्सक्रिप्शन का नाम: a-z, 0-9, _ और - के 1 से 64 वर्ण। उसकी प्रगति इसी नाम से रखी जाती है। |
repository | वह रिपॉज़िटरी जिसकी फ़ीड भेजी जाती है। |
url | रिसीवर। HTTPS, बिना उपयोगकर्ता नाम, query या fragment के, अधिकतम 2048 वर्ण। सादा HTTP केवल localhost, 127.0.0.1 और [::1] के लिए मान्य है। |
secretFile | हस्ताक्षर सीक्रेट वाली फ़ाइल का निरपेक्ष पथ। |
nextSecretFile | रोटेशन के लिए वैकल्पिक दूसरा सीक्रेट। |
actions | भेजी जाने वाली फ़ीड कार्रवाइयों की वैकल्पिक सूची, उदाहरण के लिए artifact.publish, artifact.delete, asset.replace, stage.added और package.register। इसके बिना सभी कार्रवाइयाँ भेजी जाती हैं। |
गलत फ़ाइल worker को शुरू होते समय worker.unavailable के साथ रोक देती है। अधिकतम 16 सब्सक्रिप्शन की अनुमति है। Compose इंस्टॉलेशन में कमांड config/webhooks को worker कंटेनर में माउंट भी करती है।
अनुरोध
| हेडर | मान |
|---|---|
Content-Type | application/json |
X-Arkvory-Delivery | घटना का id। घटना के हर दोहराव पर यह वही रहता है। |
X-Arkvory-Event | फ़ीड की कार्रवाई, उदाहरण के लिए artifact.publish। |
X-Arkvory-Timestamp | वह Unix समय (सेकंड में) जब अनुरोध पर हस्ताक्षर किया गया। |
X-Arkvory-Signature | sha256=<hex>। रोटेशन के दौरान अल्पविराम से अलग दो मान होते हैं। |
बॉडी JSON है:
{
"id": "releases:128",
"repository": "releases",
"sequence": "128",
"action": "artifact.publish",
"artifactId": "00000000-0000-4000-8000-000000000001",
"detail": null
}sequence फ़ीड में स्थिति है, एक दशमलव स्ट्रिंग। detail उन कार्रवाइयों के लिए फ़ाइल पथ या चरण है जिनमें वह होता है। बॉडी में लेखक, फ़ाइल सामग्री या मेटाडेटा नहीं होता: वर्तमान स्थिति API से artifactId द्वारा पढ़ें।
10 सेकंड के भीतर किसी भी 2xx स्थिति से उत्तर दें। 3xx (रीडायरेक्ट नहीं अपनाए जाते), 4xx, 5xx, कनेक्शन त्रुटि या टाइमआउट विफलता गिना जाता है। Arkvory उत्तर का अधिकतम 4 KiB पढ़ता है और उसे अनदेखा करता है।
हस्ताक्षर सत्यापित करें
हस्ताक्षर आपके सीक्रेट से <timestamp>.<body> टेक्स्ट पर HMAC-SHA256 है, जिसे sha256= और hex डाइजेस्ट के रूप में लिखा जाता है। किसी अनुरोध पर भरोसा करने से पहले इसे जाँचें:
- JSON पार्स करने से पहले कच्ची बॉडी पढ़ें।
- यदि टाइमस्टैम्प आपकी घड़ी से 5 मिनट से अधिक अलग हो तो अनुरोध अस्वीकार करें।
- हस्ताक्षर की गणना करें और उसे स्थिर-समय वाले फ़ंक्शन से तुलना करें। यदि हेडर में दो मान हों तो कोई भी स्वीकार करें।
Node.js:
import { createHmac, timingSafeEqual } from 'node:crypto';
export function verify(secret, headers, rawBody) {
const timestamp = headers['x-arkvory-timestamp'];
if (!/^\d{1,12}$/.test(timestamp ?? '')) return false;
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
const expected = Buffer.from(
'sha256=' + createHmac('sha256', secret).update(`${timestamp}.${rawBody}`).digest('hex'),
);
return String(headers['x-arkvory-signature'] ?? '')
.split(',')
.some((given) => {
const actual = Buffer.from(given.trim());
return actual.length === expected.length && timingSafeEqual(actual, expected);
});
}Python:
import hashlib, hmac, time
def verify(secret: bytes, headers, raw_body: bytes) -> bool:
timestamp = headers.get("X-Arkvory-Timestamp", "")
if not timestamp.isdigit() or abs(time.time() - int(timestamp)) > 300:
return False
digest = hmac.new(secret, timestamp.encode() + b"." + raw_body, hashlib.sha256).hexdigest()
expected = "sha256=" + digest
given = headers.get("X-Arkvory-Signature", "").split(",")
return any(hmac.compare_digest(part.strip(), expected) for part in given)दोहराई गई डिलीवरी संभालें
- संभाली गई हर घटना का
idसहेजें और दोहराव को अनदेखा करें। - जल्दी उत्तर दें: काम को कतार में डालें और
204लौटाएँ। धीमा रिसीवर अपने सब्सक्रिप्शन की बाद की सभी घटनाओं को देर करता है। - दोहराव का मतलब यह नहीं कि ऑपरेशन दो बार हुआ। घटना को संकेत मानें और वर्तमान स्थिति API से पढ़ें।
सीक्रेट बदलें
- वही कमांड फिर चलाएँ: वर्तमान सीक्रेट के लिए
--webhook-secret-fileऔर नए के लिए--webhook-next-secret-file। अब हर अनुरोध में दो हस्ताक्षर होते हैं। - रिसीवर को नए सीक्रेट पर ले जाएँ। दोनों में से कोई भी हस्ताक्षर स्वीकार करने वाला रिसीवर इस बीच चलता रहता है।
- कमांड फिर चलाएँ: नई सीक्रेट फ़ाइल को
--webhook-secret-fileमें दें और--webhook-next-secret-fileहटा दें।
निजी रिसीवर और प्रमाणपत्र
- Arkvory लूपबैक, निजी, लिंक-लोकल और क्लाउड मेटाडेटा पतों वाले रिसीवर, और उन पर हल होने वाले नामों को अस्वीकार करता है। इससे सर्वर का उपयोग आंतरिक सेवाओं तक पहुँचने के लिए नहीं हो सकता।
- अपने नेटवर्क के रिसीवर को भेजने के लिए
--webhook-allow-privateसे वह नेटवर्क जोड़ें, उदाहरण के लिए--webhook-allow-private 10.20.0.0/16(ARKVORY_WEBHOOKS_ALLOW_PRIVATE)। यह आख़िरी सब्सक्रिप्शन हटने तक बना रहता है। - यदि रिसीवर का प्रमाणपत्र आपके अपने प्राधिकरण से आता है, तो
--webhook-ca-fileसे उस प्राधिकरण वाली PEM फ़ाइल जोड़ें (ARKVORY_WEBHOOKS_CA_FILE)। प्रमाणपत्र हमेशा सत्यापित होता है।
वेबहुक की निगरानी
डिलीवरी विफल होने पर worker errorCode के साथ webhook.step_failed लिखता है, और फिर से चलने पर webhook.recovered। मीट्रिक arkvory_webhook_failing और arkvory_webhook_last_success_timestamp_seconds तथा अलर्ट ArkvoryWebhookFailing का वर्णन निगरानी में है। webhook.stopped सदस्यता के लूप का अंत दिखाता है: बंद होने पर या जब worker स्टोरेज का स्वामित्व खो देता है। webhook.prune_failed का अर्थ है कि शुरू होते समय worker हटाई गई सदस्यताओं को भूल नहीं सका; वह अगली शुरुआत में फिर कोशिश करता है। कोड unavailable और internal केवल लॉग में दिखते हैं, arkvory_webhook_failing में नहीं।
आगे न बढ़ने वाली सदस्यता
Arkvory कभी कोई इवेंट नहीं छोड़ता: डिलीवरी की विश्वसनीयता इसी पर टिकी है। इसलिए जो रिसीवर एक ही इवेंट को बार-बार अस्वीकार करता है, उदाहरण के लिए उसे पढ़ न पाने के कारण 400 लौटाता है, वह अपनी पूरी सदस्यता रोक देता है। उस सदस्यता का कोई बाद वाला इवेंट नहीं भेजा जाता; बाकी सदस्यताएँ चलती रहती हैं। worker http_4xx के साथ webhook.step_failed लिखता है और एक घंटे तक के अंतराल पर फिर कोशिश करता है, arkvory_webhook_failing 1 होता है और अलर्ट ArkvoryWebhookFailing 15 मिनट बाद चालू होता है।
- रिसीवर को ठीक करें ताकि वह उस इवेंट का उत्तर
2xxसे दे। Arkvory उसे अगली कोशिश में भेजता है, अधिकतम लगभग एक घंटे बाद, और फिर सभी प्रतीक्षारत इवेंट क्रम से। उसी नाम और रिपॉज़िटरी के साथconfigureदोबारा चलाने से स्थिति बनी रहती है। - यदि इवेंट कभी स्वीकार नहीं हो सकता, तो
--webhook-detachसे सदस्यता हटाएँ और फिर से जोड़ें। वह फ़ीड के अंत से शुरू होती है: प्रतीक्षारत इवेंट नहीं भेजे जाते। उन्हें परिवर्तन फ़ीड से उस अंतिमsequenceके बाद पढ़ें जिसे आपके रिसीवर ने संभाला था।
समस्या निवारण
errorCode | कारण और क्या करें |
|---|---|
blocked | रिसीवर का पता अनुमत नहीं है (लूपबैक, निजी, लिंक-लोकल या मेटाडेटा)। सार्वजनिक पता इस्तेमाल करें या नेटवर्क को ARKVORY_WEBHOOKS_ALLOW_PRIVATE में जोड़ें। |
timeout | 10 सेकंड में कोई उत्तर नहीं। जल्दी उत्तर दें और काम को कतार में डालें। |
network | कनेक्शन अस्वीकृत, नाम नहीं मिला या कनेक्शन रीसेट हुआ। सर्वर से URL, DNS और फ़ायरवॉल जाँचें। |
tls | प्रमाणपत्र भरोसेमंद नहीं है, समाप्त हो गया है या नाम गलत है। उसे ठीक करें, या ARKVORY_WEBHOOKS_CA_FILE सेट करें। |
redirect | रिसीवर ने 3xx से उत्तर दिया। रीडायरेक्ट नहीं अपनाए जाते: अंतिम URL इस्तेमाल करें। |
http_4xx | रिसीवर ने अनुरोध अस्वीकार किया। उसकी हस्ताक्षर जाँच, पथ और कुंजी जाँचें। |
http_5xx | रिसीवर विफल हुआ। Arkvory एक घंटे तक के अंतराल पर कोशिश करता रहता है। |
secret | सीक्रेट फ़ाइल नहीं है, पढ़ी नहीं जा सकती या 16 बाइट से छोटी है। |
unavailable | worker डेटाबेस से फ़ीड या सदस्यता की स्थिति नहीं पढ़ सका। कुछ नहीं भेजा गया; वह 5 सेकंड बाद फिर कोशिश करता है। डेटाबेस जाँचें। |
internal | worker में एक अनपेक्षित त्रुटि। कुछ नहीं भेजा गया; वह 5 सेकंड बाद फिर कोशिश करता है। worker लॉग के साथ इसकी सूचना दें। |
कुछ नहीं आ रहा? जाँचें कि worker लॉग में webhook.started है, ARKVORY_WEBHOOKS_FILE सेट है, रिपॉज़िटरी का नाम और actions फ़िल्टर। नया सब्सक्रिप्शन अपने पहले चरण के बाद की घटनाएँ ही भेजता है।