Skip to content
This repository was archived by the owner on May 10, 2021. It is now read-only.

Prisma does not seem to get rhel binary in functions #55

Closed
garrypolley opened this issue Oct 14, 2020 · 9 comments
Closed

Prisma does not seem to get rhel binary in functions #55

garrypolley opened this issue Oct 14, 2020 · 9 comments

Comments

@garrypolley
Copy link
Contributor

I've been following this example and it works on "standard netlify" : https://github.com/garrypolley/deployment-example-netlify

I'm attempting to use next as well on a private site API ID: c076fc19-1890-4dd6-b610-1b57342b8c39

Whenever any attempt to query the database is made I get the following error:

Query engine binary for current platform "rhel-openssl-1.0.x" could not be found.
This probably happens, because you built Prisma Client on a different platform.
(Prisma Client looked in "/query-engine-rhel-openssl-1.0.x")

Files in /:

  bin
  boot
  dev
  etc
  home
  lib
  lib64
  media
  mnt
  opt
  proc
  root
  run
  sbin
  srv
  sys
  tmp
  usr
  var

You already added the platforms "native", "rhel-openssl-1.0.x" to the "generator" block
in the "schema.prisma" file as described in https://pris.ly/d/client-generator,
but something went wrong. That's suboptimal.

Please create an issue at https://github.com/prisma/prisma-client-js/issues/new

I believe this is because the rhel binary is not shipping inside the bundled function that goes in the out_functions directory.

I've tried a lot of options:

  • bundling the primsa client in my own code -- still misses the rhel binary
  • copying over the binary to each of the output directories in a custom build plugin -- still misses the same error

I think if the rhel binary can be found on the running lambda disk then this environment variable could be set and it'd work PRISMA_QUERY_ENGINE_BINARY

There are a few issues logged for this across Netlify and Primsa githubs. And also a community post as well https://community.netlify.com/t/prisma-client-binary-not-copied-for-netlify-lambda-functions-for-graphql-server/11701

I'm happy to help troubleshoot further.

@FinnWoelm
Copy link
Contributor

Hi @garrypolley,

I think your assessment of the issue (rhel binary not shipping) might be exactly right. We've seen this kind of issue before when using packages that rely on binaries/native code. NextJS' strategy for creating serverless functions is to inline the code from all dependencies into a big JS file. That works really well, except when binaries are involved.

Given that everything works when you require prisma in a Netlify function and that it does not work when that require/import is inside the Next API endpoint (or page), I wonder if Netlify has some sort of post-processing script that is triggered only when prisma is detected in the Netlify function. Would be good to set up a super basic repo and test that.

If you have time and interest, it would be great if you could set up a minimal repo for reproducing the issue (just with one really simple API endpoint that uses Prisma, for example). Otherwise, I will try to make some time for this tomorrow.

We should definitely be able to get this working 👍 Thanks for taking the time to report this issue! 😊

@garrypolley
Copy link
Contributor Author

@FinnWoelm I appreciate the feedback.

Here is a basic repo that does work: https://github.com/garrypolley/deployment-example-netlify.

@FinnWoelm
Copy link
Contributor

Yap, that's super helpful already! What I want to do next is to create a version that uses next-on-netlify. And then we can try manually adding require("prisma... into the Netlify Function that next-on-netlify creates in out_functions and see if that changes anything!

So for this test case, we would not run our build command on netlify.com. We would instead locally run next build & next-on-netlify and then edit the created Netlify Function in out_functions. Then we just push that to Netlify and see what happens and whether it changes anything!

@garrypolley
Copy link
Contributor Author

garrypolley commented Oct 14, 2020

@FinnWoelm I can confirm the out_functions do not get the binaries at all locally when I run. I think the code only grabs .js files when I looked at the source. https://github.com/netlify/next-on-netlify/blob/main/lib/helpers/setupNetlifyFunctionForPage.js#L11-L35 (I may be wrong)

I used a custom build plugin:

const fs = require('fs')

const getDirectories = source =>
  fs.readdirSync(source, { withFileTypes: true })
    .filter(dirent => dirent.isDirectory())
    .map(dirent => dirent.name)

module.exports = {
	onBuild: api => {
		console.log('Copying over `rhel-openssl-1.0.x` binary engine...')
		const src = `node_modules/@prisma/cli/query-engine-rhel-openssl-1.0.x`

		console.log(`Primsa plugin located at ${api.constants.FUNCTIONS_SRC}`);

		console.log(` files: ${JSON.stringify(fs.readdirSync(api.constants.FUNCTIONS_SRC, {withFileTypes: true}))}`);

		return getDirectories(api.constants.FUNCTIONS_SRC).forEach((dir) => {
			const dest = `${api.constants.FUNCTIONS_SRC}/${dir}/query-engine-rhel-openssl-1.0.x`;
			console.log(`Copying from ${src} to ${dest}`);
			fs.copyFile(src, dest, err => console.log(err))
			console.log(`in dir files: ${JSON.stringify(fs.readdirSync(`${api.constants.FUNCTIONS_SRC}/${dir}`, {withFileTypes: true}))}`);
		});
	}
}

