הכללים נמצאים ב-docs/architecture/23-ops.md סעיף 7 וב-docs/architecture/07-data.md
סעיף 4.1. אלה שלבי העבודה.
ההבטחה שמאפשרת זאת בבטחה
גרסה R פועלת כראוי מול סכמת R ומול סכמת R פחות אחת. כל שינוי סכימה מתחלק להרחבה, מעבר והסרה:
- הרחבה: הוסיפו עמודה, טבלה או אינדקס. הקוד הישן מתעלם מהם.
- מעבר, למשך גרסה אחת לפחות: קוד חדש כותב את שני המבנים וקורא את החדש; משימה שניתן לחדש ממלאת נתונים ישנים בשורות הקיימות.
- הסרה: הסירו את המבנה הישן בגרסה מאוחרת יותר, לבדה.
לכן בכל רגע של שדרוג מדורג, תהליכים ישנים וחדשים יכולים לחלוק מסד נתונים אחד. אין מיגרציות לאחור: מיגרציה שהסירה עמודה לפני שעה אינה יכולה להחזיר את השורות שנכתבו באותה שעה.
משימת CI בשם schema-compat בודקת את ההבטחה בכל גרסה, על ידי הרצת בדיקות הגרסה
הקודמת מול הסכמה החדשה.
לפני שמתחילים
- קראו את הערות הגרסה. גרסה שמצריכה חלון תחזוקה מציינת זאת יחד עם הערכת הזמן; לכל היותר גרסה אחת כזו בכל מחזור.
- הריצו תרגול שחזור, או ודאו שהוא הסתיים בהצלחה עבור גרסה זו (backup-restore.md). תרגול שנכשל עוצר את השדרוג.
- צרו גיבוי בסיס:
docker compose -f docker/compose.yaml --profile backup run --rm backup.
Docker Compose, מארח אחד
export QUIRE_RELEASE=2026.10.0 # or set it in docker/.env
docker compose -f docker/compose.yaml pull # or build
docker compose -f docker/compose.yaml run --rm migrate
docker compose -f docker/compose.yaml up -d --no-deps web content collab
docker compose -f docker/compose.yaml up -d --no-deps worker schedulerהסדר מכוון:
- תחילה מיגרציה, בעוד הגרסה הישנה ממשיכה לטפל בתעבורה. מיגרציות הרחבה אינן נראות לה.
- אחר כך שכבת האינטרנט. עם קבלת SIGTERM כל תהליך אינטרנט משנה את
/readyzלמצבdraining, מסיים בקשות פעילות בתוך 30 שניות, סוגר זרמים עם הנחיה להתחבר מחדש ויוצא.stop_grace_periodמוגדר ל-40 שניות, כך ש-Compose אינו קוטע ניקוז בריא. - לבסוף העובדים, כך שמבנה האירוע החדש נוצר לפני שהצרכן החדש מצפה לו. העובדים מפסיקים להביא משימות מיד ומקבלים 120 שניות; משימה שאינה יכולה להסתיים נלקחת שוב במקום אחר, וזה בטוח משום שכל משימה idempotent. המתזמן מעביר את ההובלה בטיק הבא.
במארח יחיד Compose מחליף כל קונטיינר בתורו, ולכן יש הפסקה קצרה לכל שירות. כדי למנוע הפסקה, הפעילו שני קונטיינרים של שכבת האינטרנט מאחורי proxy משלכם (קובץ override שמוסיף שירות אינטרנט שני ללא יציאת port ציבורית), וצרו אותם מחדש אחד בכל פעם; לפני המעבר לבא, המתינו שהקודם ידווח שהוא בריא.
כמה מארחים או מתזמר
השתמשו באותו סדר: הריצו מיגרציה פעם אחת ממשימה יחידה, העבירו את שכבת האינטרנט עם
surge של אחד ו-unavailable של אפס, ואז את העובדים. הגדירו בדיקות מוכנות ב-/readyz
ובדיקות חיוניות ב-/healthz.
במסדי נתונים ייעודיים ל-tenants שלב migrate עושה את שניהם: תחילה הוא ממגר את
מסד הנתונים לניהול, אחר כך כל מסד שמופיע ב-ops.tenant_database, אחד בכל פעם ותחת
נעילה משלו. כשל במסד של tenant אחד אינו עוצר את האחרים. לאחר השלמת כולם הוא משווה
את יומני המיגרציה ויוצא עם מצב שאינו אפס אם לא הוחלו בכל מסד בדיוק אותן מיגרציות
כמו במסד הניהול; הוא מציין כל מסד שנמצא מאחור או מלפנים. אותה פקודה מתקינה את
טבלאות התור בכל מסד, משום שהעובד צורך את המשימות של tenant מוצמד במקום שבו נכתבו.
bun apps/worker/src/migrate.ts # what the Compose step runs
bun run db:migrate:all # the same, from a checkoutלכל מסד נתונים ייעודי מתחברים באמצעות השם שבו הוא רשום. מסד שרשום בתור
env:QUIRE_DB_NORTHWIND_URL זקוק ל:
| משתנה | משמש עבור |
|---|---|
QUIRE_DB_NORTHWIND_URL |
תפקיד היישום, עבור שכבת האינטרנט והעובד |
QUIRE_DB_NORTHWIND_URL_MIGRATOR |
תפקיד הממגר, עבור הפקודה הזאת ועבור העברות |
QUIRE_DB_NORTHWIND_URL_SUPERUSER |
אופציונלי: החלה מחדש של bootstrap (roles, schemas, helpers) לפני המיגרציה |
מסד רשום ללא חיבור _MIGRATOR מדווח ככשל ולעולם אינו מדולג. אפשר להעביר את שכבת
האינטרנט לאחר שמסד הניהול הושלם. איחור של שעה במסד tenant יוצר אזהרה; איחור של יום
מפעיל התראת pager.
pgvector
ממיגרציה 0264 ואילך מאגר ה-grounding משתמש באינדקס pgvector HNSW אם השרת כולל את
ההרחבה; שירות postgres של Compose נבנה איתה (docker/postgres.Dockerfile).
הפקודה migrate הראשונה לאחר החלפת התמונות יוצרת את ההרחבה באמצעות bootstrap של
superuser, ואחר כך 0264 מוסיפה עמודת vector מחושבת ובונה את האינדקס. הוספת העמודה
כותבת מחדש את app.ai_chunk פעם אחת תחת נעילה בלעדית, לכן בקשות grounding ממתינות;
דבר אחר אינו נוגע בטבלה הזאת.
בשרת ללא pgvector, מיגרציה 0264 רושמת הודעה ואינה משנה דבר, והחיפוש נשאר מדויק.
עם pgvector בגרסה ישנה מ-0.8, העמודה והאינדקס נבנים אך החיפוש נשאר מדויק עד לשדרוג
ההרחבה (alter extension vector update), כי סריקות HNSW מסוננות זקוקות לסריקות
איטרטיביות שהופיעו ב-0.8. כדי להפעיל זאת מאוחר יותר בשרת שאין בו pgvector, התקינו
את ההרחבה, הריצו שוב bootstrap (או create extension vector כ-superuser), ואז
התחברו כ-quire_migrator:
set maintenance_work_mem = '1GB'; -- the HNSW build is much faster in memory
select ops.ai_chunk_enable_vector_index();הפעולה idempotent ומחזירה enabled או unavailable. הריצו אותה גם בכל מסד נתונים
ייעודי של tenant.
חזרה לאחור
תמיד אפשר להחזיר לאחור את הקוד: הגדירו את QUIRE_RELEASE לתג הקודם והריצו שוב
up -d. הדבר עובד מפני שהסכמה תואמת לשני הכיוונים בתוך גרסה.
החזרת הסכמה לאחור אינה מוצעת. מה שאי אפשר לבטל ואיך לשחזר בעקבותיו:
| לא ניתן לביטול | שחזור |
|---|---|
| מיגרציית contract שהסירה עמודה | שחזור לנקודת זמן שלפני ההסרה למסד חדש, חילוץ ומיזוג |
| שינוי נתונים במקום | אותו תהליך ואז התאמת הכתיבות מאז |
| webhooks ואירועים שנשלחו | אירועים מפצים, לעולם לא מחיקה |
| דוא״ל שנשלח | אדם כותב הודעת המשך |
| שרשרת הגיבוב של הביקורת | לעולם אינה נכתבת מחדש; מוסיפים רשומת תיקון |
לכן מיגרציית contract יוצאת לבדה: כך לשחזור יש גבול ברור.
בדיקת השדרוג
docker compose -f docker/compose.yaml ps # every service healthy
curl -fsS http://localhost:8080/readyz # ready, and what is configured
docker compose -f docker/compose.yaml logs migrate # the migrations applied