وضعیت انتشار را از برنامهٔ آینده جدا کنید

اطلاعیهٔ رسمی پستگرس، نخستین نامزد انتشار نسخهٔ ۱۹ را در ۱۵ اکتبر ۲۰۲۶ معرفی کرده است. همان اطلاعیه، نامزد بعدی را برای ۱۲ نوامبر و انتشار عمومی را به‌صورت برنامه‌ریزی‌شده برای ۱۹ نوامبر بیان می‌کند. بنابراین در بازبینی ۲۷ اکتبر، نسخهٔ ۱۹ را پایدار معرفی نمی‌کنیم. تاریخ برنامه می‌تواند تغییر کند و پیش از تصمیم نهایی باید با همان منبع رسمی دوباره تطبیق داده شود.

نامزد انتشار برای تمرین و بازخورد محیط جدا ارزشمند است، اما شمارهٔ بزرگ‌تر به معنی آمادگی خودکار سرویس اصلی نیست. باید معلوم شود برنامه به کدام سرور وصل است و افزونه‌های آن چیست. بررسی نسخهٔ ابزار خط فرمان کافی نیست؛ ممکن است کاربر به سروری با نسخهٔ دیگر وصل شود. نمونهٔ پرس‌وجو، اطلاعات را از خود اتصال سرور می‌گیرد و یک شیء ساختاریافته برای بررسی بعدی تولید می‌کند.

ثبت نسخه و جلوگیری از پذیرش خاموش نامزد انتشار

دروازهٔ نمونه، رشتهٔ نسخه و عدد نسخه را با هم می‌سنجد و نامزد، بتا یا نسخهٔ توسعه را برای محیط اصلی قبول نمی‌کند. حتی اگر رشتهٔ پایدار نسخهٔ ۱۹ به آن داده شود، بدون بازبینی منبع و سیاست تازه آن را خودکار تأیید نمی‌کند. این محافظ ساده جای آزمون افزونه‌ها، طرح اجرا یا سازگاری داده را نمی‌گیرد؛ تنها مانع تبدیل خاموش یک پیش‌انتشار به خط مبنای تأییدشده می‌شود.

چهار فایل را کنار هم ذخیره و python -m unittest test_release_gate.py را اجرا کنید. سپس python release_gate.py demo_inventory.json را اجرا کنید؛ خروجی نمونه باید وضعیت پیش‌انتشار و کد خروج ناموفق برای انتشار اصلی داشته باشد. این شکست، نتیجهٔ مورد انتظار آزمایش است. برای جمع‌آوری واقعی، کاربر مجاز می‌تواند psql -At -f collect_version.sql > inventory.json را روی اتصال هدف اجرا کند؛ نمونهٔ محلی خودکار به سرور وصل نمی‌شود.

پرس‌وجوی موجودی خواندنی است، اما فایل حاصل می‌تواند نام افزونه‌های داخلی را نشان دهد؛ آن را در مسیر خصوصی نگه دارید. اجرای آزمون پایتون با دادهٔ نمونه، اثبات اجرای پستگرس ۱۹ یا موفقیت ارتقای یک خوشه نیست. برنامهٔ مهاجرت نسخهٔ اصلی باید نسخهٔ پشتیبان، بازیابی، تغییرات ناسازگار و زمان توقف را پوشش دهد. راهنمای رسمی ارتقای همان نسخه را با روش بسته‌بندی محیط خود تطبیق دهید.

فایل‌های کامل و قابل اجرا

چهار فایل زیر کامل‌اند؛ پیش‌نیاز، ترتیب اجرا و روش بررسی در متن آمده است. کدها خلاصه یا پنهان نشده‌اند.

1. فایل کامل collect_version.sql

این فایل را با همین نام و بدون حذف سطرها کنار بقیهٔ فایل‌ها ذخیره کنید.

SELECT json_build_object(
  'serverVersion', current_setting('server_version'),
  'versionNum', current_setting('server_version_num')::integer,
  'extensions', (SELECT coalesce(json_agg(extname ORDER BY extname), '[]'::json) FROM pg_extension)
);

دستور اجرا، نتیجهٔ مورد انتظار و محدودیت این فایل در بخش اجرای مقاله توضیح داده شده است.

