Skip to content

Commit

Permalink
Refactor: Deployment / Connection management (prisma#1537)
Browse files Browse the repository at this point in the history
Co-authored-by: Jan Piotrowski <[email protected]>
Co-authored-by: mhwelander <[email protected]>
Co-authored-by: Martina Welander <[email protected]>
  • Loading branch information
4 people authored Apr 20, 2021
1 parent c98cfc5 commit 8331781
Show file tree
Hide file tree
Showing 99 changed files with 1,340 additions and 831 deletions.
Empty file modified .husky/pre-commit
100755 → 100644
Empty file.
2 changes: 1 addition & 1 deletion config.js
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ const config = {
},
{
text: 'migrate',
url: 'reference/api-reference/command-reference#prisma-migrate-preview',
url: 'reference/api-reference/command-reference#prisma-migrate',
codeBlock: true,
},
{
Expand Down
2 changes: 1 addition & 1 deletion content/100-getting-started/01-quickstart.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ This should print the following result to your terminal:
]
```

One of the main features of Prisma Client is the ease of working with relations. You can retrieve the `posts` of each user by using the [`include`](../concepts/components/prisma-client/select-fields#include) option. Adjust your code to look as follows:
One of the main features of Prisma Client is the ease of working with relations. You can retrieve the `posts` of each user by using the [`include`](../concepts/components/prisma-client/select-fields#include-relations-and-select-relation-fields) option. Adjust your code to look as follows:

<SwitchTech technologies={['typescript']}>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -666,7 +666,7 @@ async function main() {

This code creates a new `User` record together with new `Post` and `Profile` records using a [nested write](../../concepts/components/prisma-client/relation-queries#nested-writes) query. The `User` record is connected to the two other ones via the `Post.author``User.posts` and `Profile.user``User.profile` [relation fields](../../concepts/components/prisma-schema/relations#relation-fields) respectively.

Notice that you're passing the [`include`](../../concepts/components/prisma-client/select-fields#include) option to `findMany` which tells Prisma Client to include the `posts` and `profile` relations on the returned `User` objects.
Notice that you're passing the [`include`](../../concepts/components/prisma-client/select-fields#include-relations-and-select-relation-fields) option to `findMany` which tells Prisma Client to include the `posts` and `profile` relations on the returned `User` objects.

<SwitchTech technologies={['typescript', '*']}>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,7 @@ async function main() {

This code creates a new `User` record together with new `Post` and `Profile` records using a [nested write](../../concepts/components/prisma-client/relation-queries#nested-writes) query. The `User` record is connected to the two other ones via the `Post.author``User.posts` and `Profile.user``User.profile` [relation fields](../../concepts/components/prisma-schema/relations#relation-fields) respectively.

Notice that you're passing the [`include`](../../concepts/components/prisma-client/select-fields#include) option to `findMany` which tells Prisma Client to include the `posts` and `profile` relations on the returned `User` objects.
Notice that you're passing the [`include`](../../concepts/components/prisma-client/select-fields#include-relations-and-select-relation-fields) option to `findMany` which tells Prisma Client to include the `posts` and `profile` relations on the returned `User` objects.

Run the code with this command:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ metaDescription: "This page gives a high-level overview of what Prisma is and ho

This page gives a high-level overview of what Prisma is and how it works.

If you want to get started with a _practical introduction_ and learn about the Prisma Client API, head over to the [**Quickstart**](../../../getting-started/quickstart-typescript).
If you want to get started with a _practical introduction_ and learn about the Prisma Client API, head over to the [**Quickstart**](../../../getting-started/quickstart-typescript).

To learn more about the _motivation_ for Prisma, check out the [**Why Prisma?**](../why-prisma) page.

Expand Down Expand Up @@ -203,8 +203,8 @@ With **Prisma Migrate**, Prisma's integrated database migration tool, the workfl

To learn more about the Prisma Migrate workflow, see:

* [Developing with Prisma Migrate](../../../guides/application-lifecycle/developing-with-prisma-migrate)
* [Deploying database changes with Prisma Migrate](../../../guides/deployment/deployment#deploying-database-changes-with-prisma-migrate)
- [Deploying database changes with Prisma Migrate](../../../guides/deployment/deploy-database-changes-with-prisma-migrate)
* [Developing with Prisma Migrate](../../../guides/database/developing-with-prisma-migrate)

### SQL migrations and introspection

Expand All @@ -219,5 +219,4 @@ The typical workflow when using **SQL migrations and introspection** is slightly

![Introspection workflow](../../../doc-images/prisma-introspection-development-workflow.png)

To learn more about the introspection workflow, please refer the [introspection section](../../components/introspection).

To learn more about the introspection workflow, please refer the [introspection section](../../components/introspection).
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ Prisma is a lot more than "just another ORM". We are building a database toolkit
- querying (with [Prisma Client](../components/prisma-client))
- data modeling (in the [Prisma schema](../components/prisma-schema))
- migrations (with [Prisma Migrate](../components/prisma-migrate))
- prototyping (via [`prisma db push`](../../reference/api-reference/command-reference#db-push))
- prototyping (via [`prisma db push`](../../reference/api-reference/command-reference#db-push--preview))
- seeding (via [`prisma db seed`](../../reference/api-reference/command-reference#db-seed-preview))
- visual viewing and editing (with [Prisma Studio](https://prisma.io/studio))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ generator client {

Prisma Client JS (prisma-client-js) uses several [engine binaries](https://github.com/prisma/prisma-engines). For example:

- **Prisma Client** uses the [query engine binary file](../prisma-client/query-engine) under the hood to communicate with a database.
- **Prisma Client** uses the [query engine binary file](../prisma-engines/query-engine) under the hood to communicate with a database.
- **Prisma Migrate** uses the migration engine binary file to run schema migrations against a database.

Engines are implemented in Rust and are used by Prisma in the form of executable _binary files_.
Expand All @@ -53,6 +53,8 @@ generator client {

In that case, Prisma detects your operating system and finds the right binary file for it based on the [list of supported operating systems](../../../reference/api-reference/prisma-schema-reference#binarytargets-options) <span class="api"></span>. As you're running Mac OS, the binary file that was compiled for `darwin` will be selected.

> **Note**: The `native` binary target is the default. You can set it explicitly if you wish to [include additional binary targets for deployment to different environments](../../../guides/deployment/deployment-guides/deploying-to-aws-lambda#binary-targets-in-schemaprisma).
### Custom binary targets

You can use environment variables to [specify a custom binary](../../overview/under-the-hood#using-custom-engine-binaries) for one or more engines.
You can use environment variables to [specify a custom binary](../../components/prisma-engines#using-custom-engine-binaries) for one or more engines.
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,7 @@ model Post {
}
```

`@default` attributes typically represent `DEFAULT` values in the underlying database. However, functions like `cuid()` and `uuid()` are provided by Prisma's [query engine](../prisma-client/query-engine/) and are therefore not "visible" in the underlying database schema.
`@default` attributes typically represent `DEFAULT` values in the underlying database. However, functions like `cuid()` and `uuid()` are provided by Prisma's [query engine](../prisma-engines/query-engine/) and are therefore not "visible" in the underlying database schema.

Default values can be:

Expand Down Expand Up @@ -564,7 +564,7 @@ model Post {
}
```

[`cuid()`](../../../reference/api-reference/prisma-schema-reference#cuid) <span class="api"></span> and [`uuid()`](../../../reference/api-reference/prisma-schema-reference#uuid) <span class="api"></span> are implemented by Prisma and therefore are not "visible" in the underlying database schema. You can still use them when using [introspection](../introspection) by [manually changing your Prisma schema](../prisma-client/working-with-prismaclient/use-custom-model-and-field-names) and [generating Prisma Client](../prisma-client/working-with-prismaclient/generating-prisma-client), in that case the values will be generated by Prisma's [query engine](../prisma-client/query-engine)
[`cuid()`](../../../reference/api-reference/prisma-schema-reference#cuid) <span class="api"></span> and [`uuid()`](../../../reference/api-reference/prisma-schema-reference#uuid) <span class="api"></span> are implemented by Prisma and therefore are not "visible" in the underlying database schema. You can still use them when using [introspection](../introspection) by [manually changing your Prisma schema](../prisma-client/working-with-prismaclient/use-custom-model-and-field-names) and [generating Prisma Client](../prisma-client/working-with-prismaclient/generating-prisma-client), in that case the values will be generated by Prisma's [query engine](../prisma-engines/query-engine)

`autoincrement()`, `now` and `dbgenerated()` are always "implemented" on the database-level, meaning they manifest in the database schema and can be recognized through introspection.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ The following example demonstrates how to import and instantiate your [generated

```ts
import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()
// use `prisma` in your application to read and write data in your DB
```

</tab>
Expand All @@ -25,100 +25,29 @@ const prisma = new PrismaClient()

```js
const { PrismaClient } = require('@prisma/client')

const prisma = new PrismaClient()
// use `prisma` in your application to read and write data in your DB
```

</tab>

</TabbedContent>

[`PrismaClient` accepts parameters](../../../../reference/api-reference/prisma-client-reference#prismaclient) <span class="api"></span> that determine:

* [Logging levels](logging)
* [Error formatting](error-formatting)
* [The global behavior of `findUnique` and `findFirst` queries](../../../../reference/api-reference/prisma-client-reference#rejectonnotfound) <span class="api"></span>
> **Tip**: You can further customize `PrismaClient` with [constructor parameters](../../../../reference/api-reference/prisma-client-reference#prismaclient) <span class="api"></span> - for example, set [logging levels](logging) or customize [error formatting](error-formatting).
</TopBlock>

## Use a single shared instance of <inlinecode>PrismaClient</inlinecode>

In long-running applications, we recommend that you:

* ✔ Create **one** instance of `PrismaClient` and re-use it across your application
* ✔ Assign `PrismaClient` to a global variable _in dev environments only_ to [prevent hot reloading from creating new instances](#prevent-hot-reloading-from-creating-new-instances-of-prismaclient)

> **Note**: You [do not need to explicitly `$disconnect()`](connection-management#calling-disconnect-explicitly) in the context of a long-running application, such as a GraphQL server.
Multiple instances of `PrismaClient` results in multiple instances of the [query engine](../query-engine). Each query engine creates a [connection pool](connection-management#connection-pool) with a default pool size of `num_physical_cpus * 2 + 1`. Too many connections may start to slow down your database and eventually lead to the following error:

```
Error in connector: Error querying the database: db error: FATAL: sorry, too many clients already
at PrismaClientFetcher.request
```

To re-use a single instance, create a module that exports a `PrismaClient` object:

```ts file=client.ts
import { PrismaClient } from "@prisma/client"
## The number of `PrismaClient` instances matters

let prisma = new PrismaClient()
Each instance of `PrismaClient` manages a [database connection pool](connection-pool), which means that a large number of clients can **exhaust the database connection limit**:

export default prisma
```

The object is [cached](https://nodejs.org/api/modules.html#modules_caching) the first time the module is imported. Subsequent requests return the cached object rather than creating a new `PrismaClient`:
1. Each client creates its own instance of the [query engine](../../prisma-engines/query-engine).
2. Each query engine creates a [connection pool](connection-pool) with a default pool size of `num_physical_cpus * 2 + 1`.
3. Too many connections may start to **slow down your database** and eventually lead to the following error:

```ts file=app.ts
import prisma from './client'
```
Error in connector: Error querying the database: db error: FATAL: sorry, too many clients already
at PrismaClientFetcher.request
```

async function main() {
const allUsers = await prisma.user.findMany();
}

main();
```

### Prevent hot reloading from creating new instances of `PrismaClient`

Frameworks like [Next.js](https://nextjs.org/) support hot reloading of changed files, which enables you to see changes to your application without restarting. However, if the framework refreshes the module responsible for exporting `PrismaClient`, this can result in **additional, unwanted instances of `PrismaClient` in a development environment**.

As a workaround, you can store `PrismaClient` as a global variable in development environments only, as global variables are not reloaded:

```ts file=client.ts
import { PrismaClient } from "@prisma/client"

declare global {
namespace NodeJS {
interface Global {
prisma: PrismaClient;
}
}
}

let prisma: PrismaClient;

if (process.env.NODE_ENV === "production") {
prisma = new PrismaClient()
} else {
if (!global.prisma) {
global.prisma = new PrismaClient()
}

prisma = global.prisma
}

export default prisma
```

The way that you import and use the client does not change:

```ts file=app.ts
import prisma from './client'

async function main() {
const allUsers = await prisma.user.findMany();
}

main();
```
How to address this challenge depends on whether you are using Prisma in a [long-running application](../../../../guides/performance-and-optimization/connection-management#prismaclient-in-long-running-applications) <span class="guide"></span> or in a [serverless environment](../../../../guides/performance-and-optimization/connection-management#prismaclient-in-serverless-environments) <span class="guide"></span>.
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
---
title: 'Connection management'
metaTitle: 'Connection management (Reference)'
title: 'Connecting and disconnecting'
metaTitle: 'Connecting and disconnecting (Concepts)'
metaDescription: 'This page explains how database connections are handled with Prisma Client and how to manually connect and disconnect your database.'
tocDepth: 2
---

<TopBlock>

Prisma Client connects and disconnects from your data sources using the following two methods:
`PrismaClient` connects and disconnects from your data source using the following two methods:

- [`$connect()`](../../../../reference/api-reference/prisma-client-reference#connect-1) <span class="api"></span>
- [`$disconnect()`](../../../../reference/api-reference/prisma-client-reference#disconnect-1) <span class="api"></span>

In most cases, you do not need to explicitly call either of these methods.
In most cases, you **do not need to explicitly call these methods**. `PrismaClient` automatically connects when you run your first query, creates a [connection pool](connection-pool), and disconnects when the Node.js process ends.

See the [connection management guide](../../../../guides/performance-and-optimization/connection-management) <span class="guide"></span> for information about managing connections for different deployment paradigms (long-running processes and serverless functions).

</TopBlock>

## Calling `$connect()` explicitly
## <inlinecode>$connect()</inlinecode>

It is not necessary to call [`$connect()`](../../../../reference/api-reference/prisma-client-reference#connect-1) <span class="api"></span> thanks to the _lazy connect_ behavior: The `PrismaClient` instance connects lazily when the first request is made to the API (`$connect()` is called for you under the hood).

It is not necessary to call `prisma.$connect()` thanks to the _lazy connect_ behavior: The `PrismaClient` instance connects lazily when the first request is made to the API (`$connect()` is called for you under the hood).
### Calling <inlinecode>$connect()</inlinecode> explicitly

If you need the first request to respond instantly and cannot wait for a lazy connection to be established, you can explicitly call `prisma.$connect()` to establish a connection to the data source:

Expand All @@ -28,17 +33,18 @@ const prisma = new PrismaClient()
await prisma.$connect()
```

## Calling `$disconnect()` explicitly
## <inlinecode>$disconnect()</inlinecode>

When Prisma Client disconnects, it:
When you call [`$disconnect()`](../../../../reference/api-reference/prisma-client-reference#disconnect-1) <span class="api"></span>, Prisma Client:

1. Runs the [`beforeExit` hook](#exit-hooks)
2. Ends child processes
3. Ends the Node.js process _if there are no other active listeners_ (for example, `SIGINT`)
2. Ends the Query Engine child process and closes all connections

In a long-running application such as a GraphQL API, which constantly serves requests, it does not make sense to `$disconnect()` after each request - it takes time to establish a connection, and doing so as part of each request will slow down your application.

> **Tip**: To avoid too _many_ connections, we recommend that you [use a single instance of `PrismaClient` across your application](instantiate-prisma-client).
> **Tip**: To avoid too _many_ connections in a long-running application, we recommend that you [use a single instance of `PrismaClient` across your application](instantiate-prisma-client).
### Calling <inlinecode>$disconnect()</inlinecode> explicitly

One scenario where you should call `$disconnect()` explicitly is where a script:

Expand Down Expand Up @@ -70,26 +76,7 @@ main()
})
```

If the above script runs multiple times in the context of a long-running application _without_ calling `$disconnect()`, [a new connection pool is created with each new instance]() of `PrismaClient`.

## Connection management in serverless environments

In serverless environments, such as AWS Lambda, there are nuances that make it sensible to reuse database connections and _not_ call `$disconnect()`. Refer to the [deployment docs](../../../../guides/deployment/deployment) for more examples.

## Connection pool

When the first connection to the database is opened (either by explicitly calling `$connect()` or running the first query) the query engine first creates a connection pool to store and manage these connections.

The default number of connections is calculated according to this formula: `num_physical_cpus * 2 + 1` where `num_physical_cpus` represents the number of physical CPUs on your machine. If your machine has four physical CPUs, your connection pool will contain nine connections (`4 * 2 + 1 = 9`).

You can also specify the amount of connections as the`connection_limit` parameter on your database connection URL. For example, with the following `datasource` configuration in your [Prisma schema](../../prisma-schema) the connection pool will have exactly five connections:

```prisma
datasource db {
provider = "postgresql"
url = "postgresql://johndoe:mypassword@localhost:5432/mydb?connection_limit=5"
}
```
If the above script runs multiple times in the context of a long-running application _without_ calling `$disconnect()`, a new connection pool is created with each new instance of `PrismaClient`.

## Exit hooks

Expand Down
Loading

0 comments on commit 8331781

Please sign in to comment.