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.

Postgres Deadlock when updating other collections in `afterChange` hook

default discord avatar
notalecclast year
11

Hi all,



We're using Payload with a Postgres 17 server for the database (using

@payloadcms/db-postgres

). Nothing is running in a function, so we aren't using the Vercel package.



However, after switching to Postgres from MongoDB, we've been getting errors like this:


Error processing test: error: canceling statement due to statement timeout
    at async PaymentEvents.hooks.afterChange (src/collections/Test.ts:233:4)
    at async handleCheckoutSessionCompleted (src/app/api/test/route.ts:73:1)
    at async POST (src/app/api/test/route.ts:97:3)
  231 |
  232 |                                 // Update user's credits
> 233 |                                 await req.payload.update({
      |                         ^
  234 |                                         collection: "users",
  235 |                                         id: userId,
  236 |                                         data: { {
  length: 156,
  severity: 'ERROR',
  code: '57014',
  where: 'while locking tuple (0,8) in relation "users"',
  routine: 'ProcessInterrupts'
}


Generally though, Payload will completly freeze and needs to be restarted. The problematic code looks like this:


Test.ts

(the Test collection)


hooks: {
        afterChange: [
            async ({ doc, req, previousDoc }) => {
                const { user, amount, type } = doc;
                const userId = typeof user === "string" ? user : user.id;
                // Get the current user to do something
                const targetUser = await req.payload.findByID({
                    collection: "users",
                    id: userId,
                });
                // Do something with the user
                await req.payload.update({
                    collection: "users",
                    id: userId,
                    data: {
                        some_field: true
                    },
                });
                return doc;


Does anyone have any insight on why this is happening?

  • default discord avatar
    zed0547last year

    You need to pass

    req

    to your payload local api calls:


    // Do something with the user
    await req.payload.update({
      collection: "users",
      id: userId,
      data: {
          some_field: true
      },
      req // Add this
    });


    See here for info:

    https://payloadcms.com/docs/local-api/overview#transactions
  • default discord avatar
    notalecclast year

    Interesting, added this to both the

    req.payload.findByID

    and

    req.payload.update

    functions, and now its hanging at the

    .update

    function.



    HOWEVER, that doc was super helpful, by adding

    disableTransaction: true

    to the

    .update

    call, it no longer hangs



    Do you have any ideas why a transaction would cause the update to fail?

  • default discord avatar
    zed0547last year

    Is this afterChange on the

    users

    collection?



    Because that would throw this into an infinite loop

  • default discord avatar
    notalecclast year

    no, should have been more clear. This is in the

    Test

    collection



    the

    Test

    collection has a

    User

    field

  • default discord avatar
    zed0547last year

    Hmm



    Not sure, with the

    req

    added it shouldn't hang I don't think unless I'm missing key info on other hooks that might be triggering more complex interactions between these two collections



    Want to try something?



    Re-add transactions in config, then remove the

    req

    from the find, but keep it in the

    update
  • default discord avatar
    notalecclast year

    kk



    Works 🤨

  • default discord avatar
    zed0547last year

    Ah, yes, I think there's either something left over by a previous transaction, or something conflicting when used in both find() and update() at the same time



    I have a PR that illustrates this in

    plugin-search

    :

    https://github.com/payloadcms/payload/pull/9623
  • default discord avatar
    notalecclast year

    Yeah this PR is the exact same behavior

  • default discord avatar
    zed0547last year

    Not sure, I know they know of it internally though!

  • default discord avatar
    notalecclast year

    The

    req

    thing is a decent work-around for the time being though, so thanks ❤️

  • default discord avatar
    zed0547last year

    It's my pleasure! Glad you got it working

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.