Skip to content

Commit 1df1dca

Browse files
committed
ref(migrations): Align journals with SQL cutover
Drop the retired core and plugin data migration capsules after the bridge-release cutover. Keep mixed journal support for future entries while preserving the current core SQL ledger and upgrade guard.
1 parent 40a6a03 commit 1df1dca

14 files changed

Lines changed: 199 additions & 2406 deletions

File tree

Lines changed: 37 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
---
22
title: "junior upgrade"
3-
description: "Apply Junior schema and data migrations."
3+
description: "Apply Junior and plugin schema or data migrations."
44
type: reference
5-
summary: Move configured SQL schemas and persisted state forward after upgrades.
5+
summary: Bring the configured Junior SQL database up to the installed schema.
66
prerequisites:
77
- /start-here/quickstart/
88
related:
@@ -11,100 +11,65 @@ related:
1111
- /cli/snapshot-create/
1212
---
1313

14-
Use `junior upgrade` after installing a Junior release that includes schema or
15-
data migrations. The command mutates the configured SQL database and state
16-
stores, so run it from the same app environment that has the production state
17-
and SQL environment variables configured for the deployment you are upgrading.
14+
Use `junior upgrade` after installing a new Junior release. The command applies
15+
pending SQL schema and TypeScript data entries from the ordered Drizzle journals
16+
owned by Junior and its enabled plugins.
1817

1918
## Usage
2019

21-
Run it from a project that already has `@sentry/junior` installed:
20+
Run the command from your Junior app:
2221

2322
```bash
2423
pnpm exec junior upgrade
2524
```
2625

27-
The command takes no extra arguments.
26+
The command takes no arguments. It migrates Junior first, then enabled plugins.
27+
Already-applied entries are recognized as up to date and are not rerun.
2828

29-
## What it does
29+
## Upgrade bridge for older databases
3030

31-
`junior upgrade` runs migrations sequentially. Core and plugin migration
32-
directories use Drizzle Kit's ordered journal and may contain either generated
33-
SQL schema migrations or TypeScript data migrations targeting a versioned
34-
host capability API. Current
35-
upgrade work includes:
31+
An existing Junior database without core Drizzle migration history must
32+
complete the `0.107.1` upgrade before upgrading to a later release. Before
33+
starting this bridge, block new ingress, drain active and resumable work, stop
34+
all old workers and queue consumers, and keep them stopped until the later
35+
release is ready. If Junior reports this unsupported database state:
3636

37-
- Apply core and enabled-plugin schema and data journal entries.
38-
- Rewrite retained turn-session records from legacy storage shapes before the
39-
new runtime reads them.
40-
- Move legacy `junior:conversation-work:*` Redis state into the newer conversation record and index state used by the durable worker and dashboard feed.
41-
- Backfill retained conversation records into the shared Junior SQL database. The upgrade requires `DATABASE_URL`.
42-
- Apply the SQL schema cutover and rewrite legacy Pi-message rows into canonical conversation events.
43-
- Repair legacy token and estimated-cost rollups from durable SQL conversation events in bounded batches. Conversations that are active during the repair are left unchanged and can be repaired by rerunning the command after they become idle.
37+
1. Install `@sentry/junior@0.107.1`.
38+
2. Run `pnpm exec junior upgrade` and confirm it completes successfully.
39+
3. Restore the intended Junior version.
40+
4. Run `pnpm exec junior upgrade` again.
41+
5. Deploy the intended version, then restart workers and reopen ingress.
4442

45-
Completed journal entries are tracked individually, and TypeScript migrations
46-
can checkpoint progress for safe retries. Legacy backfills remain idempotent:
47-
rerunning them skips records that were already moved, removes stale legacy
48-
index entries that no longer have a record, and upserts SQL conversation rows.
49-
The conversation-history import paginates through every conversation in the
50-
retained activity index; orphaned or expired Redis keys outside that index are
51-
not treated as retained history. After cutover, SQL owns durable conversation
52-
metadata and event history.
53-
54-
## Hard-cutover upgrade sequence
55-
56-
The canonical conversation-event cutover is not rolling-compatible. Do not run it inside a Vercel build while the previous deployment can still accept work. Use this operator sequence:
57-
58-
1. Block new ingress and enqueueing while leaving the previous release's workers and continuation consumers running.
59-
2. Let existing work drain, then verify that no turns remain running or awaiting resume.
60-
3. Stop every old worker, queue consumer, and heartbeat. Keep the old deployment stopped for the rest of the procedure.
61-
4. Run the upgrade from an operator environment with the production `REDIS_URL`, `JUNIOR_STATE_KEY_PREFIX`, and `DATABASE_URL`.
62-
5. Confirm the history import and message-event seal complete with no missing rows.
63-
6. Run `junior check`, deploy the new release, and only then reopen ingress and start the new workers.
64-
65-
Run the upgrade as a separate operator command:
66-
67-
```bash
68-
pnpm exec junior upgrade
69-
pnpm exec junior check
70-
```
71-
72-
The checkpoint and message-event rewrites fail closed if resumable work remains. After the drain succeeds, each rewrite invalidates stale resume state before changing physical event positions. Checkpoint normalization closes deletion gaps, and the message migration resequences the streams it changes while preserving reporting summaries.
73-
74-
If the command exits nonzero, leave the deployment stopped, correct the reported state, and rerun it. Do not restart workers after only part of the sequence completes.
43+
Fresh databases without Junior tables do not require the bridge release.
7544

7645
## Example output
7746

78-
Typical logs look like this:
47+
An already-current database reports its migrations as existing:
7948

