Skip to content

Next js get server side props returns 502 when using promise.all ( only 7 promises or more )

0

here is my nextJS page

import AuditForm from 'containers/AuditForm';
import { useEffect } from 'react';
import { useStore } from 'store';
import { fetcher, fetchMany } from 'utils/fetcher';

const EditId = ({
  editId,
  auditors,
  contractors,
  user,
  parentId,
  invoices,
  history,
  extraForms,
  qas,
  audit,
  child,
  // emailTemplates,
}) => {
  const {
    setAuditors,
    setContractors,
    setUser,
    // setEmailTemplates
  } = useStore();

  useEffect(() => {
    setAuditors(auditors);
    setContractors(contractors);
    setUser(user);
    // setEmailTemplates(emailTemplates);
  }, []);

  return (
    <AuditForm
      audit={audit}
      child={child}
      parent={audit.parent}
      editId={editId}
      parentId={parentId}
      invoices={invoices}
      history={history}
      extraForms={extraForms}
      qas={qas}
    />
  );
};

export default EditId;

export const getServerSideProps = async ({ req, res, query }) => {
  const token = req.cookies['accessToken'];
  const userId = req.cookies['userId'];
  const hasAcceptedTerms = req.cookies['hasAcceptedTerms'];

  if (!token) {
    return {
      redirect: {
        permanent: false,
        destination: '/login',
      },
    };
  }

  if (hasAcceptedTerms !== 'true') {
    return {
      redirect: {
        permanent: false,
        destination: '/profiles',
      },
    };
  }

  const fetchItems = await fetchMany({
    audit: fetcher('Audit', 'Find', { _id: query.editId }, { req, res }),
    child: fetcher('Audit', 'Find', { parent: query.editId }, { req, res }),
    contractors: fetcher('User', 'List', { role: 'Contractor' }, { req, res }),
    auditors: fetcher('User', 'List', { role: 'Auditor' }, { req, res }),
    user: fetcher('User', 'Find', { _id: userId }, { req, res }),
    invoices: fetcher(
      'Invoice',
      'List',
      { model: 'Audit', modelId: query.editId },
      { req, res }
    ),
    history: fetcher(
      'History',
      'List',
      {
        model: 'Audit',
        modelId: query.editId,
      },
      { req, res }
    ),
    extraForms: fetcher(
      'Form',
      'List',
      {
        model: 'Audit',
        modelId: query.editId,
      },
      { req, res }
    ),
    qas: fetcher('QA', 'List', { audit: query.editId }, { req, res }),
  });

  return {
    props: {
      editId: query.editId,
      parentId: query.parentId || null,
      ...fetchItems,
    },
  };
};

Here is the fetch many declaration

import { getCookie, setCookie, deleteCookie } from 'cookies-next';
import Router from 'next/router';
import { createToast } from './createToast';

export const fetcher = async (model, action, data, options = null) => {
  try {
    const accessToken = getCookie('accessToken', options);
    const idToken = getCookie('idToken', options);
    const refreshToken = getCookie('refreshToken', options);
    const perm = getCookie('perm', options);
    const userId = getCookie('userId', options);

    const res = await fetch(process.env.NEXT_PUBLIC_API_ENDPOINT + '/crud', {
      method: 'post',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        model,
        action,
        data,
        tokens: { accessToken, idToken, refreshToken },
        perm,
        userId,
      }),
    });
    const response = await res.json();
    if (response.tokens) {
      setCookie('accessToken', response.tokens.accessToken, options);
      setCookie('idToken', response.tokens.idToken, options);
      setCookie('refreshToken', response.tokens.refreshToken, options);
    }
    if (response.success) return response.data;
    createToast(
      response?.message || 'An error occured when retrieving data',
      'warning'
    );
    if (response.loggedOut) {
      deleteCookie('accessToken', options);
      deleteCookie('idToken', null, options);
      deleteCookie('refreshToken', null, options);
      if (!options) Router.push({ pathname: '/login' });
    }
    return null;
  } catch (e) {
    console.log(
      `Crud with model : ${model} and action: ${action} with data: ${JSON.stringify(
        data
      )} failed due to error: ${JSON.stringify(e)} `
    );
    return null;
  }
};

export const fetchMany = async (calls) => {
  try {
    const results = await Promise.allSettled(Object.values(calls));
    const resultObject = {};
    Object.keys(calls).forEach((key, i) => {
      resultObject[key] = results[i].value;
    });
    return resultObject;
  } catch (e) {
    console.log(`fetchMany failed due to error: ${JSON.stringify(e)} `);
    return {};
  }
};

fetchMany basically run 9 API calls and when the calls are finished the promise.all will return the value of all 9 of them and then it is deconstructed and passed as props

When I remove any 3 out of the 9 API calls page works perfectly however if I got to 7 or more page returns 502 Error.

If I use 9 singular await calls page doesn't work either. Finally I tried mix and match approach , keeping 6 calls in promise.all and 3 singular awaits and it still gave me 502 error. I tried a settimeout for 30 seconds and page loads so its not a timeout issue because the request rejects in 1s. I tried it witH API calls that return empty array as well so it is not response limit as well.

When I ran the same app on AWS EC2 m5.large I get this issue but I when I run it on vercel it works fine. Does AWS have a limit on number of sockets that can be opened at a time ?

asked 3 years ago313 views
1 Answer
0

Hello. Having a 50x error it implies a server error due server errors. In this case due to sizing or throttling of resources. Check that you did not go over the maximum number of files created by the system and that your function fetchMany is managing all the promises in the correct way.

I would suggest, logging each call in the above function and limit concurrent calls. Start small.

EXPERT
answered 2 years ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.