Skip to content

fix(plugin-multi-tenant): run tenant delete cleanup inside the request transaction#17045

Open
yashs33244 wants to merge 1 commit into
payloadcms:mainfrom
yashs33244:fix/multi-tenant-delete-tenant-global-hang
Open

fix(plugin-multi-tenant): run tenant delete cleanup inside the request transaction#17045
yashs33244 wants to merge 1 commit into
payloadcms:mainfrom
yashs33244:fix/multi-tenant-delete-tenant-global-hang

Conversation

@yashs33244

Copy link
Copy Markdown

What?

Deleting a tenant hangs forever (on Postgres) when the multi-tenant plugin has one or more collections marked isGlobal: true. The request never resolves and no error is thrown.

Fixes #16045

Why?

The tenants collection afterDelete hook (afterTenantDelete) cleans up tenant-scoped docs by calling payload.delete/find/update without passing req. Without req, each of those operations opens its own database transaction.

That cleanup runs while the parent tenant-delete transaction is still open and holding row locks. A global collection has a unique tenant field that FK-references the tenant row being deleted, so its cleanup delete needs a lock the parent transaction holds. The cleanup's separate transaction waits on the parent, and the parent waits for the hook to return - a cross-transaction deadlock across two pooled connections that Postgres can't detect, so it hangs indefinitely. SQLite happens to tolerate it, which is why it only reproduces on Postgres.

How?

Pass req to the cleanup delete, find, and update calls so they join the existing request transaction instead of opening new ones. This matches how other plugins (e.g. plugin-search's deleteFromSearch) propagate the transaction in their afterDelete hooks, and makes the cleanup atomic with the tenant delete.

Added an integration test that creates a tenant with a global-collection document and asserts the delete completes. It times out (hangs) without the fix and passes with it. Verified against Postgres and SQLite (pnpm test:int:postgres plugin-multi-tenant, pnpm test:int:sqlite plugin-multi-tenant).

@DanRibbens

Copy link
Copy Markdown
Contributor

As a heads up, the main branch is for work targeting our 4.0 release. If you want this backported to 3.0 you will need to open a separate PR. Please link to this PR so we track work against both.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Delete tenant hangs when using global collections

2 participants