this copied them to the out_functions in each function.

out_functions/
  some_function/
    function.js
    rhel-binary
  some_other_function/
    function.js
    rhel-binary

At the point they they then get "zipped" up and sent to lambda they seem to lack the rhel file. I'm not sure where to put the binary at -- I even tried to manually put them in the code base, since the client is dynamically generated. This didn't work either, though I may have done something incorrectly.

EDIT

I just noticed this:

And then we can try manually adding require("prisma... into the Netlify Function that next-on-netlify creates in out_functions and see if that changes anything!

You mean to manually try it -- I have not done that. I can give that a whirl.

@FinnWoelm
Copy link
Contributor

Hey @garrypolley, thanks to your excellent repo, I was able to reproduce the issue and behavior!

I understand the issue now; brace yourself for a brief rollercoaster — and a beautiful solution at the end 😊

Rollercoaster 🎢

When NextJS creates the serverless functions for the API endpoints, it hardcodes the names and even paths of the prisma binaries into the function code. That obviously leads to issues. For example: https://github.com/FinnWoelm/next-on-netlify-prisma/blob/beb399075f1018b18254545cb06cc2610e512fb8/out_functions/next_api_test/nextJsPage.js#L526

We can get around that by wrapping the require/import in eval, so that NextJS does not pre-process the client and does not hardcode all those file names and paths. Example: https://github.com/FinnWoelm/next-on-netlify-prisma/blob/beb399075f1018b18254545cb06cc2610e512fb8/pages/api/test7.js#L1

Now, this leads to one more issue, namely that Netlify does not know that it needs to bundle prisma into the Netlify Function. So we need to have a noop-require in the function handler (this one does not get touched by NextJS, so no inlining happens). Example: https://github.com/FinnWoelm/next-on-netlify-prisma/blob/beb399075f1018b18254545cb06cc2610e512fb8/out_functions/next_api_test8/next_api_test8.js#L4

You can see everything working here: https://compassionate-euler-d2be4d.netlify.app/.netlify/functions/next_api_test8 (well, except, that I don't have Prisma set up nor the DATABASE_URL configured). But compare with https://compassionate-euler-d2be4d.netlify.app/.netlify/functions/next_api_test and you will see the difference.

Solution 🌞

Don't fear! You do not actually need to eval all your requires and add noop-requires to the functions created by next-on-netlify. Instead, you can just switch to target: experimental-serverless-trace in your next.config.js and NextJS will not inline its dependencies and everything will work!
Here is the setup: https://github.com/FinnWoelm/next-on-netlify-prisma/blob/main/next.config.js
Here is a function I generated with experimental-serverless-trace: https://compassionate-euler-d2be4d.netlify.app/.netlify/functions/next_api_test9

In fact, we should probably tell everyone to switch over to experimental-serverless-trace. Looking back, I think that would have actually been the appropriate and correct solution for #34 and #33. So I am very glad you posted this issue and that we know this now. Vercel actually applies that mode to all NextJS deployments on its platform, too: vercel/next.js#8797 (comment)

Would you mind trying experimental-serverless-trace and letting us know if it resolves the issue? 😊

@garrypolley
Copy link
Contributor Author

Thanks @FinnWoelm this fixed it entirely.

Using the config

module.exports = {
  target: "experimental-serverless-trace",
};

This is great, and I'm glad it was this easy to fix. I'm appreciative of the time you've taken here! Consider this done.

garrypolley added a commit to garrypolley/next-on-netlify that referenced this issue Oct 16, 2020
This change in the readme is to help future developers not have binary issues across lambda functions created by the next build command.
@garrypolley
Copy link
Contributor Author

This change does seem to make it slower to deploy.
From about 1 minute 30 seconds (on average) to about 2 minutes and 30 seconds (on average) so far with the same code -- but using the experimental trace part.

@garrypolley
Copy link
Contributor Author

For future developers that may google their way here. There is an issue (October 15 2020) where Prisma needs to be disconnected after all calls on any function. Your lambda will timeout otherwise.

You'll need to do.

//after all your DB calls, before the `res.json` call
await prismaClientInstance.$disconnect();

For details see: https://github.com/prisma/prisma-client-js/issues/540

lindsaylevine pushed a commit that referenced this issue Oct 19, 2020
* Update to prevent #55 from occurring again

This change in the readme is to help future developers not have binary issues across lambda functions created by the next build command.

* Include default option and a binary option
@s-kris
Copy link

s-kris commented Dec 2, 2020

This change does seem to make it slower to deploy.
From about 1 minute 30 seconds (on average) to about 2 minutes and 30 seconds (on average) so far with the same code -- but using the experimental trace part.

Thank you for the fix @garrypolley @FinnWoelm
Yes, my build time went from 2 minutes to 5 minutes after using experimental. Can we reduce the build time somehow?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants