Repository navigation
feat(dev): checkouts of one app get their own local databases and buckets, and prisma dev stops its Postgres servers on exit - #356
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…ates, with stop and start The Postgres emulator no longer knows apps. A client creates a database instance with free-form labels, an optional requested port and the path it resolved `@prisma/dev` from; the emulator generates the id, starts a `@prisma/dev` server named after it and stores the labels verbatim. Every operation is by id, and GET /instances lists them all. Stop shuts a server down and keeps its data and its port; start brings it back on the same port with the same data. A database keeps its port until it is deleted, because its URL is in dependents' environments. Delete removes the server's data. `@prisma/dev` keeps a server's data in its own data directory, outside the emulators directory, under the server's name. State from the app-keyed version is removed on load, and its servers' data is deleted on the first request that brings a `@prisma/dev` module, unless another live process still serves one. A failed create removes the directory its start leaked. Temporary adaptation until the directory's record covers databases: the local Database provider finds its instance by the labels it wrote, and teardown deletes the instances labelled with the directory and app. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…per-bucket credentials The bucket emulator no longer knows apps. A client creates a bucket instance with free-form labels and the data root its objects live in; the emulator generates the id, which is also the bucket's name on the S3 wire (`bkt-<16 hex digits>`, since an S3 bucket name allows no underscore), and stores the labels and data root verbatim. Credentials are registered per bucket, and a request is verified only against its target bucket's own keys. GET /_pcdev/instances lists every bucket. Deleting a bucket forgets it and its credentials; its objects stay in its data root. State from the app-keyed version is discarded on load. The path-segment rules and the app-keyed instance names are gone with the routes that used them. Temporary adaptation until the directory's record covers buckets: the local Bucket provider finds its instance by the labels it wrote, and teardown deletes the instances labelled with the directory and app. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…s per directory
The directory's emulator-instances.json now holds every app run from the
directory: `{ current, apps: { <app>: { nodes: { <address>:
{ kind, id, port? } } } } }`, where a node is a Compute instance, a
database or a bucket. A single-app record from the previous version
reads as that one app and is rewritten on the next write.
The emulators hook starts the emulators the topology uses, makes the app
the directory's current app, and ensures every node's instance in graph
order: a recorded instance is reused, a stopped database is started, and
a missing one is created again on its remembered port. Starting recorded
databases before converge closes the warm-start gap where Alchemy finds
nothing to change and never calls the Database provider.
Switching apps now stops the previous app's services and databases and
keeps them recorded, so switching back resumes them with their data and
ports; the [dev] line says so. --fresh deletes the current app's
instances of every kind and its entry, and its part of the dev
directory, leaving other apps' entries and bucket objects alone. Bucket
objects therefore live under `.prisma-composer/dev/buckets/<app>/`. When
`prisma dev` ends, the attachment's stopServices stops the app's
databases as well as its service processes.
The Database, Connection, Bucket and BucketAccessKey providers reach
their instances through the record; the label lookups are gone. A
Database or Bucket whose recorded instance changed asks for an update,
and the local OrmMigration provider asks for one when the database is
not at its target by its marker, so a database created again empty is
migrated even though its URL is unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
… the multi-app record ADR-0052 now covers all three emulators: databases and buckets are instances keyed by generated ids with labels never read, the record holds every app run from a directory with `current` naming the last one, switching apps stops the previous app's instances and keeps them, and `--fresh` deletes only the current app's. It records why `prisma dev` stops its database servers when it ends and why the hook starts them before converge, and why a database created again empty is migrated although its URL is unchanged. local-dev.md describes the Postgres and bucket instances, the multi-app record and how each part of dev uses it, stopping on exit, and where a database's and a bucket's data live. The "still keyed by the app" caveats are gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…stops Postgres on exit The running-locally guide and the core-concepts skill now say that two checkouts of one app have separate databases and buckets as well as services, that ending `prisma dev` stops the app's Postgres servers and keeps their data and ports, that a re-created database replays its migrations, and that running a different app from a directory stops the previous one's instances and keeps them. The note that the emulators directory does not isolate Postgres is replaced by where a database's data lives. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…what they are - The core attachment seam `stopServices` is now `stopApp`: it stops everything the target runs for the app, databases included, and no longer mirrors `startServices`, which still starts only services. - The record's node kinds are `service`, `database` and `bucket`, all node kinds, so nothing translates `compute` into "service" for users. A single-app record from S1a, which called services `compute`, reads them as `service`. - The Compute client's types are `ServiceInstanceInfo`, `CreateServiceRequest` and `ServiceInstanceStatus`, beside the database and bucket ones. - One helper, `resourceName`, gives a database's and a bucket's resource name; the lowering and the emulators hook both use it, and the local providers refuse a resource without a name instead of recording it under its Alchemy resource id. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…atabases with the caller's @prisma/dev
- Deleting a database loads `@prisma/dev` from the path the caller
sends, so `--fresh` still deletes the data after an upgrade removed
the copy the database was created with. DELETE /instances/<id>
accepts an optional `{ prismaDevModulePath }`.
- A failure while the emulators hook ensures the app's instances stops
what that run started, best effort, then reports the failure.
- Stopping the app attempts both the service and the database stop and
reports the first failure after both, so a failed service stop never
leaves the database servers running.
- The Postgres emulator writes its state before acknowledging a create
or a delete.
Tests: the local OrmMigration diff against a real Postgres (no marker
asks for an update, at the target asks for nothing, unreachable asks for
an update); the attachment's stopApp stops the app's database servers
and keeps their ports; --fresh's file removal on a temporary directory;
the legacy cleanup leaving a server another live process serves alone
until it exits; a delete after the creating module copy is gone; the
module path under the marker directory in the state test; the hook's
failure path. The integration script asserts the database is stopped and
its port closed after the first Ctrl-C. The extension's module mocks now
apply only while their own file's tests run, since bun's mock.module is
global to the run.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…and fix the ADR-0041 summary - The running-locally guide and the core-concepts skill show the port-change line for a database as well as a service, and say that a re-created Prisma ORM database replays its migrations while a rawPostgres() one stays empty. - ADR-0052 and local-dev.md show the record's `service` kind, and local-dev.md says how S1a's `compute` nodes are read and that a database's and bucket's key comes from one helper. - The ADR index's ADR-0041 summary says the Postgres emulator hosts one `@prisma/dev` server per database instance. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
|
✅ Gizmo reviewed 9ea57c1 — posted 0 inline comment(s) this pass. Open findings: none Change walkthrough
Emulator instances (dev-emulators). The Postgres emulator gains stop/start/delete: stopping closes a Dev record and hook (local-target). The per-directory record now keys every node of every app ( Migration re-run. Because a re-created database is empty on an unchanged URL (Alchemy sees nothing to diff), the local Compute emulator concurrency. A start whose child process has already exited is no longer joined by a concurrent resume or identical PUT; those start the service again instead of waiting on a doomed start. The poll interval is exposed as Docs and skills. ADR-0052 now covers all three emulators, the local-dev design doc records the new concurrency rule, and the skill documents platform |
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configuration
Comment |
commit: |
…art stops the whole app Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Brings in the `listens: false` deployment property. The one conflict, in the
core-concepts skill, keeps this branch's description of per-directory
databases and buckets and adds the sentence about services declared with
`compute({ ..., listens: false })`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…emulator-data-instances
Bucket objects moved from `.prisma-composer/dev/buckets/<bucket>/` to `.prisma-composer/dev/buckets/<app>/<bucket>/`, so the bucket round-trip proof waited for a file that never appeared there. It now reads the app's name from the directory's `emulator-instances.json`, which records the current app, and checks and drops files under that app's bucket directory. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Brings in the fix that a start does not wait for one whose process has exited, and main. Conflicts: the local-target manifest keeps this branch's dev dependencies at main's version, 0.30.0; the stage database keeps this branch's resourceName(id) and gains main's logical id. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Brings in the readiness tests' own port range. The one conflict keeps this branch's ServiceInstanceInfo type and adds the get-port import. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Brings in the --ready-poll-ms tests for a start that must not join a dead in-flight start. No conflicts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Brings in the removal of a repeated test assertion. Signed-off-by: Will Madden <madden@prisma.io> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Brings in #353's own port range for the readiness tests; the test file keeps the instance-keyed version. No other changes. Signed-off-by: Will Madden <madden@prisma.io> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Linked issue
n/a. Part of the local-dev work that adds
prisma dev url,prisma dev stopandprisma emulator list(plan in.drive/projects/emulator-commands/).Summary
Two checkouts of the same app now get separate local databases and buckets, and stopping
prisma devnow stops its Postgres servers too:Decisions:
prisma devends, it stops the app's Postgres servers as well as its service processes. Data stays.ADR-0052 is extended to cover all three emulators.
Background
prisma devruns your app against local stand-ins for Prisma Cloud, called emulators. They are long-lived processes shared by everything on the machine:#354 changed the Compute emulator to run instances under ids it generates, with Composer recording in each directory (
.prisma-composer/dev/emulator-instances.json) which instance runs which service. The Postgres and bucket emulators were still keyed by app name, so two checkouts of one app shared a database and a bucket, and a--freshin either wiped both.Databases and buckets become instances
db_<hex>) and its own Postgres server named after that id. New operations: stop closes the server and keeps its data and port; start brings it back on the same port with the same rows; delete removes the server and its data. A stopped database keeps its port for the same reason a stopped service does: its connection URL is in other services' environments, and a warm start doesn't redeploy.bkt-<hex>; S3 bucket names can't contain_), and that id is its name on the S3 wire. Access keys are registered per bucket. Objects stay as plain files in the project, now under.prisma-composer/dev/buckets/<app>/<bucket>/.As with services, Composer's names reach these emulators only as labels they store but never read.
The record holds every app run from a directory
Each entry under
nodesis keyed by its address, the node's dotted name in the app.#354 deleted the previous app's services when a directory ran a different app. With databases involved, that would delete data whenever someone renamed the root module or passed a different
--name. So now:--freshdeletes only the current app's instances.A record written by #354 is read as a single app.
Starting and stopping
prisma devmakes sure every node of the app has its instance. It reuses recorded instances, re-creates missing ones on their remembered ports, and starts stopped databases. That last part fixes an existing gap. After the Postgres emulator restarted, for example after a reboot, a warmprisma devnever started its databases again, because the deploy engine saw nothing to change.prisma devends, or a start fails partway, the app's databases are stopped along with its services.Old state
Data from before the upgrade is discarded, as with every local-state change:
Testing performed
Against real Compute, Postgres and bucket emulators in temporary emulators directories (skipped on Windows):
--freshremoves only the current app.examples/orm-demo: write a row, Ctrl-C, warm start with the row intact; delete the database through the emulator, then start, and it is re-created and migrated.Also
pnpm build,typecheck,lint,lint:deps,lint:casts, the docs checks, and the local-dev integration scripts, each run on its own.Checklist
git commit -s) per the DCO. The DCO status check will block merge if any commit is missing aSigned-off-by:trailer.feat,fix,chore,docs,refactor,test,build) — PR titles drive the auto-generated release notes.n/aif the change is doc-only / refactor with no behavioural delta).Notes for the reviewer
mainwhen feat(dev): checkouts of one app get their own local services, and a service keeps its port #354 merges.prisma devcalls on exit is nowstopAppinstead ofstopServices, since it also stops databases..drive/projects/emulator-commands/deferred.md: the dev directory'senv.jsonandsecrets.jsonare still shared by every app run there, and--freshwipes them. This was already the case before this PR.Alternatives considered
buckets/<bucket>/. Two apps in one directory would share a bucket's files.Agent: attila-51
🤖 Generated with Claude Code