کدهای خطا و کاری که باید کرد
هر کدی که ممکن است برگردد، معنیاش، و اینکه باید دوباره تلاش کنید، چیزی را درست کنید یا صبر کنید.
خطا در سگمنتیک یک شکل ندارد. میزبان ورود داده یک شکل دارد، میزبان مدیریتی شکل دیگری، و شکل سومی روی یازده مسیر از میزبان مدیریتی بیرون میزند. کلاینتی که فقط یکی از این سه را میشناسد، روی دو تای دیگر undefined میخواند و شاخهای را میرود که هیچکس تستش نکرده است.
این صفحه هر کدی را که یک سطح مشتریرو میتواند برگرداند فهرست میکند، دستهبندیشده بر اساس کاری که باید بکنید.
سه شکل خطا، نه یکی
محتاطانه پارس کنید. اگر error یک آبجکت است، error.code را بخوانید. اگر error یک رشته است، هیچ کدی وجود ندارد و تنها چیزی که دارید وضعیت HTTP است. اگر کلید error وجود ندارد، روی میزبان ورود داده هستید و فیلدی که میخواهید status است.
میزبان ورود داده
نشانی https://in.segmentic.net یک آبجکت تخت برمیگرداند. هیچ فیلد code روی این میزبان وجود ندارد. مقدار ماشینخوان status است و همیشه یکی از دو رشته "ok" یا "error".
{"status":"error","message":"malformed JSON"}
پاسخ موفق شمارش دارد. accepted و rejected وقتی صفرند فرستاده نمیشوند، نه اینکه 0 بیایند. پس دستهای که کامل رد شده باشد در اصل کلید accepted ندارد.
{
"status": "ok",
"accepted": 1,
"warnings": [
{
"code": "generated_message_id",
"field": "message_id",
"note": "no message_id sent; retries of this event cannot be de-duplicated"
}
]
}
در دسته، خرابی هر قلم با اندیس آرایهای که فرستادهاید گزارش میشود، تا منطق تلاش دوباره شما بتواند آن قلم را بدون تطبیق محتوا پیدا کند. رویدادهایی که فرستادهاید ممکن است هنوز شناسه نداشته باشند، که خودش نیمی از دلیل رد شدنشان است.
{
"status": "ok",
"accepted": 2,
"rejected": 1,
"errors": [{"index": 1, "reason": "unknown_type: \"trak\""}]
}
رشته reason متن کامل خطاست و مقدار خودتان را هم در خود دارد. بخش پایدارش کلمه اول است، اینجا unknown_type. روی پیشوند تطبیق بدهید، نه روی کل رشته.
نوع محتوا روی هر پاسخ این میزبان application/json; charset=utf-8 است.
سه مسیر ورود داده از این شکل استفاده نمیکنند. POST /v1/bounce/{local} متن ساده برمیگرداند نه JSON. POST /v1/inbox و POST /v1/devices شکل خودشان را دارند که در دستگاهها و پوش و درونسایتی و صندوق پیام آمده است. GET /s/{code} برای کد ناشناخته یک ۴۰۴ متن ساده و در حالت درست ۳۰۲ میدهد.
میزبان مدیریتی
نشانی https://api.segmentic.net همهچیز را زیر error تودرتو میکند.
{"error":{"code":"budget_exhausted","message":"this key has spent its request budget for the minute"}}
فیلد details بخش ساختاریافته خطای اعتبارسنجی را میآورد، تا بتوانید انگشت بگذارید روی همان جای payload خودتان که مشکل دارد.
{
"error": {
"code": "batch_too_large",
"message": "a batch may carry at most 500 events",
"details": {"limit": 500, "sent": 501}
}
}
فیلد need روی ۴۰۳ میآید و درست نام همان مجوزی را میگوید که کلید ندارد. بهعمد منتشر شده است: راه دیگر این بود که مشتری تیکت بزند تا بفهمد کدام مجوز را باید بدهد.
{
"error": {
"code": "forbidden",
"message": "this key does not carry campaign.send, see GET /v1/whoami for what it does carry",
"need": "campaign.send"
}
}
روی POST /v1/events، مقدار details بهجای آبجکت، آرایه قلمبهقلم است.
{
"error": {
"code": "all_events_rejected",
"message": "no event in this batch could be accepted",
"details": [
{"index": 0, "reason": "missing_identity"},
{"index": 1, "reason": "missing_identity"}
]
}
}
شکل تخت، روی یازده مسیر
یازده مسیر مدیریتی هندلرشان را با پنل به اشتراک میگذارند، و نویسنده خطای پنل یک رشته تخت بدون هیچ کدی مینویسد.
{"error":"segment not found"}
کلاینتی که فقط body.error.code را میخواند، روی تکتک اینها undefined میگیرد. مسیرها و خرابیهایی که این شکل را دارند:
| مسیر | خرابیهای تخت |
|---|---|
GET /v1/schema/events | ۵۰۳ با schema unavailable |
GET /v1/schema/traits | ۵۰۳ با schema unavailable |
POST /v1/audiences/validate | ۴۰۰ با malformed JSON |
POST /v1/audiences/count | ۴۰۰ با malformed JSON، ۴۰۰ با متن خود کامپایلر، ۵۰۳ با count unavailable |
GET /v1/segments | ۵۰۳ با segments unavailable |
GET /v1/segments/{id} | ۴۰۰ با invalid segment id، ۴۰۴ با segment not found |
GET /v1/campaigns | ۵۰۳ با campaigns unavailable |
GET /v1/campaigns/{id} | ۴۰۰ با invalid campaign id، ۴۰۴ با campaign not found |
POST /v1/reports/funnel | ۴۰۰ با invalid_report، ۵۰۳ با متن فارسی |
POST /v1/reports/retention | ۴۰۰ با invalid_report، ۵۰۳ با متن فارسی |
POST /v1/messages | ۴۰۰ و ۴۰۹ و ۴۲۹ و ۵۰۳، همهشان |
کد invalid_report استثنای داخل استثناست: تخت است ولی کد دارد.
{"error":"قیف به دستکم دو مرحله نیاز دارد","code":"invalid_report"}
چهار رد شدن از نگهبان مشترک اعتبارنامه هم با همین شکل تخت به میزبان مدیریتی میرسند، با کد و متن فارسی: wrong_surface روی ۴۰۱، و impersonation_read_only و impersonation_forbidden و ip_not_allowed روی ۴۰۳. آخری با یک کلید API معمولی هم دیده میشود، چون فهرست نشانیهای مجاز حساب روی هر اعتبارنامهای اعمال میشود، نه فقط روی نشست مرورگر.
نه میزبان ورود داده و نه میزبان مدیریتی به Accept-Language توجه نمیکنند. میانافزار زبان فقط روی خود پنل سوار است. هر پیامی که از کاتالوگ ترجمه بیاید، هرچه بخواهید، فارسی به دست شما میرسد. این شامل هر چهار پیام quota_* و پیام account_locked است.
روی کد شاخه بزنید، هرگز روی متن
کد قرارداد است. متن قرارداد نیست و هر وقت جمله بهتری پیدا شود عوض میشود.
دو پیام این را ملموس میکنند. متن write_key_rejected دو بار نویسه سهنقطه U+2026 دارد، داخل (wk_…) و (sk_seg_…)، نه سه نقطه جدا. متن قالب کلید تراکنشی بین ۸ و ۲۰۰ یک en dash با کد U+2013 دارد، نه خط تیره ساده. یکپارچهسازیای که روی هرکدام از این دو رشته تطبیق بدهد، با نویسهای میشکند که نویسندهاش هرگز تایپش نکرده است.
درخواست را درست کنید
تلاش دوباره روی هرکدام از اینها یعنی فرستادن همان payload به همان رد شدن. شکل تودرتو، روی میزبان مدیریتی.
| کد | HTTP | مسیرها | یعنی چه |
|---|---|---|---|
malformed_json | ۴۰۰ | هر مسیری که بدنه میگیرد | بدنه پارس نشد، یا بزرگتر از 8 MiB بود |
batch_empty | ۴۰۰ | POST /v1/events | کلید events نبود یا خالی بود |
bad_id | ۴۰۰ | PUT /v1/segments/{id}، DELETE /v1/segments/{id}، POST /v1/campaigns/{id}/send، POST /v1/campaigns/{id}/submit | مسیر شناسه عددی مثبت نداشت |
name_required | ۴۰۰ | POST /v1/segments | فیلد name خالی یا فقط فاصله بود |
invalid_channel | ۴۰۰ | POST /v1/campaigns | این کانال چیزی نیست که این حساب بتواند رویش بنویسد. مقدار details برابر {"field":"channel"} است |
unknown_endpoint | ۴۰۴ | مسیر پیشفرض | این مسیر روی این میزبان ثبت نشده است. متن، متد و مسیر را میگوید و به GET /v1/capabilities ارجاع میدهد |
not_found | ۴۰۴ | PUT /v1/segments/{id}، POST /v1/campaigns/{id}/send، POST /v1/campaigns/{id}/submit | شناسه ناشناخته است، یا مال حساب دیگری است. این دو حالت بهعمد از هم جدا نشدهاند |
batch_too_large | ۴۱۳ | POST /v1/events | بیش از ۵۰۰ رویداد. مقدار details برابر {"limit":500,"sent":N} است. دسته را بشکنید |
filter_invalid | ۴۲۲ | POST /v1/audiences/validate، POST /v1/segments، PUT /v1/segments/{id} | تعریف مخاطب کامپایل نشد. متن، جمله خود کامپایلر است |
campaign_invalid | ۴۲۲ | POST /v1/campaigns، POST /v1/campaigns/{id}/submit | کمپین از اعتبارسنجی رد نشد |
export_kind_invalid | ۴۲۲ | POST /v1/exports | مقدار kind یکی از events و messages و profiles و segment نبود |
all_events_rejected | ۴۲۲ | POST /v1/events | هیچ رویدادی از دسته نرمالسازی نشد. مقدار details آرایه قلمبهقلم است |
سه کد دیگر ۴۰۹ هستند و درست کردنشان کار آدم است، نه ویرایش payload.
| کد | HTTP | مسیر | یعنی چه |
|---|---|---|---|
approval_required | ۴۰۹ | POST /v1/campaigns/{id}/send | این حساب تایید کمپین را قبل از ارسال لازم دارد. اول ثبتش کنید، بعد تایید بگیرید |
approval_stale | ۴۰۹ | POST /v1/campaigns/{id}/send | کمپین بعد از تایید عوض شده است. دوباره ثبتش کنید |
not_submittable | ۴۰۹ | POST /v1/campaigns/{id}/submit | فقط کمپین پیشنویس یا متوقفشده را میشود برای تایید ثبت کرد |
مسیر POST /v1/audiences/validate برای فیلتر نامعتبر ۴۲۲ میدهد، در حالی که نقطه معادلش در پنل ۲۰۰ با valid: false میدهد. پنل برای فرمی که کسی دارد در آن تایپ میکند درست است و برای یکپارچهسازیای که خطایش روی وضعیت شاخه میزند غلط.
اعتبارنامه را درست کنید
چهارتای اینها ۴۰۱ هستند و با هم فرق دارند. قبل از اینکه دنبال غلط تایپی بگردید کد را بخوانید.
| کد | HTTP | یعنی چه |
|---|---|---|
unauthenticated | ۴۰۱ | هیچ اعتبارنامهای روی درخواست نبود، یا بود و شناخته نشد. متن: a valid API key is required |
api_key_required | ۴۰۱ | نشست پنل فرستاده شده است. این میزبان فقط کلید sk_seg_ میگیرد |
write_key_rejected | ۴۰۱ | توکن با wk_ شروع میشود. آن کلید عمومی است و داخل اپ شما منتشر میشود و چیزی نمیتواند بخواند. یک کلید API بسازید |
key_expired | ۴۰۱ | کلید شناخته شد و تاریخ انقضایش گذشته است. بچرخانیدش |
wrong_surface | ۴۰۱ | اعتبارنامه ستادی روی میزبان مشتری، یا برعکس. شکل تخت، متن فارسی |
forbidden | ۴۰۳ | نقش کلید در اشتراک با دامنهاش این مجوز را ندارد. فیلد need نامش را میگوید. مسیر GET /v1/whoami مجموعه مؤثر را برمیگرداند |
ip_not_allowed | ۴۰۳ | حساب فهرست نشانی مجاز دارد و این نشانی در آن نیست. شکل تخت، متن فارسی |
impersonation_read_only | ۴۰۳ | نشست پشتیبانی فقطخواندنی خواسته چیزی را تغییر بدهد. شکل تخت |
impersonation_forbidden | ۴۰۳ | نشست پشتیبانی کاری را خواسته که پشتیبانی هرگز در حساب شما نمیتواند بکند. شکل تخت |
مسیر GET /v1/whoami یک واحد بودجه خرج میکند، مثل هر مسیر ساده دیگری، و مجموعه مؤثر مجوزها را برمیگرداند، پس یک کلاینت خوب میتواند موقع بالا آمدن شکست بخورد بهجای اینکه روی همان یک فراخوانی ماهانهای شکست بخورد که به مجوز نداشتهاش نیاز دارد. تنها مسیر میزبان مدیریتی که سنجیده نمیشود GET /v1/status است.
curl -s https://api.segmentic.net/v1/whoami \
-H "Authorization: Bearer sk_seg_..."
{
"tenant_id": 42,
"api_key_id": 7,
"role": "analyst",
"permissions": [
"analytics.read", "audit.read", "campaign.read", "data.export",
"event.read", "journey.read", "member.read", "profile.read",
"segment.read", "settings.read", "template.read"
],
"scoped": false
}
فهرست permissions مجموعه مؤثر است و الفبایی مرتب میشود. نقش یکی از این هفتتاست: owner و admin و marketer و analyst و viewer و approver و finance. کلید با نقش owner اصلا ساخته نمیشود، پس هیچ کلیدی tenant.transfer و tenant.delete ندارد.
مقدار scoped روی هر کلیدی که این محصول میتواند بسازد false است. ستون دامنه در پایگاه داده هست و خوانده هم میشود، ولی هیچ مسیری آن را نمینویسد، پس هر کلید کل نقشش را دارد و کلید باریکتر از نقش هنوز ساختنی نیست.
روی میزبان ورود داده، هر دو پیام missing write key و invalid write key وضعیت ۴۰۱ دارند و هر دو دائمیاند. دومی برای کلید ناشناخته و کلید باطلشده و کلید معلق یک جواب میدهد، تا نشود با این نقطه فهمید چه کلیدهایی وجود دارند.
صبر کنید
| کد | HTTP | کجا | چه کنید |
|---|---|---|---|
budget_exhausted | ۴۲۹ | هر مسیر مدیریتی بهجز GET /v1/status | هدر Retry-After: 60. سطل دقیقه با ساعت دیواری میچرخد. سقفها را ببینید |
بدون کد، error تخت | ۴۲۹ | POST /v1/messages | هدر Retry-After: 60. متن rate limit exceeded: N requests per minute است |
HTTP/1.1 429 Too Many Requests
Retry-After: 60
Content-Type: application/json; charset=utf-8
{"error":{"code":"budget_exhausted","message":"this key has spent its request budget for the minute"}}
وضعیت ۴۲۹ تراکنشی شکل دیگری دارد:
HTTP/1.1 429 Too Many Requests
Retry-After: 60
X-RateLimit-Limit: 2
X-RateLimit-Remaining: 0
Content-Type: application/json; charset=utf-8
{"error":"rate limit exceeded: 2 requests per minute"}
میزبان ورود داده هرگز ۴۲۹ نمیدهد. هیچ محدودکننده نرخی ندارد.
دوباره تلاش کنید
همه اینها ۵۰۳ هستند و همه یعنی ایراد از ماست. عقب بکشید و همان payload را دوباره بفرستید.
| کد | HTTP | مسیر | علت |
|---|---|---|---|
budget_unavailable | ۵۰۳ | هر مسیر مدیریتی بهجز GET /v1/status | ردیس در دسترس نبود و بررسی بودجه بسته شکست میخورد |
ingest_unavailable | ۵۰۳ | POST /v1/events | صف در دسترس نبود. بهعمد ۵۰۳ است نه ۵۰۰: کسی که ۵۰۰ بگیرد فکر میکند payload خودش مشکل داشته و متوقف میشود |
segment_unavailable | ۵۰۳ | POST /v1/segments، PUT /v1/segments/{id}، DELETE /v1/segments/{id} | ذخیرهگاه سگمنت خطا داد |
campaign_unavailable | ۵۰۳ | POST /v1/campaigns، POST /v1/campaigns/{id}/send | ذخیرهگاه کمپین خطا داد |
approval_unavailable | ۵۰۳ | ثبت و ارسال | ذخیرهگاه تایید خطا داد. بسته شکست میخورد، پس ارسالی انجام نشده است |
export_unavailable | ۵۰۳ | GET /v1/exports، POST /v1/exports | ذخیرهگاه خروجی خطا داد |
بدون کد، error تخت | ۵۰۳ | POST /v1/messages | متن message not sent. فقط وقتی هیچ شناسه پیامی برنگشته باشد. ارسال تراکنشی را ببینید |
بدون کد، error تخت | ۵۰۳ | خواندن اسکیما و شمارش و سگمنت و کمپین، و دو مسیر گزارش | انبار داده یا ذخیرهگاه در دسترس نبود. روی گزارشها متن یک جمله فارسی است |
در کل محصول فقط یک ۵۰۳ هدر Retry-After دارد و آن هم روی میزبان ورود داده است: خرابی جستوجوی کلید نوشتن Retry-After: 5 میگذارد. بقیه ۵۰۳ها هیچ نمیگذارند. عقبنشینی خودتان را انتخاب کنید.
پول بدهید، یا تیکت بزنید
تلاش دوباره هیچکدام از اینها را باز نمیکند. کسی باید فاکتوری را پرداخت کند، پلنی را ارتقا بدهد یا مجوزی بدهد.
| کد | HTTP | مسیر | یعنی چه |
|---|---|---|---|
quota_cancelled | ۴۰۲ | POST /v1/events و هر مسیر ورود داده | اشتراک لغو شده است |
quota_trial_over | ۴۰۲ | POST /v1/events و هر مسیر ورود داده | دوره آزمایشی تمام شده است |
quota_event_cap | ۴۰۲ | POST /v1/events و هر مسیر ورود داده | حساب به سقف سخت رویداد پلنش در این ماه جلالی رسیده است |
quota_message_cap | ۴۰۲ | هیچجا به آن نمیرسد | مسیر کد وجود دارد. هیچ فراخوانیای سنجه پیام را به بررسی سهمیه نمیدهد، پس هرگز رخ نمیدهد |
account_locked | ۴۰۳ | GET /v1/exports، POST /v1/exports، POST /v1/reports/funnel، POST /v1/reports/retention | مصرف به سه برابر سهمیه رسیده، یا فاکتوری ۷۵ روز از سررسیدش گذشته است. مقدار details یکی از {"reason":"usage_300"} یا {"reason":"overdue_75"} است |
پیامهای quota_* روی هر دو میزبان همیشه فارسیاند، هر چیزی که Accept-Language بگوید. این چهار جمله:
| کد | متن |
|---|---|
quota_cancelled | اشتراک این حساب لغو شده است |
quota_trial_over | دورهٔ آزمایشی به پایان رسیده است |
quota_event_cap | سقف رویدادهای این ماه پر شده است |
quota_message_cap | سقف پیامهای این ماه پر شده است |
کد account_locked درست چهار مسیر مدیریتی را میبندد. ورود داده، ارسال تراکنشی، ساخت کمپین، ارسال کمپین و نوشتن سگمنت همگی موقع قفل بودن حساب باز میمانند، چون سوراخ در داده شما را بعدها نمیشود پر کرد و بدهی را بعدها میشود وصول کرد.
حکم سهمیه میداند حساب چقدر از سقف گذشته است. آن عدد به شما نمیرسد: پاسخ رد فقط جمله را دارد و بس. مصرف را از پنل بخوانید.
وضعیت ۴۰۲ باعث میشود هر SDK سگمنتیک دستهای را که نگه داشته دور بریزد، نه اینکه بافرش کند. هر سه SDK هر ۴xx بهجز ۴۲۹ را دائمی میشمارند. وقتی به سقف سخت رویداد بخورید، رویدادهایی که همان لحظه روی گوشی کاربران شما در صف بودند از دست میروند و بعدها هم برنمیگردند. هشدارهای مصرف را ببینید، نه پاسخ رد را.
میزبان ورود داده وضعیت دارد، نه کد
روی https://in.segmentic.net فیلد code وجود ندارد. روی وضعیت HTTP شاخه بزنید.
| HTTP | متن | علت | کار |
|---|---|---|---|
| ۴۰۰ | malformed JSON | بدنه پارس نشد | درست کنید |
| ۴۰۰ | یکی از کلیدواژههای جدول پایین | یک رویداد از اعتبارسنجی رد نشد | درست کنید |
| ۴۰۰ | batch_empty | صفر قلم در batch | درست کنید |
| ۴۰۰ | batch_too_large: N items, limit 500 | بیش از ۵۰۰ قلم | بشکنیدش |
| ۴۰۱ | missing write key | نه Authorization: Bearer، نه X-Segmentic-Key، نه ?write_key= | درست کنید. هرگز تلاش دوباره نکنید |
| ۴۰۱ | invalid write key | کلید ناشناخته، باطلشده یا معلق | درست کنید. هرگز تلاش دوباره نکنید |
| ۴۰۲ | متن فارسی سهمیه | سقف سخت، اشتراک لغوشده، یا پایان دوره آزمایشی | تلاش دوباره نکنید |
| ۴۱۳ | request body too large | بزرگتر از 5 MiB | کمتر بفرستید |
| ۵۰۳ | cannot verify the write key right now; retry | جستوجوی کلید ما خطا داد. هدر Retry-After: 5 میگذارد | تلاش دوباره، رویدادها را نگه دارید |
| ۵۰۳ | temporarily unavailable, please retry | هم گذرگاه پیام و هم بافر دیسک خطا دادند | تلاش دوباره |
دقت کنید که یک شرط روی دو میزبان دو وضعیت میگیرد: دسته بیشتر از ۵۰۰ قلم روی POST /v1/batch وضعیت ۴۰۰ میگیرد و روی POST /v1/events وضعیت ۴۱۳.
مسیرهای کانال و درونسایتی همین شکل را با متنهای خودشان دارند.
| مسیر | HTTP | متن |
|---|---|---|
POST /v1/devices | ۴۰۰ | malformed JSON، یا متن خود نرمالساز بههمراه warnings |
POST /v1/devices | ۵۰۳ | temporarily unavailable, please retry |
POST /v1/devices/unregister | ۴۰۰ | device_id is required |
POST /v1/webpush/subscribe | ۴۰۰ | user_id and a complete subscription are required |
POST /v1/webpush/unsubscribe | ۴۰۰ | endpoint is required |
POST /v1/messenger/link | ۴۰۰ | user_id, chat_id and a known platform are required |
POST /v1/messenger/unlink | ۴۰۰ | user_id and a known platform are required |
POST /v1/inbox | ۴۰۰ | user_id is required |
POST /v1/inbox | ۴۰۳ | user identity is not verified |
POST /v1/onsite/event | ۴۰۰ | campaign_id and a visitor id are required، یا unknown action |
POST /v1/onsite/response | ۴۰۰ | unknown campaign، یا متن خود اعتبارسنج |
POST /v1/hooks/{source}/{token} | ۴۰۱ | signature mismatch، یا unauthorized |
POST /v1/hooks/{source}/{token} | ۴۰۴ | unknown webhook |
POST /v1/bounce/{local} | ۴۰۰ یا ۴۱۳ | متن ساده، نه JSON |
دو مسیر بهعمد هرگز خرابی گزارش نمیکنند. GET /v1/onsite وقتی ذخیرهگاهش پایین است 200 {"campaigns":[]} میدهد، چون داخل بارگذاری صفحه شما اجرا میشود و کند شدن یا خطای گرفتن کمپین نباید به چشم بازدیدکننده شما بیاید. POST /v1/onsite/event همیشه ۲۰۰ است، حتی وقتی نوشتن نمایش خطا داده باشد. POST /v1/hooks/... برای payload ای که نمیتواند تبدیلش کند 200 {"status":"ok","accepted":0} میدهد، چون شاپیفای و ووکامرس پاسخ غیر ۲xx را روزها تکرار میکنند.
چرا یک رویداد رد شد
این ده رشته بخش پایدار errors[].reason روی میزبان ورود داده و details[].reason روی POST /v1/events هستند. مجموعه بسته است. هرچه بیرون از آن باشد invalid شمرده میشود.
| کلیدواژه | معنی |
|---|---|
unknown_type | مقدار type یکی از track و identify و page و screen و alias نبود. با مقدار خودتان همراه است |
missing_identity | نه user_id بود و نه anonymous_id |
missing_event_name | نوع track بدون event |
event_name_too_long | نام رویداد بیشتر از ۱۲۸ بایت |
event_name_invalid_chars | نام رویداد نویسه کنترلی یونیکد دارد |
id_too_long | یکی از user_id و anonymous_id و message_id بیشتر از ۲۵۶ بایت |
missing_previous_id | نوع alias بدون previous_id |
batch_too_large | بیشتر از ۵۰۰ قلم. با متن batch_too_large: N items, limit 500 |
batch_empty | صفر قلم |
timestamp_too_old | فقط در backfill. ورود داده زنده بهجایش زمان را میچسباند و هشدار میدهد |
هشدارها، که روی ۲۰۰ میآیند
هشدار یعنی رویداد پذیرفته شد و چیزی اصلاح شد. خطا نیست و وضعیت را عوض نمیکند. هر هشدار {"code","field","note"} است و field و note وقتی خالیاند فرستاده نمیشوند.
| کد | فیلد | چه شد |
|---|---|---|
generated_message_id | message_id | نفرستادید، پس ساخته شد. تلاش دوباره این رویداد دیگر تکراریزدایی نمیشود |
timestamp_in_future | timestamp | ساعت دستگاه از سرور جلوتر است. به زمان دریافت چسبانده شد |
timestamp_too_old | timestamp | قدیمیتر از پنجره ورود داده. به لبه پنجره چسبانده شد |
too_many_properties | properties | بیشتر از ۲۵۶ ویژگی. ۲۵۶ تای اول نگه داشته شد |
too_many_traits | traits | بیشتر از ۲۵۶ ویژگی پرونده. ۲۵۶ تای اول نگه داشته شد |
unserialisable_property | همان کلید | مقدار قابل ذخیره نبود و حذف شد |
invalid_phone | phone | شماره موبایل ایرانی معتبر نیست. همانطور که فرستادید ذخیره شد |
invalid_national_id | national_id | رقم کنترلی نخواند. اصلا ذخیره نشد |
پاسخ یک دسته وقتی پنجاه هشدار جمع کرد جمع کردن را بس میکند، هرچند همهشان در سنجههای کیفیت داده حساب شما شمرده میشوند. حواستان به generated_message_id باشد: تنها هشداری است که برایتان خرج دارد، چون یعنی رویدادی که دوباره فرستاده شود دو بار ذخیره میشود.
این جدول مال میزبان ورود داده است. مسیر POST /v1/events روی میزبان مدیریتی همین هشدارها را حساب میکند و بعد دورشان میریزد، پس پاسخش هیچوقت آرایه warnings ندارد و از روی آن نمیفهمید زمانی چسبانده شده یا شناسه پیامی ساخته شده. اگر این در را برای مهاجرت داده به کار میبرید، حساب کنید که هیچ سیگنالی از اصلاحها نمیگیرید.
خطاهای ارسال تراکنشی
مسیر POST /v1/messages قدیمیترین هندلر میزبان مدیریتی است و از اول تا آخر شکل تخت میدهد. هیچکدام از خرابیهایش code ندارند.
همه اینها ۴۰۰ هستند و کل رشته error همان متن کلیدواژه است:
error | معنی |
|---|---|
transactional: user_id is required | گیرندهای نیست |
transactional: template_id is required | قالبی نیست |
transactional: idempotency_key is required | نه در بدنه و نه در هدر Idempotency-Key کلیدی نیست |
transactional: idempotency_key must be 8-200 characters of letters, digits, dot, dash, underscore or colon | کلید با ^[A-Za-z0-9._:-]{8,200}$ نخواند. متن روی سیم بین ۸ و ۲۰۰ نویسه U+2013 دارد |
transactional: unknown channel | کانالی نیست که این حساب رویش بفرستد |
transactional: this endpoint does not send marketing; use a campaign | مقدار category برابر marketing بود. این نقطه سقف تعداد و ساعت سکوت را دور میزند، پس قبول کردن پیام بازاریابی اینجا یعنی یک راه مستند برای دور زدن قواعد ارسال خودتان |
transactional: too many variables | بیشتر از ۴۰ کلید در vars |
malformed JSON: <detail> | پارس نشد، یا فیلد ناشناخته داشت. فیلد ناشناخته رد میشود نه نادیده گرفته، تا idempotencyKey بدغلط ۴۰۰ بگیرد و روی هر تلاش یک کلید تازه نسازد |
یک ۴۰۹ و یک ۵۰۳:
| HTTP | error | معنی |
|---|---|---|
| ۴۰۹ | transactional: a message with this idempotency key is already in flight | تلاش قبلی خودتان هنوز در جریان است. هدر Retry-After: 1 |
| ۵۰۳ | message not sent | ارسال خطا داد و هیچ شناسه پیامی برنگشت |
وضعیت ۲۰۰ روی این نقطه یعنی تحویل داده شد نیست. فیلدهای reason و reason_fa را در بدنه بخوانید: وقتی پر میشوند که پیام بهعمد فرستاده نشده باشد، برای انصراف کاربر، فهرست سیاه، یا نبود نشانی. و اگر ارسال انجام شد ولی ثبتش خطا داد، این نقطه بهجای ۵۰۳ همان ۲۰۰ با نتیجه را میدهد، چون پیام بهراستی رفته و کسی که خلافش را بشنود دوباره میفرستد و پیام دوم ارسال میشود.
تلاش دوباره
قاعدهای که SDKها پیاده کردهاند، و همانی که باید خودتان پیاده کنید.
| وضعیت | تلاش دوباره | چرا |
|---|---|---|
| ۴۰۰، ۴۰۲، ۴۰۳، ۴۰۴، ۴۰۹، ۴۱۳، ۴۲۲ | نه | همان payload تا ابد همان جواب را میگیرد. استثنا ۴۰۹ روی POST /v1/messages است که تلاش خودتان است |
| ۴۰۱ | نه | اعتبارنامه هرگز کار نخواهد کرد. کلید را درست کنید |
| ۴۲۹ | بله، بعد از Retry-After | پنجره میچرخد |
| ۵xx | بله، با عقبنشینی نمایی و jitter | ایراد از ماست |
هر سه SDK سگمنتیک این را در یک خط گفتهاند: هرچه در بازه ۴۰۰ تا ۴۹۹ باشد بهجز ۴۲۹ دائمی است و دور ریخته میشود؛ بقیه با عقبنشینی نمایی و jitter کامل تکرار میشوند، از پایه ۱ ثانیه تا سقف ۵ دقیقه.
تفاوت ۴۰۱ و ۵۰۳ کل دلیل جدا بودنشان روی میزبان ورود داده است. SDK وضعیت ۴۰۱ را «این کلید هرگز کار نمیکند» میخواند، متوقف میشود و رویدادهای بافرشده را دور میریزد؛ ۵۰۳ را «بعدها دوباره امتحان کن» میخواند و نگهشان میدارد. این میزبان پیشتر وقتی خود جستوجوی کلید خطا میداد هم ۴۰۱ میداد، که ایراد ماست نه کلید شما: با پایگاه داده خاموششده، هشت رویداد از هشت رویداد ۴۰۱ گرفتند و سمت مشتری نابود شدند، در حالی که لاگ خودشان میگفت کلید نوشتنشان نامعتبر است. حالا آن حالت ۵۰۳ با Retry-After: 5 است، و بافر دیسک پشت کالکتور درست برای همین هست که خرابی زیرساخت هیچ رویدادی را نبرد.
نتیجه برای شما: هر ۴۰۱ از ما را ایراد پیکربندی بدانید، نه گذرا. اگر روی کلیدی که دیروز کار میکرد ۴۰۱ انبوه دیدید، بهراستی مشکل اعتبارنامه است، چون حالت خرابی دیگر این شکلی نیست.
کجا تلاش دوباره محافظتشده است
| مسیر | ساز و کار | پنجره |
|---|---|---|
| هر مسیر روی میزبان ورود داده | تکراریزدایی با message_id در ردیس | ۴۸ ساعت، با DEDUPE_TTL |
POST /v1/messages | کلید idempotency_key خودتان، رزرو در دفتر با یک رفت و برگشت | ۷ روز، با API_IDEMPOTENCY_RETENTION |
| وبهوکهای ورودی | شناسه پیام قطعی، تا تکرار پلتفرم بعد از timeout حالت عادی باشد | ۴۸ ساعت |
روی هر رویداد message_id بفرستید. بدون آن ما میسازیمش، شما هشدار generated_message_id میگیرید، و تلاش دوباره بعد از timeout شبکه رویداد را دو بار ذخیره میکند. با آن، تلاش دوباره رایگان است.
این محافظت روی POST /v1/events نیست. آن مسیر رویدادها را بیآنکه ردیس را ببیند مستقیم منتشر میکند، پس message_id آنجا فقط شناسه رویداد است و هیچچیز تکراری را نمیگیرد. تلاش دوباره روی این در، حتی با همان message_id، رویداد را دو بار ذخیره میکند. قبل از فرستادن دوباره یک خواندن بزنید.
رویداد تکراریزداییشده بهعنوان پذیرفتهشده گزارش میشود، نه بهعنوان تکراری. هیچ فیلد duplicate روی سیم نیست و شمارشها این دو را از هم جدا نمیکنند. این عمدی است: منطق تلاش دوباره شما نباید مجبور باشد اهمیت بدهد، و تکراری در سهمیه شما شمرده نمیشود.
وقتی ردیس در دسترس نیست، بررسی تکراریزدایی رد میشود و تکراری احتمالی پذیرفته میشود، بهجای اینکه رویداد از دست برود.
ارسال تراکنشی بازپخششده علامت دارد. فیلد replayed را در نتیجه بخوانید تا «پیشتر این کار را کردیم» را از «همین حالا کردیم» جدا کنید، که وقتی تلاش اولتان timeout خورده و نمیدانید کدامش شده مهم است.
هیچ نوشتن مدیریتی دیگری بهجز POST /v1/messages کلید idempotency نمیگیرد. مسیرهای POST /v1/segments و POST /v1/campaigns و POST /v1/campaigns/{id}/send و POST /v1/exports و POST /v1/events چنین فیلدی ندارند، پس تلاش دوباره روی POST /v1/campaigns کمپین دوم میسازد. اینها را فقط بعد از یک خواندن که مطمئن شوید تلاش اول ننشسته دوباره بفرستید.
شناسه پیگیری برای تیکت
هر پاسخ از هر میزبان هدر X-Segmentic-Trace دارد، شانزده نویسه شانزدهشانزدهی.
HTTP/1.1 503 Service Unavailable
X-Segmentic-Trace: 4f2a9c81b0d3e756
Content-Type: application/json; charset=utf-8
{"error":{"code":"ingest_unavailable","message":"could not queue these events; retry"}}
در بدنه خطا نیست. از هدر لاگش کنید و در تیکت پشتیبانی بیاوریدش: همین است که به ما اجازه میدهد درست همان درخواست را در لاگ پیدا کنیم، نه دستهای از درخواستهای شبیه هم. اگر خودتان شناسه پیگیری دارید، آن را با همین هدر روی درخواست بفرستید: وقتی بین ۸ تا ۶۴ نویسه شانزدهشانزدهی باشد، با حروف کوچک رعایتش میکنیم و در پاسخ برمیگردانیمش. هرچیز دیگری دور ریخته میشود و شناسه خودمان جایش مینشیند، چون این مقدار داخل خطهای لاگ ما میرود.
نام هدر مال خودمان است و traceparent استاندارد کنسرسیوم وب نیست، چون پشتش نه تصمیم نمونهگیری هست و نه سلسلهمراتب span، و هدری که شبیه traceparent باشد ولی نباشد اولین کسی را که ابزار ردیابی واقعی را به آن وصل کند گمراه میکند.
آنچه در بدنه خطا نیست
اینها را نوشتهایم چون هرکدام چیزی است که خواننده دنبالش میگردد و پیدا نمیکند.
- فیلد
request_idوجود ندارد. شناسه پیگیری فقط در هدر است. - فیلد
message_faوجود ندارد. شکل مدیریتیcodeوmessageوdetailsوneedدارد و بس. هرجا متنی فارسی باشد، در همانmessageفارسی است. - کد جدا برای خطاهای گزارش وجود ندارد. سیزده خطای اعتبارسنجی موتور گزارشها همه در یک کد
invalid_reportجمع میشوند. نه تای آنها جمله فارسی کاتالوگ را درerrorمیگذارند؛ چهار تای دیگر، یعنی نام رویداد بلند و فیلتر زیاد و کلید ویژگی بلند و مقدار ویژگی بلند، از شاخه پیشفرض رد میشوند و متن انگلیسی خود خطا را میآورند، مثلanalytics: too many filters. پس زبانerrorروی این دو مسیر ثابت نیست. بدون خواندن آن رشته هم نمیتوانید «مراحل قیف زیاد است» را از «بازه زمانی خیلی گسترده است» جدا کنید. - فیلدهای
usedوlimitروی ۴۰۲ وجود ندارند. حکم سهمیه هر دو را حساب میکند و قبل از نوشتن پاسخ دور میریزد. - بودجه باقیمانده در
GET /v1/whoamiوجود ندارد. پنج فیلد برمیگرداند و هیچکدام بودجه نیست. - **هدرهای
X-RateLimit-*روی بودجه مدیریتی وجود ندارند.** فقط رویPOST /v1/messagesهستند، آن هم فقط وقتی محدودیت نرخی تنظیم شده باشد که بهطور پیشفرض نشده است. سقفها را ببینید.
مرتبط: سقفها و محدودیت نرخ، API ورود داده، API مدیریتی.