Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Next.js 13 app dir: Fast Refresh (hot reloading) causes database connection exhaustion #45483

Open
Eprince-hub opened this issue Feb 1, 2023 · 16 comments
Labels
bug Issue was opened via the bug report template.

Comments

@Eprince-hub
Copy link

Eprince-hub commented Feb 1, 2023

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 22.1.0: Sun Oct  9 20:14:30 PDT 2022; root:xnu-8792.41.9~2/RELEASE_ARM64_T8103
Binaries:
  Node: 19.4.0
  npm: 9.2.0
  Yarn: 1.22.19
  pnpm: 7.25.1
Relevant packages:
  next: 13.1.6
  eslint-config-next: N/A
  react: 18.2.0
  react-dom: 18.2.0

Which area(s) of Next.js are affected? (leave empty if unsure)

  • Fast Refresh (hot reloading)
  • app directory

Link to the code that reproduces this issue

https://codesandbox.io/p/sandbox/autumn-mountain-0efmhn

To Reproduce

Run the project in CodeSandbox

https://codesandbox.io/p/sandbox/autumn-mountain-0efmhn

Start editing and saving any of these files => database/connect.ts / app/page.tsx

Check the console and watch the database connection count increase as the changes are saved

Describe the Bug

With Fast Refresh (hot reloading) during the development mode, a new database connection is initiated on every refresh, Thereby causing a database connection slot error like remaining connection slots are reserved for non-replication superuser connections in PostgreSQL

In the CodeSandbox linked above, a database connection is made similarly to how the docs section Sharing data between Server Components suggests:

export const db = new DatabaseConnection(...);

Screenshot of the error on the browser
Screenshot 2023-02-01 at 10 38 04

Screenshot of the error in CLI
Screenshot 2023-02-01 at 11 16 44

When a file that imports a database code is edited and saved, the Fast Refresh makes a new connection to the database on every refresh, rapidly increasing the database connection count. The database connection slot error is triggered when the count is above 90

The videos below show the process that triggers the error and the database connection count increment

video-output-B409C148-D9EB-4999-B6BB-D5EE4CE9FAB1.1.mp4

I also left a comment on another similar discussion, but this discussion is not about the app directory: #26427

Expected Behavior

It is expected that the development mode Fast Refresh (hot reloading) doesn't attempt reconnecting to the database but instead uses the previous connection.

Workaround

Using the globalThis singleton workaround described here #26427 (comment), I was able to prevent this behavior.

import postgres from 'postgres';

declare module globalThis {
  let postgresSqlClient: ReturnType<typeof postgres> | undefined;
}

// Connect only once to the database
// https://github.com/vercel/next.js/discussions/26427#discussioncomment-898067
function connectOnceToDatabase() {
  if (!globalThis.postgresSqlClient) globalThis.postgresSqlClient = postgres();
  return globalThis.postgresSqlClient;
}

export const sql = connectOnceToDatabase();

The video below shows that the database connection count is not increasing above 13-14 counts regardless of how many reloads happen

video-output-140FC546-5D8D-45C1-A83D-0C2A54BCE6C5.MOV

Which browser are you using? (if relevant)

No response

How are you deploying your application? (if relevant)

No response

@Eprince-hub Eprince-hub added the bug Issue was opened via the bug report template. label Feb 1, 2023
@Eprince-hub Eprince-hub changed the title Database connection slot error in Next.js 13 app directory Next.js 13 app dir: Fast Refresh (hot reloading) causes database connection exhaustion Feb 2, 2023
@abuinitski
Copy link

Pretty important issue, +1 on it. Super important for any non-trivial apps which use any global context or services (e.g. a Message Queue consumer, or gRPC clients / Protobuf parsers).

Few extra observations:

  1. Workaround has to be implemented exactly as proposed, any attempt to hide it behind any tooling breaks it. E.g. "singleton" utility that maintains a collection of singleton instances in global context and provide convenience methods to get-or-instantiate an instance - doesn't work, it's like globalContext is also getting reinstantiated based on some funny rules. Every singleton has to define its own extension of globalContext and export its own getSingletonInstance()-kind-of-a-function.
  2. A side-effect of that - instance of operator doesn't work at least in dev mode. If you created a custom exception class, for example, you cannot use x instance of MyException, since multiple versions of the same class may be present.
  3. A singleton hidden behind such workaround cannot use any standard next methods for server functions (e.g. cookies etc). Next is not able to find it's async context.

