Found the solution! The issue was indeed related to database transactions. The afterChange hook executes within the active transaction, but the data hasn't been committed yet when the external rebuild process tries to read it.
To fix it, I just wrapped the fetch call in setImmediate() to execute it after the transaction commits:
import type { CollectionAfterChangeHook } from 'payload';
import dotenv from 'dotenv';
dotenv.config();
export const afterChangeHook: CollectionAfterChangeHook = async ({
doc,
operation,
}) => {
setImmediate(async () => {
try {
const rebuildURL = process.env.MANAGER_URL || ""
const response = await fetch(rebuildURL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
documentId: doc.id,
}),
});
if (!response.ok) {
console.error(`Rebuild Error: ${response.statusText}`)
} else {
console.log(`Rebuild successful: ${await response.text()}`)
}
} catch (err) {
console.error('Error in afterChangeHook:', err)
}
});
return doc;
}
I think this works because setImmediate() schedules execution for the next iteration of the Node.js event loop. At that point, all the payload operations should be finished, or at least the database transactions, and I think that is what is happening because it works now 😄 .
Thanks for your response @keen mason .