8049
```text
81-
Running Junior upgrade migrations...
82-
Running migration core-migrations...
83-
Finished migration core-migrations: scanned=10 migrated=6 existing=4 missing=0 skipped=0
84-
Running migration plugin-migrations...
85-
Finished migration plugin-migrations: scanned=8 migrated=8 existing=0 missing=0 skipped=0
86-
Junior upgrade complete.
50+
Checking database migrations...
51+
junior: up to date (7 migrations)
52+
junior-github: up to date (4 migrations)
53+
junior-memory: up to date (5 migrations)
54+
junior-scheduler: up to date (2 migrations)
55+
Database is up to date (18 migrations).
8756
```
8857

8958
## Failure behavior
9059

91-
If the configured state store is unavailable or a legacy record is malformed, the CLI exits non-zero and prints the underlying error:
92-
93-
```text
94-
junior command failed: Legacy conversation work state is invalid for slack:C123:1712345.0001
95-
```
96-
97-
Treat that as a deploy blocker for the affected environment. Check `REDIS_URL`, `JUNIOR_STATE_KEY_PREFIX`, `DATABASE_URL`, and the reported legacy record before retrying.
60+
The command exits nonzero when it cannot connect to SQL, encounters an
61+
unsupported pre-Drizzle database, or a migration fails. Treat that as a deploy
62+
blocker: correct the reported database or migration error, then rerun the
63+
command.
9864

9965
## Verification
10066

101-
After running the command:
102-
103-
1. Confirm the final log line includes `Junior upgrade complete`.
104-
2. Confirm `backfill-conversation-events-sql` scanned the complete retained activity index and did not stop at one page.
105-
3. Confirm `move-conversation-messages-to-events` reports `missing=0`. The runtime now uses the copied events. The legacy message table remains available so a later upgrade can recover messages written by old workers during deployment.
106-
4. Run `pnpm exec junior check` before building or deploying the app.
67+
Confirm that the command exits successfully and lists `junior` plus each
68+
enabled plugin that owns migrations. The final line reports whether the
69+
database was already current or how many migrations were applied.
10770

10871
## Next step
10972

110-
Run [junior check](/cli/check/) after the upgrade, then continue with [junior snapshot create](/cli/snapshot-create/) if your plugins need sandbox dependencies.
73+
Run [junior check](/cli/check/) before deploying, then continue with
74+
[junior snapshot create](/cli/snapshot-create/) if your plugins need sandbox
75+
dependencies.

packages/junior-migrations/README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ schema snapshot while preserving the mixed journal order.
3232
Drizzle Kit remains the supported authoring tool. Drizzle ORM's stock
3333
`migrate()` function is not a supported executor for mixed journals because it
3434
requires every entry to have a SQL file. Call `runMigrationJournal` instead and
35-
provide the host database adapter, state adapter, and TypeScript loader. The
35+
provide the host database adapter and, for TypeScript entries, a context and
36+
loader. The
3637
same database adapter drives the journal ledger and is exposed as
3738
`context.database`, so migration files never own connection or driver setup.
3839

@@ -44,8 +45,8 @@ so it must not be used to upgrade an existing installation.
4445

4546
The runner rejects runtime imports of application source, relative modules,
4647
and unversioned `@sentry/junior` modules. Migrations may import the append-only
47-
`@sentry/junior/migration-helpers/v1` surface for parsing primitives, adapters,
48-
stores, and key resolution. One-off migration decisions and data transforms
48+
`@sentry/junior/migration-helpers/v1` surface for stable parsing primitives and
49+
other reusable infrastructure. One-off migration decisions and data transforms
4950
must still remain in the journal entry. Add a new helper or capability version
5051
rather than changing an existing contract.
5152

packages/junior/migrations/README.md

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# SQL migrations
1+
# Migrations
22

33
`src/db/schema.ts` is the Drizzle schema entrypoint. This directory is the
44
append-only history used to bring an existing database to that schema. It
@@ -33,21 +33,20 @@ TypeScript migrations target the versioned migration capability API and must
3333
not import Junior runtime internals or current feature schemas. Their complete
3434
implementation remains in the migration file and uses only the stable
3535
database, state, Redis, and progress capabilities supplied by the runner. The
36-
host database adapter owns connections, drivers, transactions, and locks so
37-
those infrastructure modules are not frozen into every migration.
36+
host database adapter owns connections, drivers, transactions, and locks.
3837

3938
Reusable infrastructure belongs in the append-only
40-
`@sentry/junior/migration-helpers/v1` export. It may provide stable parsers,
41-
stores, adapter projections, and key resolution, but must not implement a
42-
specific data migration. The journal entry remains the only owner of one-off
43-
record transformations.
39+
`@sentry/junior/migration-helpers/v1` export. It may provide stable parsing and
40+
other reusable infrastructure, but must not implement a specific data
41+
migration. The journal entry remains the only owner of one-off record
42+
transformations.
4443

4544
The `0000_initial.sql` baseline represents the schema already deployed by the
46-
pre-Drizzle Junior migration runner. During upgrade, existing installations
47-
adopt that baseline once; new installations execute it normally. All later
48-
migrations are applied by Junior in journal order. Drizzle ORM's stock
49-
`migrate()` function is not compatible with TypeScript entries in this folder.
50-
51-
Migration loading, locking, and legacy baseline adoption live in
52-
`src/chat/conversations/sql/migrations.ts`. Their integration coverage lives in
53-
`tests/integration/conversation-sql.test.ts`.
45+
pre-Drizzle Junior migration runner. Existing databases without core Drizzle
46+
history must first run the documented bridge release; current upgrades do not
47+
infer or adopt legacy state. Fresh databases execute the complete journal
48+
normally. Drizzle ORM's stock `migrate()` function is not compatible with
49+
TypeScript entries in this folder.
50+
51+
Migration loading, locking, and the bridge-release guard live in
52+
`src/chat/conversations/sql/migrations.ts`.

0 commit comments

Comments
 (0)