Simplify your stack and build anything. Or everything.
Build tomorrow’s web with a modern solution you truly own.
Code-based nature means you can build on top of it to power anything.
It’s time to take back your content infrastructure.

Payload fails to run afterChange hook relialibly when deployed on Vercel (serverless)

default discord avatar
martafiixeklast year
10

Hi, I have an interesting problem. I run Payload on Vercel, however, even though I change the content and save it in the admin interface, the

afterChange

hook is not ran.



I have to save the content one more time, and then it works. On

localhost

, everything is working fine.



The regeneratePage function is simple


export const regeneratePage = async ({
  doc,
  collection,
  payload,
}: {
  doc?: Document
  collection?: 'catalogues' | 'countries'
  payload: Payload
}): Promise<void> => {
  try {
    const siteUrl = process.env.SITE_URL

    let path: string | null = null

    if (collection === 'catalogues') {
      const country = await payload.findByID({
        collection: 'countries',
        id: doc.country,
      })
      path = `/${addApiSuffix(country?.label_url)}/${addApiSuffix(
        doc.publisher.name_url
      )}`
    } else if (collection === 'countries') {
      path = `/${addApiSuffix(doc?.label_url)}`
    }

    const res = await fetch(`${siteUrl}/api/revalidate`, {
      method: 'POST',
      body: path,
    })
    console.log(path)
    if (res.ok) {
      payload.logger.info(`Revalidated`)
    } else {
      payload.logger.error(`Error revalidating`)
    }
  } catch (err: unknown) {
    payload.logger.error(`Error hitting revalidate route}`)
  }
}


Looking at the Vercel function logs, I don't see any fetch request to

api/revalidate

, and I don't see Payload trying to connect to DB to find the countries



What most of the time works is saving the content two or three times in a row

  • default discord avatar
    imcorfitzlast year

    This sounds more like a timeout issue on Vercel than a problem with Payload.

    https://vercel.com/docs/concepts/limits/overview
  • default discord avatar
    martafiixeklast year

    I don't think so



    Vercel would throw a timeout error



    Also the regenerate function does not take more than 2 seconds

  • default discord avatar
    imcorfitzlast year

    Do you only have one afterChange hook - or multiple?

  • default discord avatar
    martafiixeklast year

    Two hooks, one hook one collection

  • default discord avatar
    imcorfitzlast year

    Can you share the entire collection config?

  • default discord avatar
    martafiixeklast year

    Sure, give a moment



    I'm in a public transport



    By the way thanks for the help

  • default discord avatar
    imcorfitzlast year

    I'm in a warm office with broken A/C. Slower pace is permitted.

  • default discord avatar
    martafiixeklast year

    F



    So, this is the collection:



    import { regeneratePage } from '../utilities/regeneratePage'
    import { Quote } from '../blocks/Quote'
    import { CollectionConfig } from 'payload/types'
    import { RichText } from '../blocks/RichText'
    import { Table } from '../blocks/Table'
    
    const Catalogues: CollectionConfig = {
      slug: 'catalogues',
      labels: {
        singular: 'Catalogue',
        plural: 'Catalogues',
      },
      timestamps: true,
      typescript: {
        interface: 'ICatalog',
      },
      access: {
        read: () => true,
      },
      hooks: {
        afterChange: [
          ({ doc, req: { payload } }) => {
            regeneratePage({
              collection: 'catalogues',
              doc,
              payload,
            })
          },
        ],
      },
      admin: {
        description: 'Collection of unique catalogues.',
        hideAPIURL: true,
      },
      fields: [
        {
          name: 'code',
          type: 'text',
          label: 'Code',
          admin: {
            readOnly: true,
            hidden: true,
          },
        },
        {
          name: 'title',
          type: 'json',
          label: 'Title',
          admin: {
            readOnly: true,
          },
        },
        {
          name: 'description',
          type: 'json',
          label: 'Description',
          admin: {
            readOnly: true,
            hidden: true,
          },
        },
        {
          name: 'slug',
          type: 'text',
          label: 'Slug',
          admin: {
            readOnly: true,
            hidden: true,
          },
        },
        {
          name: 'homepage',
          type: 'text',
          label: 'Homepage',
          admin: {
            readOnly: true,
            hidden: true,
          },
        },
        {
          name: 'country',
          type: 'relationship',
          relationTo: 'countries',
          hasMany: false,
          admin: {
            readOnly: true,
            hidden: true,
          },
        },
        {
          name: 'publisher',
          label: 'Publisher',
          type: 'json',
          admin: {
            readOnly: true,
            hidden: true,
          },
        },
        {
          label: 'Components',
          labels: {
            singular: 'Component',
            plural: 'Components',
          },
          name: 'layout',
          type: 'blocks',
          blocks: [Quote, Table, RichText],
        },
      ],
    }
    
    export default Catalogues


    So, it somehow fails on:



    const country = await payload.findByID({
            collection: 'countries',
            id: doc.country,
          })


    The serverless function runs for 353 ms and ends on the

    findById

    When I click on save again, the function somehow runs again (seems like)





    And then the

    /api/revalidate

    is called



    Nevermind, I fixed it



    I am dumb

  • default discord avatar
    imcorfitzlast year

    Lol. Been there mate. Great you got it resolved. 🍾

  • default discord avatar
    martafiixeklast year

    The regenerate page did not have await and the function containing it didnt have async

    :facepalm:
Star on GitHub

Star

Chat on Discord

Discord

online

Can't find what you're looking for?

Get dedicated engineering support directly from the Payload team.