حالت شکستی که فقط وقتی دیر شده نمایان می‌شود

یک وظیفه‌ی بکاپ که هر شب اجرا می‌شود و یک سال تمام «موفق» گزارش می‌دهد می‌تواند دقیقاً همان یک باری که لازمش دارید بی‌ارزش باشد — یک دامپ بی‌صدا ناقص‌مانده، یک ناهماهنگیِ اسکیما، یک خطای مجوز که فقط هنگام بازیابی شکست می‌خورد، نه هنگام خروجی‌گرفتن. تمام‌شدنِ pg_dump بدون خطا فقط می‌گوید مرحله‌ی خروجی‌گرفتن کار کرده. هیچ‌چیزی درباره‌ی اینکه آیا فایل تولیدشده واقعاً می‌تواند داده‌هایتان را بازسازی کند نمی‌گوید. فاصله‌ی بین «وظیفه کرش نکرد» و «بکاپ کار می‌کند» دقیقاً همان‌جایی است که برنامه‌های بازیابی فاجعه در عمل شکست می‌خورند، و تا روزی که واقعاً دارید بازیابی می‌کنید نامرئی است.

اینجا «تأییدشده» دقیقاً یعنی چه

// A daily scheduler runs pg_dump (custom format), then proves the dump is
// actually restorable: it restores it into a scratch database, compares the
// table count and key row counts against the live values captured at dump
// time, and drops the scratch database again. A backup that was never
// restored is a hope, not a backup — every run records whether the restore
// check passed.

هر اجرا چهار کار انجام می‌دهد، نه دو تا: دامپ‌گرفتن، بازیابی در یک پایگاه‌داده‌ی دورریختنی، مقایسه، پاک‌سازی. مقایسه یک چک‌سام روی فایل نیست — تعداد ردیف روی یک مجموعه‌ی ثابت از جدول‌های مهم است (users, organizations, projects, tasks, columns, issues, time_entries, comments) که در برابر شمارش‌های گرفته‌شده از پایگاه‌داده‌ی زنده هنگام دامپ‌گرفتن چک می‌شود. اگر پایگاه‌داده‌ی بازیابی‌شده در tasks ردیف کمتری از پایگاه‌داده‌ی زنده هنگام شروع دامپ داشته باشد، این یک حالت شکستِ فرضی نیست — همان شب گرفته می‌شود، نه هنگام یک حادثه‌ی واقعی کشف می‌شود.

هر اجرا چه‌چیزی ثبت می‌کند

type Run struct {
    Trigger       string // scheduled | manual
    Status        string // running | success | failed
    File          string
    SizeBytes     int64
    TableCount    int
    RowCounts     string // نمای لحظه‌ای JSON هنگام دامپ‌گرفتن
    RestoreStatus string // verified | failed | pending
    RestoreDetail string
    StartedAt     time.Time
    FinishedAt    *time.Time
    DurationMs    int64
}

RestoreStatus عمداً یک فیلد جدا از Status است — یک دامپ می‌تواند به‌عنوان یک فایل موفق شود درحالی‌که چک بازیابی‌اش شکست می‌خورد، و همین تفکیک دقیقاً همان اطلاعاتی است که یک لاگ بکاپ برای مفیدبودن لازم دارد. یک ردیف با Status: success, RestoreStatus: failed سیستم است که صریحاً می‌گوید «یک فایل دارید، اما نتوانستم ثابت کنم کار می‌کند» — که در یک لاگ چیز خیلی متفاوتی از سکوت است.

خارج از سایت، نه فقط روی همان دیسک

بکاپی که روی همان سروری زندگی می‌کند که دارد از پایگاه‌داده‌ی روی آن محافظت می‌کند، در برابر حالت شکستی که خودِ آن سرور از بین می‌رود دوام نمی‌آورد. وی‌کی‌اف‌گو به‌صورت اختیاری دامپ تأییدشده را از طریق تلگرام یا بله خارج از سایت می‌فرستد — با یک توکن بات اپراتور تنظیم‌شده (BACKUP_TG_TOKEN, BACKUP_TG_CHAT_ID)، نه بات خودِ هیچ تننتی، پس این زیرساختی است که پلتفرم اجرایش می‌کند، نه چیزی که هر سازمان باید خودش راه‌اندازی کند. دامپ پیش از خروج از سرور رمزنگاری می‌شود و برای جاشدن در محدودیت حجم فایل پلتفرم پیام‌رسان تکه‌تکه می‌شود؛ یک هش RemoteSHA از دامپِ متنِ‌ساده ثبت می‌شود تا یک نسخه‌ی بازیابی‌شده بعداً در برابرش تأیید شود.

پشتیبانی بله مشخصاً برای استقرارهای ایرانی اهمیت دارد: API خودِ تلگرام از داخل ایران به‌طور قابل‌اعتماد در دسترس نیست، و BALE_API_BASE اجازه می‌دهد همان خط‌لوله‌ی خارج-از-سایت به‌جایش با API بله اجرا شود، بدون یک یکپارچه‌سازیِ دوم برای ساختن و نگه‌داری.

نگه‌داری، تا دامپ‌های قدیمی برای همیشه انباشته نشوند

BACKUP_RETENTION_DAYS (پیش‌فرض ۱۴) فایل‌های دامپِ قدیمی‌تر از آن سن را خودکار حذف می‌کند — یک سیستم بکاپ که هیچ‌وقت هرس نمی‌کند سرانجام همان دیسکی را پر می‌کند که قرار است از گم‌شدنش محافظتتان کند.

اشتباهات رایج

اعتمادکردن به یک علامتِ سبز که فقط یعنی «خروجی‌گرفتن تمام شد». این دقیقاً همان شکافی است که این سیستم می‌بندد — هنگام ممیزیِ سلامت بکاپ، RestoreStatus را چک کنید، نه فقط Status.

اجرای زمان‌بند زیر یک نقش پایگاه‌داده بدون CREATEDB. مرحله‌ی تأیید-بازیابی نیاز دارد یک پایگاه‌داده‌ی موقت بسازد و حذف کند؛ بدون آن مجوز، دامپ همچنان موفق می‌شود و اجرا با یک پیام قابل‌اقدام به‌عنوان restore-failed علامت‌گذاری می‌شود، نه اینکه بی‌صدا شکست بخورد.

فرض‌کردن اینکه بکاپ‌های روی دیسک کافی‌اند. آن‌ها در برابر یک مایگریشنِ بد یا حذف تصادفی محافظت می‌کنند. در برابر از دست‌دادن خودِ سرور محافظت نمی‌کنند — کپیِ خارج-از-سایت برای همین است.

سؤالات متداول

بکاپ چقدر یک‌بار اجرا می‌شود؟ روزی یک‌بار، در یک ساعت محلیِ قابل‌تنظیم (BACKUP_HOUR, پیش‌فرض ۳ بامداد) — به‌علاوه اجراهای دستیِ به‌درخواست.

برای پایگاه‌داده‌ی موقتِ استفاده‌شده برای تأیید چه اتفاقی می‌افتد؟ بلافاصله بعد از مقایسه‌ی تعداد ردیف حذف می‌شود؛ هرگز باقی نمی‌ماند و هرگز ترافیک نمی‌گیرد.

می‌توانم زمان‌بند را بدون از‌دست‌دادن قابلیت بکاپ دستی غیرفعال کنم؟ بله — BACKUP_ENABLED=false اجرای خودکار روزانه را غیرفعال می‌کند؛ اجراهای دستی همچنان کار می‌کنند.

قدم بعدی