@sangauit
Copy link

In AWS has the proxy feature, actually that is the connection pooling, and in the .NET core I can implement something like that. So I believe you can implement something like that or NextJs have feature that support connection pooling in a case using server action to query data in db

@eashish93
Copy link

Related to : #52165

@nanzm

This comment has been minimized.

@alexeigs
Copy link

Solution when working with supabase and drizzle: drizzle-team/drizzle-orm#928 (comment)

@hungcung2409
Copy link

The workaround solution does not work anymore

@karlhorky
Copy link
Contributor

karlhorky commented Oct 14, 2024

@hungcung2409 The globalThis workaround continues to work in multiple new projects we've started in new v15 canary versions (latest tested version next@15.0.0-canary.171) - not sure what you're experiencing, maybe your workaround code is misconfigured somehow.

@karlhorky
Copy link
Contributor

I noticed that Prisma documented this globalThis workaround for Next.js Fast Refresh in their official docs now too:

@zero1zero
Copy link

The workaround solution does not work anymore

Seconded that this appears to not work anymore (14.2). Is there really no functioning way to create a singleton object in NextJS (in dev mode)? This seems like a pretty simple use case that I'm shocked is impossible, or even requires a workaround.

@karlhorky
Copy link
Contributor

@zero1zero can you provide failing demo code? It has worked for numerous apps of ours on pretty much every minor/patch version of 13, 14 and 15.

@zero1zero
Copy link

I tried implementing this on a fresh CRA app with a dead simple singleton and it seems to work there. Tried the same code in my project and it did not have any effect. Sounds like a more complex project/setup (or artifact thereof) makes this workaround ineffective.

We've been having issues with very slow dev mode reloads (or reloads when no files have changed), so this may play a factor, but may not. Seems that multiple people are experiencing similar issues with no resolution, so I'm hoping someone with more of a depth of understanding in dev mode runs into this and solves it soon.

@karlhorky
Copy link
Contributor

@zero1zero without demo code showing it failing or reproduction steps, it will be difficult to reproduce your problem.

It is a common solution to the problem of database connections with hot reloading - you can see this recommended in multiple official places, apart from here.

So I'm guessing there is something else with your app code or setup that is causing the problem.

I would be interested to know more from anyone experiencing failures here, but without a reproduction there is not much I can do.

@zero1zero
Copy link

So I'm guessing there is something else with your app code or setup that is causing the problem.

Yes, I'm suggesting that a more complex or specific setup renders this workaround ineffective. Without knowing what it is about our app that is causing it to be ineffective makes it impossible to extract out demo code to share. I tried making a CRA app with the basic patterns and simplified structure but the workaround was effective there.

If I eventually find the cause (or a solution) I will update this thread but this is mostly so I can share that in some cases the workaround is ineffective with the hopes that someone (or NextJS) will find a working solution for singletons in dev mode.

@karlhorky
Copy link
Contributor

karlhorky commented Nov 1, 2024

Ok, let us know if you can reproduce the problem in a minimal reproduction.

Two ways to do this:

  1. Reduce the complexity of your complex app until you see that globalThis is working again for you
  2. Increase the complexity of the create-next-app example until you see that the globalThis is no longer working

In both approaches above, the last change you made was related to the problematic code, and you can make a minimal reproduction.

For now, the note that it's not working in a larger app with no additional details is unfortunately not actionable and not helpful.

@Bligoubloups
Copy link

Hi !

I've got similar issue and made a minimal reproduction of it.
https://codesandbox.io/p/devbox/kvxgj2?file=%2Fbaz.ts%3A15%2C25

The issue appears when fetching a dynamic api route (/api/foo/[bar]).
The global variable baz gets initialized everytime but actually kind of never update itself 🤯.

@karlhorky
Copy link
Contributor

@Bligoubloups not understanding yet what you mean - I'm having trouble making a connection between your reproduction and the database exhaustion issue / the globalThis workaround.

Maybe you could edit your post above to make it clear what the connection is?

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
bug Issue was opened via the bug report template.
Projects
None yet
Development

No branches or pull requests

10 participants