API: Eliminate race condition in Image Builder API slice

The images table uses the useGetComposesQuery hook to fetch composes and
implement pagination. When this query is used, args are provided for the
offset and limit and a 'Compose' tag is provided for the query.

When a mutation is triggered (causing a POST request to be sent to the
`/compose` end point), the 'Compose' tag is invalidated which clears all
cached data from useGetComposesQuery hooks, which in turn causes the
table to refetch compose information.

If invalidating the `Compose` tag causes a refetch before the new compose
is available in image-builder, the result does not contain the new
compose and the table is not updated to include it.

This commit eliminates the race condition by waiting for the query to be
fulfilled before invalidating tags (and therefore before refetching the
data).

All of the above applies equally to the `cloneCompose` mutation, and its
race condition has also been eliminated.

This commit is loosely inspired by the RTK Query docs section on
pessimistic updates:
https://redux-toolkit.js.org/rtk-query/usage/manual-cache-updates#pessimistic-updates

Typescript complains about the type of the tags. It does not recognize
the tag types that are defined in the same enhanceEndpoint() function.
For now, we simply ignore the Typescript errors. There is some
discussion here: https://github.com/reduxjs/redux-toolkit/issues/1510
This commit is contained in:
lucasgarfield 2023-10-10 12:29:43 +02:00 committed by Jakub Rusz
parent c73824cd22
commit 6e018ce7c8
2 changed files with 26 additions and 7 deletions

View file

@ -593,20 +593,20 @@ const CreateImageWizard = () => {
return (
<ImageCreator
onClose={handleClose}
onSubmit={({ values, setIsSaving }) => {
onSubmit={async ({ values, setIsSaving }) => {
setIsSaving(true);
const requests = onSave(values);
navigate(resolveRelPath(''));
// https://redux-toolkit.js.org/rtk-query/usage/mutations#frequently-used-mutation-hook-return-values
// If you want to immediately access the result of a mutation, you need to chain `.unwrap()`
// if you actually want the payload or to catch the error.
// We do this so we can dispatch the appropriate notification (success or failure).
Promise.all(
await Promise.all(
requests.map((composeRequest) =>
composeImage({ composeRequest }).unwrap()
)
)
.then(() => {
navigate(resolveRelPath(''));
dispatch(
addNotification({
variant: 'success',
@ -620,6 +620,7 @@ const CreateImageWizard = () => {
msg = err.response.data?.errors[0]?.detail;
}
navigate(resolveRelPath(''));
dispatch(
addNotification({
variant: 'danger',