---
title: "Downtime ছাড়া upgrade"
description: "নিজে host করা Quire-কে downtime ছাড়া upgrade করুন।"
image: "https://docs.quirelms.com/og.png"
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.quirelms.com/bn/llms.txt
> Use this file to discover all available pages before exploring further.

# Downtime ছাড়া upgrade

<span id="upgrading-without-downtime"></span>

নিয়মগুলো `docs/architecture/23-ops.md`-এর section 7 এবং `docs/architecture/07-data.md`-এর section 4.1-এ আছে। এখানে প্রক্রিয়াটি দেওয়া হলো।

## যে নিশ্চয়তা upgrade নিরাপদ করে <!--quire:the-guarantee-that-makes-it-safe-->

**Release R schema R এবং schema R minus one—দুটির সঙ্গেই সঠিকভাবে চলে।** প্রতিটি schema change-কে expand, transition ও contract-এ ভাগ করা হয়:

1. **Expand**: নতুন column, table বা index যোগ করুন। পুরোনো code সেটি উপেক্ষা করে।
2. **Transition**, অন্তত একটি release ধরে: নতুন code দুই রকম গঠনেই লেখে ও নতুনটি পড়ে; আবার শুরু করা যায় এমন job পুরোনো row পূরণ করে।
3. **Contract**: পরের কোনো release-এ শুধু পুরোনো গঠন বাদ দিন।

তাই rolling upgrade-এর প্রতিটি মুহূর্তে পুরোনো ও নতুন process একই database ভাগ করে ব্যবহার করতে পারে। Down migration নেই: এক ঘণ্টা আগে কোনো column বাদ দিলে ওই ঘণ্টায় লেখা row ফিরিয়ে আনা যাবে না।

প্রতিটি release-এ `schema-compat` CI job নতুন schema-র বিরুদ্ধে আগের release-এর test চালিয়ে এই নিশ্চয়তা পরীক্ষা করে।

## শুরু করার আগে <!--quire:before-you-start-->

1. Release note পড়ুন। Maintenance window লাগবে এমন release-এ সর্বোচ্চ একটি অনুমানসহ তা বলা থাকে।
2. Restore drill চালান অথবা নিশ্চিত করুন এই release-এর জন্য সফলভাবে চালানো হয়েছে ([backup-restore.md](/bn/ops/backup-restore/))। Drill ব্যর্থ হলে upgrade করা যাবে না।
3. Base backup নিন: `docker compose -f docker/compose.yaml --profile backup run --rm backup`।

## Docker Compose, একটি host <!--quire:docker-compose-one-host-->

```sh
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
```

ক্রমটি ভেবেচিন্তে নির্ধারণ করা হয়েছে:

1. **আগে migrate**, পুরোনো release traffic পরিবেশন করার সময়। Expand migration পুরোনো release-এর কাছে অদৃশ্য।
2. **এরপর web tier।** SIGTERM পেলে প্রতিটি web process `/readyz`-এ `draining` দেখায়, চলমান request সর্বোচ্চ 30 সেকেন্ডে শেষ করে, reconnect hint-সহ stream বন্ধ করে এবং বেরিয়ে যায়। `stop_grace_period` 40 সেকেন্ড, যাতে সুস্থ drain কখনো Compose কেটে না দেয়।
3. **সবশেষে worker**, যাতে নতুনতম consumer তা আশা করার আগেই নতুনতম event shape তৈরি হয়। Worker সঙ্গে সঙ্গে fetch বন্ধ করে এবং 120 সেকেন্ড পায়; কোনো job শেষ করা না গেলে অন্য জায়গায় আবার fetch হয়, যা নিরাপদ কারণ প্রতিটি job idempotent। পরবর্তী tick-এ scheduler নেতৃত্ব হস্তান্তর করে।

এক host-এ Compose একটির পর একটি container বদলায়, তাই প্রতিটি service-এ অল্প সময়ের বিরতি থাকে। একেবারেই বিরতি না চাইলে নিজের proxy-র পেছনে দুটি web container চালান (override file-এ প্রকাশিত port ছাড়া দ্বিতীয় web service যোগ করে), এবং একবারে একটি করে recreate করুন; পরেরটি করার আগে প্রতিটি সুস্থ হয়েছে বলে জানানো পর্যন্ত অপেক্ষা করুন।

## একাধিক host বা orchestrator <!--quire:several-hosts-or-an-orchestrator-->

একই ক্রম ব্যবহার করুন: একটি job থেকে একবার migrate করুন, তারপর surge one ও unavailable zero রেখে web tier roll করুন, তারপর worker। Readiness probe `/readyz`-এ এবং liveness probe `/healthz`-এ দিন।

নির্দিষ্ট tenant database থাকলে `migrate` ধাপে দুটো কাজই হয়: আগে control database migrate হয়, তারপর `ops.tenant_database`-এ তালিকাভুক্ত প্রতিটি database আলাদা lock-এর অধীনে একবারে একটি করে migrate হয়। একটি tenant database-এ ব্যর্থতা অন্যগুলোকে থামায় না। সব database শেষ হলে migration ledger তুলনা করে; প্রতিটিতে control database-এর ঠিক একই migration না চললে কোনটি পিছিয়ে বা এগিয়ে তা উল্লেখ করে non-zero status-এ শেষ হয়। একই command প্রতিটি database-এ queue table-ও install করে, কারণ worker নির্দিষ্ট tenant-এর job যে database-এ লেখা, সেখান থেকেই নেয়।

