@aws/nx-plugin-mcp 0.119.0 → 0.121.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/aws-nx-mcp.js +23 -35
- package/docs/guides/astro-docs.mdx +142 -0
- package/docs/guides/connection/py-agent-a2a.mdx +105 -0
- package/docs/guides/connection/py-agent-mcp.mdx +147 -0
- package/docs/guides/connection/react-agui.mdx +240 -0
- package/docs/guides/connection/react-fastapi.mdx +1476 -0
- package/docs/guides/connection/react-py-agent.mdx +198 -0
- package/docs/guides/connection/react-smithy.mdx +1355 -0
- package/docs/guides/connection/react-trpc.mdx +447 -0
- package/docs/guides/connection/react-ts-agent.mdx +198 -0
- package/docs/guides/connection/smithy-rdb.mdx +161 -0
- package/docs/guides/connection/trpc-rdb.mdx +127 -0
- package/docs/guides/connection/ts-agent-a2a.mdx +106 -0
- package/docs/guides/connection/ts-agent-mcp.mdx +144 -0
- package/docs/guides/connection/ts-agent-rdb.mdx +141 -0
- package/docs/guides/connection/ts-mcp-server-rdb.mdx +135 -0
- package/docs/guides/connection.mdx +126 -0
- package/docs/guides/docker-bundling.mdx +403 -0
- package/docs/guides/fastapi.mdx +509 -0
- package/docs/guides/license.mdx +293 -0
- package/docs/guides/nx-generator.mdx +588 -0
- package/docs/guides/py-agent.mdx +483 -0
- package/docs/guides/py-mcp-server.mdx +161 -0
- package/docs/guides/python-lambda-function.mdx +207 -0
- package/docs/guides/python-project.mdx +228 -0
- package/docs/guides/react-website-auth.mdx +216 -0
- package/docs/guides/react-website.mdx +421 -0
- package/docs/guides/runtime-config.mdx +312 -0
- package/docs/guides/terraform-project.mdx +317 -0
- package/docs/guides/trpc.mdx +816 -0
- package/docs/guides/ts-agent.mdx +436 -0
- package/docs/guides/ts-lambda-function.mdx +218 -0
- package/docs/guides/ts-mcp-server.mdx +169 -0
- package/docs/guides/ts-nx-plugin.mdx +159 -0
- package/docs/guides/ts-rdb.mdx +759 -0
- package/docs/guides/ts-smithy-api.mdx +661 -0
- package/docs/guides/typescript-infrastructure.mdx +408 -0
- package/docs/guides/typescript-project.mdx +312 -0
- package/docs/guides/workspace.mdx +181 -0
- package/docs/snippets/agent/architecture.mdx +72 -0
- package/docs/snippets/agent/bedrock-deployment.mdx +172 -0
- package/docs/snippets/agent/runtime-arn.mdx +64 -0
- package/docs/snippets/api/api-architecture.mdx +93 -0
- package/docs/snippets/api/api-choice-note.mdx +6 -0
- package/docs/snippets/api/cors-configuration-cdk-note.mdx +25 -0
- package/docs/snippets/api/cors-configuration-terraform-note.mdx +28 -0
- package/docs/snippets/api/shared-constructs.mdx +38 -0
- package/docs/snippets/api/type-safe-api-integrations.mdx +643 -0
- package/docs/snippets/api/waf-configuration.mdx +37 -0
- package/docs/snippets/connection/a2a-infrastructure.mdx +63 -0
- package/docs/snippets/connection/lambda-rdb-ssl-requirements.mdx +40 -0
- package/docs/snippets/connection/mcp-server-rdb-ssl-requirements.mdx +35 -0
- package/docs/snippets/connection/rdb-api-infrastructure.mdx +72 -0
- package/docs/snippets/connection/react-agent-infrastructure.mdx +61 -0
- package/docs/snippets/connection/strands-agent-rdb-ssl-requirements.mdx +35 -0
- package/docs/snippets/lambda-function/architecture.mdx +36 -0
- package/docs/snippets/lambda-function/deploying-your-function.mdx +118 -0
- package/docs/snippets/mcp/architecture.mdx +58 -0
- package/docs/snippets/mcp/assistant-docs.mdx +10 -0
- package/docs/snippets/mcp/bedrock-deployment.mdx +167 -0
- package/docs/snippets/mcp/config.mdx +13 -0
- package/docs/snippets/mcp/configuration-py.mdx +42 -0
- package/docs/snippets/mcp/configuration-ts.mdx +53 -0
- package/docs/snippets/mcp/observability.mdx +8 -0
- package/docs/snippets/mcp/shared-constructs.mdx +32 -0
- package/docs/snippets/pdk-migration/example/01-migrate-api.mdx +602 -0
- package/docs/snippets/pdk-migration/example/02-migrate-website.mdx +915 -0
- package/docs/snippets/pdk-migration/example/03-migrate-infra.mdx +161 -0
- package/docs/snippets/pdk-migration/example/04-deploy.mdx +229 -0
- package/docs/snippets/pdk-migration/faq/aws-arch.mdx +17 -0
- package/docs/snippets/pdk-migration/faq/cdk-graph.mdx +29 -0
- package/docs/snippets/pdk-migration/faq/infrastructure-python-java.mdx +19 -0
- package/docs/snippets/pdk-migration/faq/pdk-nag.mdx +15 -0
- package/docs/snippets/pdk-migration/faq/pipeline.mdx +15 -0
- package/docs/snippets/pdk-migration/faq/type-safe-api.mdx +310 -0
- package/docs/snippets/pdk-migration/faq/use-of-projen.mdx +15 -0
- package/docs/snippets/prerequisites.mdx +20 -0
- package/docs/snippets/required-prerequisites.mdx +12 -0
- package/docs/snippets/shared-constructs.mdx +40 -0
- package/docs/snippets/tools/acurl.mdx +73 -0
- package/docs/snippets/ts-bundle.mdx +14 -0
- package/package.json +1 -1
- package/src/py/agent/schema.json +1 -1
- package/src/py/fast-api/schema.json +2 -2
- package/src/py/mcp-server/schema.json +1 -1
- package/src/smithy/ts/api/schema.json +2 -2
- package/src/trpc/backend/schema.json +2 -2
- package/src/ts/agent/schema.json +1 -1
- package/src/ts/mcp-server/schema.json +1 -1
|
@@ -0,0 +1,759 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Relational Database
|
|
3
|
+
description: Create a relational database project
|
|
4
|
+
generator: ts#rdb
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
import { FileTree } from '@astrojs/starlight/components';
|
|
8
|
+
import Link from '@components/link.astro';
|
|
9
|
+
import RunGenerator from '@components/run-generator.astro';
|
|
10
|
+
import GeneratorParameters from '@components/generator-parameters.astro';
|
|
11
|
+
import Infrastructure from '@components/infrastructure.astro';
|
|
12
|
+
import NxCommands from '@components/nx-commands.astro';
|
|
13
|
+
import PackageManagerExecCommand from '@components/package-manager-exec-command.astro';
|
|
14
|
+
import Snippet from '@components/snippet.astro';
|
|
15
|
+
import OptionFilter from '@components/option-filter.astro';
|
|
16
|
+
|
|
17
|
+
This generator creates a new relational database project backed by [Amazon Aurora](https://aws.amazon.com/rds/aurora/) (PostgreSQL or MySQL) and [Prisma ORM](https://www.prisma.io/docs/orm). It generates the application code and infrastructure needed to provision and manage a database using AWS CDK or Terraform, with declarative schema definition, automatic migration deployment, and a type-safe ORM client.
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
### Generate a Relational Database
|
|
22
|
+
|
|
23
|
+
You can generate a new relational database project in two ways:
|
|
24
|
+
|
|
25
|
+
<RunGenerator generator="ts#rdb" />
|
|
26
|
+
|
|
27
|
+
### Options
|
|
28
|
+
|
|
29
|
+
<GeneratorParameters generator="ts#rdb" />
|
|
30
|
+
|
|
31
|
+
## Generator Output
|
|
32
|
+
|
|
33
|
+
The generator will create the following project structure in the `<directory>/<name>` directory:
|
|
34
|
+
|
|
35
|
+
<FileTree>
|
|
36
|
+
- prisma
|
|
37
|
+
- models
|
|
38
|
+
- example.prisma Example model definition
|
|
39
|
+
- schema.prisma Main Prisma schema (references models)
|
|
40
|
+
- scripts
|
|
41
|
+
- docker-pull.ts Pulls the database Docker image for local development
|
|
42
|
+
- docker-start.ts Starts a local database container
|
|
43
|
+
- wait-for-db.ts Waits for the local database to be ready
|
|
44
|
+
- src
|
|
45
|
+
- index.ts Project entry point
|
|
46
|
+
- constants.ts Local development connection details and runtime config key
|
|
47
|
+
- prisma.ts Prisma runtime client wrapper
|
|
48
|
+
- utils.ts Runtime config and secret helpers
|
|
49
|
+
- create-db-user-handler.ts Lambda handler used to create the application database user during deployment
|
|
50
|
+
- migration-handler.ts Lambda handler used to run database migrations during deployment
|
|
51
|
+
- .gitignore Git ignore entries including generated Prisma client output
|
|
52
|
+
- Dockerfile Container image definition for the migration handler
|
|
53
|
+
- project.json Project configuration and build targets
|
|
54
|
+
- prisma.config.ts Configuration for Prisma CLI
|
|
55
|
+
</FileTree>
|
|
56
|
+
|
|
57
|
+
### Infrastructure
|
|
58
|
+
|
|
59
|
+
<Snippet name="shared-constructs" />
|
|
60
|
+
|
|
61
|
+
<Infrastructure>
|
|
62
|
+
<Fragment slot="cdk">
|
|
63
|
+
<FileTree>
|
|
64
|
+
- packages/common/constructs/src
|
|
65
|
+
- app
|
|
66
|
+
- dbs
|
|
67
|
+
- \<name>.ts Infrastructure specific to your database
|
|
68
|
+
- core
|
|
69
|
+
- rdb
|
|
70
|
+
- aurora.ts Generic Aurora database construct
|
|
71
|
+
</FileTree>
|
|
72
|
+
</Fragment>
|
|
73
|
+
<Fragment slot="terraform">
|
|
74
|
+
<FileTree>
|
|
75
|
+
- packages/common/terraform/src
|
|
76
|
+
- app
|
|
77
|
+
- dbs
|
|
78
|
+
- \<name>
|
|
79
|
+
- \<name>.tf Module specific to your database
|
|
80
|
+
- core
|
|
81
|
+
- rdb
|
|
82
|
+
- aurora
|
|
83
|
+
- aurora.tf Generic Aurora module
|
|
84
|
+
</FileTree>
|
|
85
|
+
</Fragment>
|
|
86
|
+
</Infrastructure>
|
|
87
|
+
|
|
88
|
+
#### Architecture
|
|
89
|
+
|
|
90
|
+
The deployed database has the following architecture. By default, an [Amazon RDS Proxy](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy.html) sits in front of the Aurora cluster to pool connections and to enable [IAM authentication](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.html) — see [Disable RDS Proxy](#disable-rds-proxy) for the alternative. The architecture is the same whether you select the PostgreSQL or MySQL engine; only the Aurora engine flavor differs.
|
|
91
|
+
|
|
92
|
+
```d2 inline=true
|
|
93
|
+
direction: right
|
|
94
|
+
|
|
95
|
+
app: Application\n(Lambda, Agent, ...) {
|
|
96
|
+
shape: hexagon
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
migrations: Migrations Lambda {
|
|
100
|
+
shape: image
|
|
101
|
+
icon: /nx-plugin-for-aws/icons/aws/lambda.svg
|
|
102
|
+
near: top-right
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
proxy: RDS Proxy {
|
|
106
|
+
shape: image
|
|
107
|
+
icon: /nx-plugin-for-aws/icons/aws/rds.svg
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
aurora: Aurora\n(PostgreSQL or MySQL) {
|
|
111
|
+
shape: image
|
|
112
|
+
icon: /nx-plugin-for-aws/icons/aws/aurora.svg
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
secrets: Secrets Manager\n(DB credentials) {
|
|
116
|
+
shape: image
|
|
117
|
+
icon: /nx-plugin-for-aws/icons/aws/secrets-manager.svg
|
|
118
|
+
near: bottom-right
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
app -> proxy: SQL (IAM auth)
|
|
122
|
+
proxy -> aurora
|
|
123
|
+
migrations -> aurora: Schema migrations
|
|
124
|
+
proxy -> secrets: Master credential rotation
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Local Development
|
|
128
|
+
|
|
129
|
+
### Data Modelling
|
|
130
|
+
|
|
131
|
+
The generated project uses [Prisma ORM](https://www.prisma.io/docs/orm) to define your database schema and generate a type-safe client. The workflow is model-first: add or update Prisma model files under your database project's `prisma/models/` directory, then generate a migration from those model changes.
|
|
132
|
+
|
|
133
|
+
Example `User` model:
|
|
134
|
+
|
|
135
|
+
```ts title="packages/postgres/prisma/models/user.prisma"
|
|
136
|
+
model User {
|
|
137
|
+
id Int @id @default(autoincrement())
|
|
138
|
+
firstName String
|
|
139
|
+
lastName String
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
For more details, see the official [Prisma data modelling guide](https://www.prisma.io/docs/orm/core-concepts/data-modeling#data-modeling-with-prisma-orm).
|
|
144
|
+
|
|
145
|
+
### Generating the Database Client
|
|
146
|
+
|
|
147
|
+
The generator automatically configures the `generate` target to create a type-safe TypeScript Prisma client whenever you build the project. The client is written to `generated/prisma` (added to `.gitignore`).
|
|
148
|
+
|
|
149
|
+
You can also manually generate the client at any time:
|
|
150
|
+
|
|
151
|
+
<NxCommands commands={['generate <your-db-project-name>']} />
|
|
152
|
+
|
|
153
|
+
Use the `prisma` target to run Prisma CLI commands from the workspace root:
|
|
154
|
+
|
|
155
|
+
<NxCommands commands={['run <project>:prisma generate']} />
|
|
156
|
+
|
|
157
|
+
The runtime wrapper in `src/prisma.ts` exports:
|
|
158
|
+
|
|
159
|
+
- `DB_PACKAGE_NAME` - the key used under the `database` runtime config namespace in AWS AppConfig
|
|
160
|
+
- `getPrisma()` - loads database connection settings from AWS AppConfig and creates a Prisma client using IAM authentication
|
|
161
|
+
|
|
162
|
+
The client automatically:
|
|
163
|
+
- Retrieves database configuration from AWS AppConfig using `RUNTIME_CONFIG_APP_ID` environment variable
|
|
164
|
+
- Generates temporary authentication tokens via AWS RDS Signer for IAM authentication
|
|
165
|
+
- Manages SSL/TLS connections with certificate validation
|
|
166
|
+
- Handles connection pooling through persistent database connection pools
|
|
167
|
+
|
|
168
|
+
### Creating Migrations
|
|
169
|
+
|
|
170
|
+
After adding or updating models under `prisma/models/`, use `migrate dev` to generate migration files and apply them to your local database at the same time.
|
|
171
|
+
|
|
172
|
+
The generated `prisma` target automatically starts a local database via Docker before running:
|
|
173
|
+
|
|
174
|
+
<NxCommands commands={['run <project>:prisma migrate dev']} />
|
|
175
|
+
|
|
176
|
+
If you only want to generate the migration files without applying them to the local database, add `--create-only`:
|
|
177
|
+
|
|
178
|
+
<NxCommands commands={['run <project>:prisma migrate dev --create-only']} />
|
|
179
|
+
|
|
180
|
+
This generates a new migration folder in `prisma/migrations` each time your schema changes:
|
|
181
|
+
|
|
182
|
+
<FileTree>
|
|
183
|
+
- prisma
|
|
184
|
+
- migrations
|
|
185
|
+
- 20260405013911_initial_migrations
|
|
186
|
+
- migration.sql
|
|
187
|
+
- migration_lock.toml
|
|
188
|
+
- schema.prisma
|
|
189
|
+
</FileTree>
|
|
190
|
+
|
|
191
|
+
When you deploy the AWS stack, the generated infrastructure automatically applies the generated migrations to the deployed database.
|
|
192
|
+
|
|
193
|
+
### Applying Existing Migrations
|
|
194
|
+
|
|
195
|
+
When you pull migration files created by other developers, use `migrate deploy` to apply those existing migrations to your local database.
|
|
196
|
+
|
|
197
|
+
<NxCommands commands={['run <project>:prisma migrate deploy']} />
|
|
198
|
+
|
|
199
|
+
In this local development flow, `migrate deploy` applies the migration files to your local database; it does not deploy the database to AWS.
|
|
200
|
+
|
|
201
|
+
### Running Prisma Commands
|
|
202
|
+
|
|
203
|
+
The generated `prisma` target exposes the Prisma CLI, so you can use it to run any command supported by Prisma against the local database. See the [Prisma CLI reference](https://www.prisma.io/docs/orm/reference/prisma-cli-reference) for available commands.
|
|
204
|
+
|
|
205
|
+
<NxCommands commands={['run <project>:prisma <prisma-command>']} />
|
|
206
|
+
|
|
207
|
+
### Prisma Studio
|
|
208
|
+
|
|
209
|
+
[Prisma Studio](https://www.prisma.io/studio) is a visual editor for your local database. Use it to browse tables, inspect and edit records, filter data, follow relations, and run raw SQL via the built-in SQL console. It is useful for verifying migrations and seeding test data during development. Launch it with:
|
|
210
|
+
|
|
211
|
+
<NxCommands commands={['run <project>:prisma studio']} />
|
|
212
|
+
|
|
213
|
+
## Connecting to the Database
|
|
214
|
+
|
|
215
|
+
In any TypeScript project, import `getPrisma` from your database package and call it to get a type-safe Prisma client:
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
import { getPrisma } from ':my-scope/db';
|
|
219
|
+
|
|
220
|
+
const prisma = await getPrisma();
|
|
221
|
+
const users = await prisma.user.findMany({ orderBy: { id: 'asc' } });
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
`getPrisma()` returns a lazily-initialised, cached client. Subsequent calls within the same Lambda execution context reuse the existing connection pool rather than opening a new one.
|
|
225
|
+
|
|
226
|
+
The Prisma client exposes fully typed models derived from your `prisma/models/` schema, giving you end-to-end type safety from the database all the way through to your API response.
|
|
227
|
+
|
|
228
|
+
### Connection Generators
|
|
229
|
+
|
|
230
|
+
For specific project types, use the `connection` generator to automatically wire up the database — it handles imports, context injection, and local development dependencies:
|
|
231
|
+
|
|
232
|
+
- <Link path="guides/connection/trpc-rdb">tRPC API → Relational Database</Link>
|
|
233
|
+
- <Link path="guides/connection/smithy-rdb">Smithy API → Relational Database</Link>
|
|
234
|
+
- <Link path="guides/connection/ts-agent-rdb">TypeScript Agent → Relational Database</Link>
|
|
235
|
+
- <Link path="guides/connection/ts-mcp-server-rdb">MCP Server → Relational Database</Link>
|
|
236
|
+
|
|
237
|
+
## Deploying your Database
|
|
238
|
+
|
|
239
|
+
The relational database generator creates CDK or Terraform infrastructure based on your selected `iacProvider`.
|
|
240
|
+
|
|
241
|
+
<Infrastructure>
|
|
242
|
+
<Fragment slot="cdk">
|
|
243
|
+
The CDK construct is created in `common/constructs`. Example usage:
|
|
244
|
+
|
|
245
|
+
```ts title="packages/infra/src/stacks/application-stack.ts"
|
|
246
|
+
import { MyDatabase } from ':my-scope/common-constructs';
|
|
247
|
+
|
|
248
|
+
export class ApplicationStack extends Stack {
|
|
249
|
+
constructor(scope: Construct, id: string, props?: StackProps) {
|
|
250
|
+
super(scope, id, props);
|
|
251
|
+
...
|
|
252
|
+
const db = new MyDatabase(this, 'Db', {
|
|
253
|
+
vpc,
|
|
254
|
+
vpcSubnets: {
|
|
255
|
+
subnetType: SubnetType.PRIVATE_ISOLATED,
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
This provisions an Aurora cluster with RDS Proxy, admin credentials, application database user, runtime config registration, and migration handler.
|
|
263
|
+
|
|
264
|
+
The generated infrastructure creates two database users:
|
|
265
|
+
- **Admin user** - Created during cluster provisioning with credentials stored in AWS Secrets Manager
|
|
266
|
+
- **Application user** - Created via a Lambda custom resource with IAM authentication enabled and full privileges on the application database
|
|
267
|
+
</Fragment>
|
|
268
|
+
<Fragment slot="terraform">
|
|
269
|
+
The Terraform module is created in `common/terraform`. Example usage:
|
|
270
|
+
|
|
271
|
+
```hcl title="packages/infra/src/main.tf"
|
|
272
|
+
module "my_database" {
|
|
273
|
+
source = "../../common/terraform/src/app/dbs/my-database"
|
|
274
|
+
|
|
275
|
+
vpc_id = module.vpc.vpc_id
|
|
276
|
+
database_subnet_ids = module.vpc.private_isolated_subnet_ids
|
|
277
|
+
lambda_subnet_ids = module.vpc.private_subnet_ids
|
|
278
|
+
|
|
279
|
+
tags = local.common_tags
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
This provisions an Aurora cluster with RDS Proxy, admin credentials, create-db-user Lambda, runtime config registration, migration Lambda, and container registry resources.
|
|
284
|
+
|
|
285
|
+
The generated infrastructure creates two database users:
|
|
286
|
+
- **Admin user** - Created during cluster provisioning with credentials stored in AWS Secrets Manager
|
|
287
|
+
- **Application user** - Created via a Lambda function with IAM authentication enabled and full privileges on the application database
|
|
288
|
+
</Fragment>
|
|
289
|
+
</Infrastructure>
|
|
290
|
+
|
|
291
|
+
The application user is automatically created with a random name and IAM authentication. `getPrisma()` is already configured to authenticate as this user using short-lived RDS tokens, so your application code never handles database passwords.
|
|
292
|
+
|
|
293
|
+
Your VPC should include public subnets, private subnets with egress, and private isolated subnets. The database can run in private isolated subnets, while API Lambda functions should run in private subnets with egress so they can reach AWS services such as AppConfig.
|
|
294
|
+
|
|
295
|
+
<Infrastructure>
|
|
296
|
+
<Fragment slot="cdk">
|
|
297
|
+
|
|
298
|
+
```ts title="packages/infra/src/stacks/application-stack.ts"
|
|
299
|
+
const vpc = new Vpc(this, 'Vpc', {
|
|
300
|
+
subnetConfiguration: [
|
|
301
|
+
{
|
|
302
|
+
name: 'public',
|
|
303
|
+
subnetType: SubnetType.PUBLIC,
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
name: 'private_with_egress',
|
|
307
|
+
subnetType: SubnetType.PRIVATE_WITH_EGRESS,
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
name: 'private_isolated',
|
|
311
|
+
subnetType: SubnetType.PRIVATE_ISOLATED,
|
|
312
|
+
},
|
|
313
|
+
],
|
|
314
|
+
});
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
</Fragment>
|
|
318
|
+
<Fragment slot="terraform">
|
|
319
|
+
|
|
320
|
+
```hcl title="packages/infra/src/main.tf"
|
|
321
|
+
module "vpc" {
|
|
322
|
+
source = "terraform-aws-modules/vpc/aws"
|
|
323
|
+
version = "~> 6.0"
|
|
324
|
+
|
|
325
|
+
name = "app"
|
|
326
|
+
...
|
|
327
|
+
public_subnet_names = ["public"]
|
|
328
|
+
private_subnet_names = ["private_with_egress"]
|
|
329
|
+
intra_subnet_names = ["private_isolated"]
|
|
330
|
+
|
|
331
|
+
enable_nat_gateway = true
|
|
332
|
+
single_nat_gateway = true
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
</Fragment>
|
|
337
|
+
</Infrastructure>
|
|
338
|
+
|
|
339
|
+
### Connecting an API to the Database
|
|
340
|
+
|
|
341
|
+
<Infrastructure>
|
|
342
|
+
<Fragment slot="cdk">
|
|
343
|
+
|
|
344
|
+
In your application stack, deploy the API into the same VPC as the database, then call `allowDefaultPortFrom` and `grantConnect` to open the network path and grant IAM `rds-db:connect` permission to each Lambda handler:
|
|
345
|
+
|
|
346
|
+
```ts title="packages/infra/src/stacks/application-stack.ts"
|
|
347
|
+
import { MyDatabase } from ':my-scope/common-constructs';
|
|
348
|
+
|
|
349
|
+
const db = new MyDatabase(this, 'Db', { vpc, ... });
|
|
350
|
+
|
|
351
|
+
const api = new Api(this, 'Api', {
|
|
352
|
+
integrations: Api.defaultIntegrations(this)
|
|
353
|
+
.withDefaultOptions({
|
|
354
|
+
vpc,
|
|
355
|
+
vpcSubnets: { subnetType: SubnetType.PRIVATE_WITH_EGRESS },
|
|
356
|
+
})
|
|
357
|
+
.build(),
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
Object.entries(api.integrations).forEach(([operation, integration]) => {
|
|
361
|
+
db.allowDefaultPortFrom(integration.handler, `Allow ${operation} to connect to the database`);
|
|
362
|
+
db.grantConnect(integration.handler);
|
|
363
|
+
});
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
Deploy the API Lambda functions into a **private subnet with egress** (recommended) or a public subnet, not a private isolated subnet. At runtime, `getPrisma()` retrieves database connection details from AWS AppConfig, which is a public AWS service endpoint. Lambda functions in a private isolated subnet have no outbound internet access and cannot reach AppConfig. Private subnets with egress route outbound traffic through a NAT Gateway which sits in a public subnet.
|
|
367
|
+
</Fragment>
|
|
368
|
+
<Fragment slot="terraform">
|
|
369
|
+
|
|
370
|
+
Pass the database module outputs into your compute module so it can reach the database and read its runtime configuration:
|
|
371
|
+
|
|
372
|
+
```hcl title="packages/infra/src/main.tf"
|
|
373
|
+
module "my_database" {
|
|
374
|
+
source = "../../common/terraform/src/app/dbs/my-database"
|
|
375
|
+
vpc_id = module.vpc.vpc_id
|
|
376
|
+
database_subnet_ids = module.vpc.private_isolated_subnet_ids
|
|
377
|
+
lambda_subnet_ids = module.vpc.private_subnet_ids
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
module "api" {
|
|
381
|
+
source = "..."
|
|
382
|
+
vpc_id = module.vpc.vpc_id
|
|
383
|
+
private_subnet_ids = module.vpc.private_subnet_ids
|
|
384
|
+
|
|
385
|
+
# Allow the API to read runtime config from AppConfig
|
|
386
|
+
appconfig_application_id = module.my_database.appconfig_application_id
|
|
387
|
+
|
|
388
|
+
# Grant rds-db:connect for the application database user
|
|
389
|
+
database_cluster_resource_id = module.my_database.cluster_resource_id
|
|
390
|
+
database_runtime_user = module.my_database.database_runtime_user
|
|
391
|
+
|
|
392
|
+
# Allow network access to the database port
|
|
393
|
+
database_security_group_id = module.my_database.security_group_id
|
|
394
|
+
database_port = module.my_database.cluster_port
|
|
395
|
+
|
|
396
|
+
environment_variables = {
|
|
397
|
+
RUNTIME_CONFIG_APP_ID = module.my_database.appconfig_application_id
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
Deploy the API Lambda functions into **private subnets with egress** (recommended) or public subnets, not private isolated subnets. At runtime, `getPrisma()` retrieves database connection details from AWS AppConfig, which is a public AWS service endpoint. Lambda functions in a private isolated subnet have no outbound internet access and cannot reach AppConfig. Private subnets with egress route outbound traffic through a NAT Gateway which requires a public subnet.
|
|
403
|
+
|
|
404
|
+
Ensure the API Lambda role has `rds-db:connect` on `arn:aws:rds-db:<region>:<account>:dbuser:<cluster_resource_id>/<database_runtime_user>` and AppConfig read permissions, that the API's security group can reach the database security group on the database port, and that the Lambda environment includes `RUNTIME_CONFIG_APP_ID`.
|
|
405
|
+
</Fragment>
|
|
406
|
+
</Infrastructure>
|
|
407
|
+
|
|
408
|
+
:::note
|
|
409
|
+
This example grants every handler in your API access, but if only some handlers need access it's better to configure individually.
|
|
410
|
+
:::
|
|
411
|
+
|
|
412
|
+
### RDS Proxy Configuration
|
|
413
|
+
|
|
414
|
+
The generated infrastructure includes an RDS Proxy by default, which sits between your application and the Aurora cluster. RDS Proxy provides several benefits:
|
|
415
|
+
|
|
416
|
+
- **Connection pooling** - Maintains a pool of database connections that can be shared across application instances, reducing the overhead of establishing new connections
|
|
417
|
+
- **Connection resilience** - Automatically handles failovers and reconnects during Aurora instance replacements or maintenance
|
|
418
|
+
- **IAM authentication** - Supports IAM-based database authentication, eliminating the need to manage database credentials in your application code
|
|
419
|
+
- **Improved security** - Enforces TLS encryption for all connections
|
|
420
|
+
|
|
421
|
+
:::note[Additional Cost]
|
|
422
|
+
RDS Proxy is enabled by default but incurs additional charges on top of the Aurora cluster cost. See [AWS RDS Proxy pricing](https://aws.amazon.com/rds/proxy/pricing/) for details. If you would prefer to disable the proxy, see the section below.
|
|
423
|
+
:::
|
|
424
|
+
|
|
425
|
+
#### Disable RDS Proxy
|
|
426
|
+
|
|
427
|
+
You can disable the RDS proxy as follows:
|
|
428
|
+
|
|
429
|
+
<Infrastructure>
|
|
430
|
+
<Fragment slot="cdk">
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
```ts title="packages/infra/src/stacks/application-stack.ts"
|
|
434
|
+
import { MyDatabase } from ':my-scope/common-constructs';
|
|
435
|
+
|
|
436
|
+
const db = new MyDatabase(this, 'Db', {
|
|
437
|
+
...
|
|
438
|
+
enableRdsProxy: false,
|
|
439
|
+
});
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
When RDS Proxy is disabled, your application connects directly to the Aurora cluster endpoint.
|
|
443
|
+
</Fragment>
|
|
444
|
+
<Fragment slot="terraform">
|
|
445
|
+
|
|
446
|
+
By default, RDS Proxy is enabled. The generated runtime client (`getPrisma()`) automatically connects through the proxy endpoint. You can disable it if needed:
|
|
447
|
+
|
|
448
|
+
```hcl title="packages/infra/src/main.tf"
|
|
449
|
+
module "my_database" {
|
|
450
|
+
source = "../../common/terraform/src/app/dbs/my-database"
|
|
451
|
+
...
|
|
452
|
+
enable_rds_proxy = false
|
|
453
|
+
}
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
When RDS Proxy is disabled, your application connects directly to the Aurora cluster endpoint.
|
|
457
|
+
</Fragment>
|
|
458
|
+
</Infrastructure>
|
|
459
|
+
|
|
460
|
+
<Snippet name="connection/lambda-rdb-ssl-requirements" parentHeading="Disable RDS Proxy" />
|
|
461
|
+
|
|
462
|
+
The generated infrastructure can be customised to match your workload requirements. The following examples demonstrate a few common customisation options available.
|
|
463
|
+
|
|
464
|
+
### Cluster Instances
|
|
465
|
+
|
|
466
|
+
Configure the writer and reader instances for your Aurora cluster.
|
|
467
|
+
|
|
468
|
+
<Infrastructure>
|
|
469
|
+
<Fragment slot="cdk">
|
|
470
|
+
|
|
471
|
+
```ts title="packages/infra/src/stacks/application-stack.ts"
|
|
472
|
+
import { MyDatabase } from ':my-scope/common-constructs';
|
|
473
|
+
|
|
474
|
+
const db = new MyDatabase(this, 'Db', {
|
|
475
|
+
...
|
|
476
|
+
writer: ClusterInstance.serverlessV2('writer'),
|
|
477
|
+
readers: [ClusterInstance.serverlessV2('reader')],
|
|
478
|
+
});
|
|
479
|
+
```
|
|
480
|
+
</Fragment>
|
|
481
|
+
<Fragment slot="terraform">
|
|
482
|
+
|
|
483
|
+
```hcl title="packages/infra/src/main.tf"
|
|
484
|
+
module "my_database" {
|
|
485
|
+
source = "../../common/terraform/src/app/dbs/my-database"
|
|
486
|
+
...
|
|
487
|
+
instance_count = 2 # 1 writer + 1 reader
|
|
488
|
+
}
|
|
489
|
+
```
|
|
490
|
+
</Fragment>
|
|
491
|
+
</Infrastructure>
|
|
492
|
+
|
|
493
|
+
### Serverless Capacity
|
|
494
|
+
|
|
495
|
+
Control Aurora Serverless v2 scaling limits to match your workload.
|
|
496
|
+
|
|
497
|
+
<Infrastructure>
|
|
498
|
+
<Fragment slot="cdk">
|
|
499
|
+
|
|
500
|
+
```ts title="packages/infra/src/stacks/application-stack.ts"
|
|
501
|
+
import { MyDatabase } from ':my-scope/common-constructs';
|
|
502
|
+
|
|
503
|
+
const db = new MyDatabase(this, 'Db', {
|
|
504
|
+
...
|
|
505
|
+
serverlessV2MinCapacity: 0.5,
|
|
506
|
+
serverlessV2MaxCapacity: 8,
|
|
507
|
+
});
|
|
508
|
+
```
|
|
509
|
+
</Fragment>
|
|
510
|
+
<Fragment slot="terraform">
|
|
511
|
+
|
|
512
|
+
```hcl title="packages/infra/src/main.tf"
|
|
513
|
+
module "my_database" {
|
|
514
|
+
source = "../../common/terraform/src/app/dbs/my-database"
|
|
515
|
+
...
|
|
516
|
+
serverless_min_capacity = 0.5
|
|
517
|
+
serverless_max_capacity = 8
|
|
518
|
+
}
|
|
519
|
+
```
|
|
520
|
+
</Fragment>
|
|
521
|
+
</Infrastructure>
|
|
522
|
+
|
|
523
|
+
### Engine Version
|
|
524
|
+
|
|
525
|
+
Pin a specific Aurora engine version.
|
|
526
|
+
|
|
527
|
+
By default, the generated local Docker database image matches the default Aurora engine version. If you change the Aurora engine version, it's recommended to also use a matching local Docker database version for maximum compatibility. See the AWS release notes for [Aurora PostgreSQL versions](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraPostgreSQLReleaseNotes/aurorapostgresql-release-calendar.html) and [Aurora MySQL versions](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraMySQLReleaseNotes/AuroraMySQL.Updates.30Updates.html) to identify the corresponding community database version.
|
|
528
|
+
|
|
529
|
+
The local database image is configured in the generated database project's `serve-local` target in `project.json`. Update the image argument passed to `scripts/docker-start.ts` when you change engine versions.
|
|
530
|
+
|
|
531
|
+
<OptionFilter when={{ engine: 'PostgreSQL' }}>
|
|
532
|
+
<Infrastructure>
|
|
533
|
+
<Fragment slot="cdk">
|
|
534
|
+
|
|
535
|
+
```ts title="packages/infra/src/stacks/application-stack.ts"
|
|
536
|
+
import { MyDatabase } from ':my-scope/common-constructs';
|
|
537
|
+
|
|
538
|
+
const db = new MyDatabase(this, 'Db', {
|
|
539
|
+
...
|
|
540
|
+
engineVersion: AuroraPostgresEngineVersion.VER_17_7,
|
|
541
|
+
});
|
|
542
|
+
```
|
|
543
|
+
</Fragment>
|
|
544
|
+
<Fragment slot="terraform">
|
|
545
|
+
|
|
546
|
+
```hcl title="packages/infra/src/main.tf"
|
|
547
|
+
module "my_database" {
|
|
548
|
+
source = "../../common/terraform/src/app/dbs/my-database"
|
|
549
|
+
...
|
|
550
|
+
engine_version = "17.7"
|
|
551
|
+
}
|
|
552
|
+
```
|
|
553
|
+
</Fragment>
|
|
554
|
+
</Infrastructure>
|
|
555
|
+
</OptionFilter>
|
|
556
|
+
|
|
557
|
+
<OptionFilter when={{ engine: 'MySQL' }}>
|
|
558
|
+
<Infrastructure>
|
|
559
|
+
<Fragment slot="cdk">
|
|
560
|
+
|
|
561
|
+
```ts title="packages/infra/src/stacks/application-stack.ts"
|
|
562
|
+
import { MyDatabase } from ':my-scope/common-constructs';
|
|
563
|
+
|
|
564
|
+
const db = new MyDatabase(this, 'Db', {
|
|
565
|
+
...
|
|
566
|
+
engineVersion: AuroraMysqlEngineVersion.VER_3_12_0,
|
|
567
|
+
});
|
|
568
|
+
```
|
|
569
|
+
</Fragment>
|
|
570
|
+
<Fragment slot="terraform">
|
|
571
|
+
|
|
572
|
+
```hcl title="packages/infra/src/main.tf"
|
|
573
|
+
module "my_database" {
|
|
574
|
+
source = "../../common/terraform/src/app/dbs/my-database"
|
|
575
|
+
...
|
|
576
|
+
engine_version = "8.0.mysql_aurora.3.12.0"
|
|
577
|
+
}
|
|
578
|
+
```
|
|
579
|
+
</Fragment>
|
|
580
|
+
</Infrastructure>
|
|
581
|
+
</OptionFilter>
|
|
582
|
+
|
|
583
|
+
### Deletion Protection
|
|
584
|
+
|
|
585
|
+
Deletion protection is enabled by default (`deletionProtection: true` in CDK, `deletion_protection = true` in Terraform) to protect the Aurora cluster from accidental deletion.
|
|
586
|
+
|
|
587
|
+
#### Disable Deletion Protection
|
|
588
|
+
|
|
589
|
+
You can disable deletion protection for environments where database deletion is expected, such as short-lived development or preview stacks.
|
|
590
|
+
|
|
591
|
+
<Infrastructure>
|
|
592
|
+
<Fragment slot="cdk">
|
|
593
|
+
|
|
594
|
+
```ts title="packages/infra/src/stacks/application-stack.ts"
|
|
595
|
+
import { MyDatabase } from ':my-scope/common-constructs';
|
|
596
|
+
|
|
597
|
+
const db = new MyDatabase(this, 'Db', {
|
|
598
|
+
...
|
|
599
|
+
deletionProtection: false,
|
|
600
|
+
});
|
|
601
|
+
```
|
|
602
|
+
</Fragment>
|
|
603
|
+
<Fragment slot="terraform">
|
|
604
|
+
|
|
605
|
+
```hcl title="packages/infra/src/main.tf"
|
|
606
|
+
module "my_database" {
|
|
607
|
+
source = "../../common/terraform/src/app/dbs/my-database"
|
|
608
|
+
...
|
|
609
|
+
deletion_protection = false
|
|
610
|
+
}
|
|
611
|
+
```
|
|
612
|
+
</Fragment>
|
|
613
|
+
</Infrastructure>
|
|
614
|
+
|
|
615
|
+
### Removal Policy
|
|
616
|
+
|
|
617
|
+
The CDK construct retains the Aurora cluster by default (`removalPolicy: RemovalPolicy.RETAIN`). Change this when you want CDK stack deletion to snapshot or destroy the cluster instead.
|
|
618
|
+
|
|
619
|
+
When using `RemovalPolicy.DESTROY`, deletion protection must also be disabled before the cluster can be deleted.
|
|
620
|
+
|
|
621
|
+
<Infrastructure>
|
|
622
|
+
<Fragment slot="cdk">
|
|
623
|
+
|
|
624
|
+
```ts title="packages/infra/src/stacks/application-stack.ts"
|
|
625
|
+
import { RemovalPolicy } from 'aws-cdk-lib';
|
|
626
|
+
import { MyDatabase } from ':my-scope/common-constructs';
|
|
627
|
+
|
|
628
|
+
const db = new MyDatabase(this, 'Db', {
|
|
629
|
+
...
|
|
630
|
+
removalPolicy: RemovalPolicy.SNAPSHOT,
|
|
631
|
+
});
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
For an ephemeral environment where the database should be deleted with the stack:
|
|
635
|
+
|
|
636
|
+
```ts title="packages/infra/src/stacks/application-stack.ts"
|
|
637
|
+
import { RemovalPolicy } from 'aws-cdk-lib';
|
|
638
|
+
import { MyDatabase } from ':my-scope/common-constructs';
|
|
639
|
+
|
|
640
|
+
const db = new MyDatabase(this, 'Db', {
|
|
641
|
+
...
|
|
642
|
+
deletionProtection: false,
|
|
643
|
+
removalPolicy: RemovalPolicy.DESTROY,
|
|
644
|
+
});
|
|
645
|
+
```
|
|
646
|
+
</Fragment>
|
|
647
|
+
<Fragment slot="terraform">
|
|
648
|
+
|
|
649
|
+
Terraform does not use CDK removal policies. By default, the module creates a final snapshot on deletion (`skip_final_snapshot = false`). To skip the final snapshot for an ephemeral environment:
|
|
650
|
+
|
|
651
|
+
```hcl title="packages/infra/src/main.tf"
|
|
652
|
+
module "my_database" {
|
|
653
|
+
source = "../../common/terraform/src/app/dbs/my-database"
|
|
654
|
+
...
|
|
655
|
+
deletion_protection = false
|
|
656
|
+
skip_final_snapshot = true
|
|
657
|
+
}
|
|
658
|
+
```
|
|
659
|
+
</Fragment>
|
|
660
|
+
</Infrastructure>
|
|
661
|
+
|
|
662
|
+
### Encryption Key Rotation
|
|
663
|
+
|
|
664
|
+
The KMS key used to encrypt the Aurora cluster and its credentials secret has automatic key rotation enabled by default. Disable it if your security policy manages rotation externally.
|
|
665
|
+
|
|
666
|
+
<Infrastructure>
|
|
667
|
+
<Fragment slot="cdk">
|
|
668
|
+
|
|
669
|
+
```ts title="packages/infra/src/stacks/application-stack.ts"
|
|
670
|
+
import { MyDatabase } from ':my-scope/common-constructs';
|
|
671
|
+
|
|
672
|
+
const db = new MyDatabase(this, 'Db', {
|
|
673
|
+
...
|
|
674
|
+
enableKeyRotation: false,
|
|
675
|
+
});
|
|
676
|
+
```
|
|
677
|
+
</Fragment>
|
|
678
|
+
<Fragment slot="terraform">
|
|
679
|
+
|
|
680
|
+
```hcl title="packages/infra/src/main.tf"
|
|
681
|
+
module "my_database" {
|
|
682
|
+
source = "../../common/terraform/src/app/dbs/my-database"
|
|
683
|
+
...
|
|
684
|
+
enable_key_rotation = false
|
|
685
|
+
}
|
|
686
|
+
```
|
|
687
|
+
</Fragment>
|
|
688
|
+
</Infrastructure>
|
|
689
|
+
|
|
690
|
+
## Limitations
|
|
691
|
+
|
|
692
|
+
<OptionFilter when={{ engine: 'MySQL' }}>
|
|
693
|
+
|
|
694
|
+
### MySQL: API Gateway Streaming Mode
|
|
695
|
+
|
|
696
|
+
When using Aurora MySQL with API Gateway streaming responses (e.g. with tRPC's `httpBatchStreamLink`), the Prisma MySQL client holds onto the Node.js event loop after a query completes, preventing the Lambda from flushing the stream and ending the request.
|
|
697
|
+
|
|
698
|
+
To work around this, explicitly disconnect the client in a `finally` block after each query so the event loop is free to exit and the streaming response can complete.
|
|
699
|
+
|
|
700
|
+
**Option 1: per-procedure**
|
|
701
|
+
|
|
702
|
+
```ts
|
|
703
|
+
export const listExampleTable = publicProcedure
|
|
704
|
+
.output(z.array(ExampleTableSchema))
|
|
705
|
+
.query(async () => {
|
|
706
|
+
const prisma = await getPrisma();
|
|
707
|
+
try {
|
|
708
|
+
return await prisma.exampleTable.findMany();
|
|
709
|
+
} finally {
|
|
710
|
+
await prisma.$disconnect();
|
|
711
|
+
}
|
|
712
|
+
});
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
**Option 2: tRPC middleware**
|
|
716
|
+
|
|
717
|
+
If you are using the [middleware pattern](#injecting-the-prisma-client-via-middleware), add the `$disconnect()` call to the middleware so all procedures built on it are covered automatically:
|
|
718
|
+
|
|
719
|
+
```ts title="packages/api/src/middleware/db.ts"
|
|
720
|
+
import { getPrisma } from ':my-scope/db';
|
|
721
|
+
import { initTRPC } from '@trpc/server';
|
|
722
|
+
|
|
723
|
+
export interface IDbContext {
|
|
724
|
+
db: Awaited<ReturnType<typeof getPrisma>>;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
export const createDbPlugin = () => {
|
|
728
|
+
const t = initTRPC.context<IDbContext>().create();
|
|
729
|
+
return t.procedure.use(async (opts) => {
|
|
730
|
+
const db = await getPrisma();
|
|
731
|
+
try {
|
|
732
|
+
return await opts.next({
|
|
733
|
+
ctx: {
|
|
734
|
+
...opts.ctx,
|
|
735
|
+
db,
|
|
736
|
+
},
|
|
737
|
+
});
|
|
738
|
+
} finally {
|
|
739
|
+
await db.$disconnect();
|
|
740
|
+
}
|
|
741
|
+
});
|
|
742
|
+
};
|
|
743
|
+
```
|
|
744
|
+
|
|
745
|
+
:::note
|
|
746
|
+
This is not required for PostgreSQL. The PostgreSQL adapter uses a `pg` connection pool configured with `allowExitOnIdle: true`, which allows the event loop to exit naturally without an explicit disconnect. Due to this limitation, `getPrisma()` for MySQL does not cache the client or reuse connections across warm Lambda invocations. A new connection is opened on every call, unlike the PostgreSQL adapter which caches the client at the module level and reuses the same connection pool.
|
|
747
|
+
:::
|
|
748
|
+
|
|
749
|
+
### MySQL: IAM Token Expiry
|
|
750
|
+
|
|
751
|
+
RDS IAM authentication tokens expire after **15 minutes**. The MySQL Prisma client captures the IAM token as a static value at the time `getPrisma()` is called. An existing open connection is not affected, but if a new connection needs to be established after the token has expired, authentication will fail. The PostgreSQL adapter avoids this by refreshing the token dynamically each time the pool opens a new connection, but the MySQL adapter has no equivalent mechanism.
|
|
752
|
+
|
|
753
|
+
:::caution
|
|
754
|
+
Be cautious with tasks running longer than 15 minutes. If the MySQL client needs to open a new connection after the original IAM token has expired, authentication will fail.
|
|
755
|
+
:::
|
|
756
|
+
|
|
757
|
+
For long-running tasks such as batch jobs or data migrations, call `getPrisma()` at the start of each unit of work rather than once for the entire operation. Because `getPrisma()` always creates a fresh client and fetches a new IAM token for MySQL, this ensures each connection authenticates with a valid token.
|
|
758
|
+
|
|
759
|
+
</OptionFilter>
|