Damiano Dotto
Damiano Dotto

Reputation: 109

NEXTJS Amplify slow server response

I've a SSR App Nextjs 12 installed on AWS Amplify that's too slow.

Logging the getServerSideProps() this is the result: It takes 9 seconds to load page but the code inside getServerSideProps takes less than 0.5 second.

This is the server log:

START RequestId: 94ced4e1-ec32-4409-8039-fdcd9b5f5894 Version: 300
2022-09-13T09:25:32.236Z    94ced4e1-ec32-4409-8039-fdcd9b5f5894    INFO    1 [09:25:32.236] -
2022-09-13T09:25:32.253Z    94ced4e1-ec32-4409-8039-fdcd9b5f5894    INFO    2 [09:25:32.253] -
2022-09-13T09:25:32.255Z    94ced4e1-ec32-4409-8039-fdcd9b5f5894    INFO    3 [09:25:32.255] -
2022-09-13T09:25:32.255Z    94ced4e1-ec32-4409-8039-fdcd9b5f5894    INFO    4 [09:25:32.255] -
2022-09-13T09:25:32.431Z    94ced4e1-ec32-4409-8039-fdcd9b5f5894    INFO    5 [09:25:32.431] -
2022-09-13T09:25:32.496Z    94ced4e1-ec32-4409-8039-fdcd9b5f5894    INFO    6 [09:25:32.496] -
END RequestId: 94ced4e1-ec32-4409-8039-fdcd9b5f5894
REPORT RequestId: 94ced4e1-ec32-4409-8039-fdcd9b5f5894  Duration: 9695.59 ms    Billed Duration: 9696 ms    Memory Size: 512 MB Max Memory Used: 206 MB 

That's the code:

export async function getServerSideProps(context) {
  console.log("1 [" + new Date().toISOString().substring(11, 23) + "] -");

  let req = context.req;
  console.log("2 [" + new Date().toISOString().substring(11, 23) + "] -");

  const { Auth } = withSSRContext({ req });

  console.log("3 [" + new Date().toISOString().substring(11, 23) + "] -");

  try {
    console.log("4 [" + new Date().toISOString().substring(11, 23) + "] -");

    const user = await Auth.currentAuthenticatedUser();
    console.log("5 [" + new Date().toISOString().substring(11, 23) + "] -");

    const dict = await serverSideTranslations(context.locale, ["common", "dashboard", "footer", "hedgefund", "info", "etf", "fs"]);
    console.log("6 [" + new Date().toISOString().substring(11, 23) + "] -");

    return {
      props: {
        exchange: context.params.exchange,
        ticker: context.params.ticker,
        username: user.username,
        attributes: user.attributes,
        ...dict,
      },
    };
  } catch (err) {
    return {
      redirect: {
        permanent: false,
        destination: "/auth/signin",
      },
      props: {},
    };
  }
}

Upvotes: 9

Views: 3330

Answers (2)

Damiano Dotto
Damiano Dotto

Reputation: 109

[UPDATE] Today I realized that entering amplify, an update was proposed to me for "improvements and performance using nextjs 12".

I did that and it actually got much faster... It messed up my backend environment though...

AWS Amplify Performance Boost with NextJS 12 - Unexpected Backend Environment Switch

Upvotes: 0

axelmukwena
axelmukwena

Reputation: 1079

This is not the answer but rather an alternative.

I tried using Amplify for my implementation because getServerSideProps on the Vercel hobby account gives a function timeout error. However, I think the Next.js deployment to Amplify is not optimized yet.

Instead of using getServerSideProps, I used getStaticPaths and getStaticProps whereby I always limited the number of paths to fetch from my API.

On client side

export const getStaticPaths: GetStaticPaths = async () => {
  // This route to my API only gets paths(IDs)
  const res = await getFetcher("/sentences-paths"); 

  let paths = [];
  if (res.success && res.resource) {
    paths = res.resource.map((sentence: any) => ({
      params: { sentenceSlug: sentence._id },
    }));
  }

  return { paths, fallback: "blocking" };
};

On API

const getSentencePaths = async (req, res) => {
  const limit = 50;

  Sentence.find(query)
    .select("_id")
    .limit(limit)
    .exec()
    .then((resource) => res.json({ success: true, resource }))
    .catch((error) => res.json({ success: false, error }));
};

This means even if I have 100 000 sentences, only 50 are rendered at build. The rest of the sentences are generated on demand because we have fallback: "blocking". See docs

Here is how my getStaticProps looks like

export const getStaticProps: GetStaticProps = async ({ params }) => {
  const sentenceSlug = params?.sentenceSlug;
  const response = await getFetcher(`/sentences/${sentenceSlug}`);

  let sentence = null;
  if (response.success && response.resource) sentence = response.resource;

  if (!sentence) {
    return {
      notFound: true,
    };
  }

  return {
    props: { sentence },
    revalidate: 60,
  };
};

As you can see above, I used revalidate: 60 seconds see docs but since you wanted to use getServerSideProps, that's not the perfect solution.

The perfect solution is On-Demand Revalidation. With this, whenever you make a change to data that's used in a page, for example, change the sentence content, you can trigger a webhook to regenerate your page created by getStaticProps. So, your page will always be updated.

Go through this youtube tutorial to implement on-demand revalidation, really comprehensive https://www.youtube.com/watch?v=Wh3P-sS1w0I&t=8s&ab_channel=TuomoKankaanp%C3%A4%C3%A4.

Next.js on Vercel works way faster and more efficiently. Hope I helped.

Upvotes: 1

Related Questions