```sh
bun apps/worker/src/migrate.ts   # what the Compose step runs
bun run db:migrate:all                            # the same, from a checkout
```
সাধারণ মাইগ্রেশন এবং প্রথমবারের সেটআপ `ops.platform_policy_version`-এ Quire অপারেটরের প্রামাণিক ইংরেজি আইনি নথিও ইনস্টল করে। ইনস্টলারটি আইডেমপোটেন্ট: শুধু অনুপস্থিত ইংরেজি বডি এবং মাইগ্রেশনে সিড করা হওয়া নিখুঁত প্লেসহোল্ডার বডি প্রতিস্থাপিত হয়। সিডগুলো আর্কাইভ করা হয় এবং নতুন প্রকাশিত সংস্করণ যোগ করা হয়; ঐতিহাসিক গ্রহণের রেফারেন্স ও বডি সংরক্ষিত থাকে। অপারেটরের সত্যিকারের লেখা যেকোনো সংস্করণ, খসড়াসহ, সংরক্ষিত থাকে এবং প্ল্যাটফর্মের নীতি কনসোল দিয়ে পরিচালনা করতে হয়। এই কাটওভারে টেন্যান্ট নীতির নথি, সংস্করণ বা সম্মতি কখনও বদলানো হয় না। এটি অপারেটরের লেখা প্রকাশ, আইনি স্বীকৃতি নয় বা স্বয়ংক্রিয়ভাবে প্রতিশ্রুতি পূরণ নয়।


প্রতিটি নির্দিষ্ট database নিবন্ধনের সময় যে নামে দেওয়া হয়েছে সেটি দিয়ে পৌঁছানো হয়। `env:QUIRE_DB_NORTHWIND_URL` নামে নিবন্ধিত database-এর জন্য লাগবে:

| Variable | কী কাজে লাগে |
| --- | --- |
| `QUIRE_DB_NORTHWIND_URL` | Application role, web tier ও worker-এর জন্য |
| `QUIRE_DB_NORTHWIND_URL_MIGRATOR` | Migrator role, এই command ও স্থানান্তরের জন্য |
| `QUIRE_DB_NORTHWIND_URL_SUPERUSER` | ঐচ্ছিক: migration-এর আগে bootstrap (role, schema, helper) আবার প্রয়োগ করে |

`_MIGRATOR` connection নেই এমন নিবন্ধিত database-কে failure হিসেবে জানানো হয়, কখনো বাদ দেওয়া হয় না। Control database migration শেষ হলেই web tier roll করা যায়। Tenant database এক ঘণ্টা পিছিয়ে থাকলে warning, এক দিন হলে page পাঠানো হয়।

## pgvector <!--quire:pgvector-->

Migration 0264 থেকে grounding corpus server-এ extension থাকলে pgvector HNSW index ব্যবহার করে; Compose-এর `postgres` service-এ এটি থাকে (`docker/postgres.Dockerfile`)। Image বদলানোর পর প্রথম `migrate` superuser bootstrap দিয়ে extension তৈরি করে, এরপর 0264 generated vector column যোগ করে ও index তৈরি করে। Column যোগ করতে exclusive lock-এ একবার `app.ai_chunk` rewrite হয়, তাই grounding request-গুলো অপেক্ষা করে; আর কিছু ওই table-এ হাত দেয় না।

pgvector নেই এমন server-এ 0264 notice log করে, কিন্তু কোনো পরিবর্তন করে না; retrieval exact-ই থাকে। 0.8-এর পুরোনো pgvector-এ column ও index তৈরি হয়, কিন্তু extension upgrade (`alter extension vector update`) না হওয়া পর্যন্ত retrieval exact থাকে, কারণ filtered HNSW scan-এর জন্য 0.8-এর iterative scan দরকার। পরে extension নেই এমন server-এ এটি চালু করতে extension install করে bootstrap আবার চালান (অথবা superuser হিসেবে `create extension vector`), তারপর `quire_migrator` হিসেবে:

```sql
set maintenance_work_mem = '1GB';  -- the HNSW build is much faster in memory
select ops.ai_chunk_enable_vector_index();
```

এটি idempotent, এবং `enabled` অথবা `unavailable` ফেরত দেয়। অন্য dedicated tenant database-গুলোতেও এটি চালান।

## Rollback <!--quire:rolling-back-->

**Code** rollback সবসময় করা যায়: `QUIRE_RELEASE` আগের tag-এ সেট করে আবার `up -d` চালান। একই release-এর মধ্যে schema দুই দিকেই compatible বলে এটি কাজ করে।

**Schema** rollback দেওয়া হয় না। যেগুলো ফেরানো যায় না এবং সেগুলো থেকে কীভাবে সেরে উঠবেন:

| ফেরানো যায় না | পুনরুদ্ধার |
| --- | --- |
| Column বাদ দেওয়া contract migration | বাদ দেওয়ার আগের সময়ে point-in-time restore করে নতুন database-এ তুলুন, merge করুন |
| Data-তে সরাসরি পরিবর্তন | একইভাবে restore, তারপর পরের write-গুলো মিলিয়ে নিন |
| পাঠানো webhook ও event | Deletion নয়, তার ক্ষতিপূরণমূলক event তৈরি করুন |
| পাঠানো email | একজন মানুষ পরবর্তী বার্তা লিখবেন |
| Audit hash chain | কখনো rewrite নয়; correction entry append করুন |

এই কারণেই contract migration একাই release হয়: restore-এ তখন পরিষ্কার সীমা থাকে।

## Upgrade পরীক্ষা <!--quire:checking-the-upgrade-->

```sh
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
```

Source: https://docs.quirelms.com/bn/ops/upgrade/index.mdx