2. فایل کامل demo_inventory.json

این فایل را با همین نام و بدون حذف سطرها کنار بقیهٔ فایل‌ها ذخیره کنید.

{"serverVersion": "19rc1", "versionNum": 190000, "extensions": ["plpgsql"]}

دستور اجرا، نتیجهٔ مورد انتظار و محدودیت این فایل در بخش اجرای مقاله توضیح داده شده است.

3. فایل کامل release_gate.py

این فایل را با همین نام و بدون حذف سطرها کنار بقیهٔ فایل‌ها ذخیره کنید.

from datetime import date
import json
from pathlib import Path
import re
import sys

REVIEWED = date(2026, 10, 27)
REVIEW_BY = date(2026, 11, 10)


def assess(inventory, today):
    if not REVIEWED <= today <= REVIEW_BY:
        return 'review-official-release-status'
    version = inventory.get('serverVersion', '')
    number = inventory.get('versionNum')
    if re.search(r'beta|rc|devel', version, re.I):
        return 'prerelease-staging-only'
    match = re.fullmatch(r'(\d+)\.\d+', version)
    if not match or type(number) is not int or int(match[1]) != number // 10000:
        return 'review-inconsistent-version-data'
    if 14 <= number // 10000 <= 18:
        return 'existing-stable-branch-check-patches-and-extensions'
    return 'unreviewed-release-check-official-status'


if __name__ == '__main__':
    path = Path(sys.argv[1]) if len(sys.argv) > 1 else Path(__file__).with_name('demo_inventory.json')
    result = assess(json.loads(path.read_text(encoding='utf-8')), date.today())
    print(json.dumps({'assessment': result}))
    raise SystemExit(0 if result.startswith('existing-stable') else 1)

دستور اجرا، نتیجهٔ مورد انتظار و محدودیت این فایل در بخش اجرای مقاله توضیح داده شده است.

4. فایل کامل test_release_gate.py

این فایل را با همین نام و بدون حذف سطرها کنار بقیهٔ فایل‌ها ذخیره کنید.

from datetime import date
import unittest
from release_gate import assess


class ReleaseTests(unittest.TestCase):
    def test_candidate_and_future_stable_are_not_promoted(self):
        today = date(2026, 10, 27)
        self.assertEqual(assess({'serverVersion': '19rc1', 'versionNum': 190000}, today), 'prerelease-staging-only')
        self.assertIn('unreviewed-release', assess({'serverVersion': '19.0', 'versionNum': 190000}, today))
        self.assertIn('existing-stable', assess({'serverVersion': '18.6', 'versionNum': 180006}, today))

    def test_policy_and_mismatched_inventory(self):
        self.assertIn('official-release', assess({}, date(2026, 11, 11)))
        self.assertIn('inconsistent', assess({'serverVersion': '18.6', 'versionNum': 190000}, date(2026, 10, 27)))


if __name__ == '__main__': unittest.main()

دستور اجرا، نتیجهٔ مورد انتظار و محدودیت این فایل در بخش اجرای مقاله توضیح داده شده است.

اجرای بررسی بدون تغییر پایگاه داده

برای ارزیابی واقعی، بارکاری نماینده، دادهٔ آزمایشِ بدون اطلاعات حساس و شاخص‌های پیش از تغییر را آماده کنید. نتیجهٔ پرس‌وجو، زمان پاسخ و رفتار تراکنش‌ها را در دو محیط مقایسه کنید و معیار بازگشت داشته باشید. یادداشت انتشار نهایی را در روز تصمیم دوباره بخوانید؛ این مقاله یک بررسی تاریخ‌دار است. هدف، تمرین قابل حسابرسی پیش از انتشار پایدار است، نه تشویق به اجرای نامزد انتشار روی دادهٔ اصلی سازمان.

چک‌لیست اجرای عملی

  • نامزد انتشار با پایدار یکسان معرفی نشود.
  • نسخه از خود اتصال سرور خوانده شود.
  • نتیجهٔ نمونهٔ نامزد باید مانع انتشار اصلی شود.
  • راهنمای نهایی و مسیر بازیابی دوباره بررسی شوند.

منابع

تدوین و راهنمای عملی: دانشنامه لیان.