Closed remihuigen closed 8 months ago
The advisory lock issue also happens with me on an Ubuntu VM hosted on Oracle, running Postgres 12.9, but seems to work fine on a Heroku app with a Postgres add-on
I'm having the same issue when developing on macOS with Postgres.app installed. First it couldn't connect because it seems to need user and password in the connection string, despite not being mentioned anywhere. Now I'm running into the advisory lock issue.
Okay, I did some more research and testing for the issues mentioned above, and came up with a workaround that seems to do the trick (at least partially). I'm not sure how this relates to local development, or any other cloudhosting than digital ocean (DO) w/ Postgres.
Anyway, the implementation discussed below seems to resolve the issues when deploying keystone to DO's app platform with Postgres 13.
First up, when running keystone in production, it is essential to use a connection pool (e.g PgBouncer). Otherwise, Prisma will just gobble up any available DB connection, and your gonna get a Error: P1001: Can't reach database server at ...
. See https://docs.digitalocean.com/products/databases/postgresql/how-to/manage-connection-pools/ for more info on how to set up connection pools for DO's managed databases. Make sure that you're using transaction mode and you add the flag pgbouncer=true
to your connection string, so Prisma knows you're using a connection pool.
However, using a connection pool will result in new issues, namely not being able to use Prisma Migrate as part of the build process (which Keystone kinda forces you to do...). Here, you're gonna run into errors like: ERROR: prepared statement "s..." already exists
. The only way to fix this (as far as I know) is to NOT use the connection pool when running prisma migrate command, but a direct connection to the DB. See https://www.prisma.io/docs/guides/performance-and-optimization/connection-management/configure-pg-bouncer for more context.
To summarize: you need to make sure the prisma migrate command uses a different connection string than the rest of the build proces. Since you can only use one variable in your keystone.ts file for the connection string that is used, my solution is to add extra env vars to track which part of the build process you're in:
in your .env / app-spec.yml
DATABASE_URL_MIGRATE=postgresql://{username}:{password}@{hostname}:25060/{DBNAME}?sslmode=require&connection_limit=1
DATABASE_URL_POOL=postgresql://{username}:{password}@{hostname}:25061/{POOLNAME}?sslmode=require&connection_limit=5&pgbouncer=true&prepareThreshold=0&connection_timeout=30&pool_timeout=30
Note: for direct DB connection, use port 25060. For connection pools, use port 25061. Note: At least the following flags are needed in DATABASE_URL_POOL:
in your package.json
"scripts": {
"dev": "keystone dev",
"postinstall": "cross-env STAGE=postinstall keystone postinstall",
"build": "cross-env STAGE=build keystone build && cross-env STAGE=migrate keystone prisma migrate deploy && cross-env STAGE=build",
"start": "cross-env STAGE=run keystone start"
},
"devDependencies": {
"cross-env": "^7.0.3"
}
in your keystone.ts
export default config({
db: {
provider: 'postgresql',
url: process.env.STAGE === 'migrate' ? process.env.DATABASE_URL_MIGRATE : process.env.DATABASE_URL_POOL,
useMigrations: true,
},
// All other config stuff...
});
Lastly, I'm not sure if this also fixes the advisory lock issue, but I haven't seen this error since implementing the fix. If it does still show up, I'll give another update.
In general, I'm running into a lot of issues when trying to use prisma migrate when deploying to digitalocean app platform. I have a production app (and some staging/test apps) running on the app platform for a couple of months now, and guess that about 2/3 of the builds that contain pending migrations fail for some reason.
Usually after repeating the build process 3 or 4 times, the build eventually passes and deploys. However, it's still extremely frustrating when half of the pending migrations are applied during the build, and then halfway through the list of pending migrations the build fails. This results in a (live) DB that is out of sync with the keystone app (which causes fatal errors in both front and backend production apps)
How to reproduce
Usually, the process as described above will fail for some reason. Below, you'll find the three most regularly occurring errors (you'll also find more complete build logs further down):
Error: db error: ERROR: prepared statement "s..." does not exist
Error: Error in migration engine: db error: ERROR: prepared statement "s..." already exists
The database server at
:
was reached but timed out. Context: Timed out trying to acquire a postgres advisory lock (SELECT pg_advisory_lock(72707369)). Elapsed: 10000ms. See https://pris.ly/d/migrate-advisory-locking for details.
What did I expect
I expected Prisma to behave the way it's intended to behave
No screenshots, but I do have build logs for the errors mentioned above. They are not complete build logs, just the part where the errors occur (during prisma migrate):
BUILD LOGS EXAMPLE 1
BUILD LOGS EXAMPLE 2
BUILD LOGS EXAMPLE 3
Some context:
?sslmode=require&connection_limit=5&pgbouncer=true&prepareThreshold=0&connection_timeout=30&pool_timeout=30
I think the errors I mentioned above are related to the following issues: https://github.com/prisma/prisma/issues/4752 https://github.com/prisma/prisma/issues/6053
I must say: in general I really love working with Keystone! But the issues as mentioned are really frustrating when working on a production app... I'm not sure if it's a problem with digitalocean or with Keystone and the way it implements Prisma.
If any additional info is required, please let me know! Remi