From d9574f734eefe1ece91f761a3105aa323ecab4de Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Wed, 27 Nov 2024 18:52:19 +0200 Subject: [PATCH] docs: update sanity guide + marketplace recipe to use permanentFailure (#10310) --- .../app/integrations/guides/sanity/page.mdx | 50 +++++++++++-------- .../marketplace/examples/vendors/page.mdx | 39 +++++++-------- www/apps/resources/generated/edit-dates.mjs | 4 +- 3 files changed, 49 insertions(+), 44 deletions(-) diff --git a/www/apps/resources/app/integrations/guides/sanity/page.mdx b/www/apps/resources/app/integrations/guides/sanity/page.mdx index 16dc7ef2b2bee..24efda6cd7a99 100644 --- a/www/apps/resources/app/integrations/guides/sanity/page.mdx +++ b/www/apps/resources/app/integrations/guides/sanity/page.mdx @@ -703,9 +703,9 @@ export const syncStep = createStep( const batchSize = 200 const hasMore = true const offset = 0 - const filters = { - id: input.product_ids || [], - } + let filters = input.product_ids ? { + id: input.product_ids + } : {} while (hasMore) { const { @@ -719,7 +719,6 @@ export const syncStep = createStep( // @ts-ignore "sanity_product.*", ], - // @ts-ignore filters, pagination: { skip: offset, @@ -777,22 +776,29 @@ export const syncStep = createStep( while (hasMore) { // ... - await promiseAll( - products.map(async (prod) => { - const after = await sanityModule.upsertSyncDocument( - "product", - prod as ProductDTO - ) - - upsertMap.push({ - // @ts-ignore - before: prod.sanity_product, - after, - }) - - return after - }) - ) + try { + await promiseAll( + products.map(async (prod) => { + const after = await sanityModule.upsertSyncDocument( + "product", + prod as ProductDTO + ); + + upsertMap.push({ + // @ts-ignore + before: prod.sanity_product, + after + }) + + return after + }), + ) + } catch (e) { + return StepResponse.permanentFailure( + `An error occurred while syncing documents: ${e}`, + upsertMap + ) + } offset += batchSize hasMore = offset < count @@ -808,7 +814,9 @@ In the `while` loop, you loop over the array of products to sync them to Sanity. For each product, you upsert it into Sanity, then push its document before and after the update to the `upsertMap`. You'll learn more about its use later. -The step returns an instance of `StepResponse`, which must be returned by any step. It accepts as a first parameter the data to return to the workflow that executed this step. +You also wrap the `promiseAll` function within a try-catch block. In the catch block, you invoke and return `StepResponse.permanentFailure` which indicates that the step has failed but still invokes the rollback mechanism that you'll implement in a bit. The first parameter of `permanentFailure` is the error message, and the second is the data to use in the rollback mechanism. + +If no errors occur, the step returns an instance of `StepResponse`, which must be returned by any step. It accepts as a first parameter the data to return to the workflow that executed this step. #### Add Compensation Function diff --git a/www/apps/resources/app/recipes/marketplace/examples/vendors/page.mdx b/www/apps/resources/app/recipes/marketplace/examples/vendors/page.mdx index 0469abad0f33f..eda36bbf40119 100644 --- a/www/apps/resources/app/recipes/marketplace/examples/vendors/page.mdx +++ b/www/apps/resources/app/recipes/marketplace/examples/vendors/page.mdx @@ -893,10 +893,10 @@ import { LinkDefinition, InferTypeOf, } from "@medusajs/framework/types" -import { Modules } from "@medusajs/framework/utils" +import { Modules, promiseAll } from "@medusajs/framework/utils" import { - createOrdersWorkflow, cancelOrderWorkflow, + createOrderWorkflow } from "@medusajs/medusa/core-flows" import MarketplaceModuleService from "../../../../modules/marketplace/service" import { MARKETPLACE_MODULE } from "../../../../modules/marketplace" @@ -1009,12 +1009,12 @@ export const vendorOrder3Highlights = [ ```ts title="src/workflows/marketplace/create-vendor-orders/steps/create-vendor-orders.ts" highlights={vendorOrder3Highlights} try { - await Promise.all( + await promiseAll( vendorIds.map(async (vendorId) => { const items = vendorsItems[vendorId] - const vendor = vendors.find((v) => v.id === vendorId)! + const vendor = vendors.find(v => v.id === vendorId)! - const { result: childOrder } = await createOrdersWorkflow( + const {result: childOrder} = await createOrderWorkflow( container ) .run({ @@ -1027,31 +1027,28 @@ try { linkDefs.push({ [MARKETPLACE_MODULE]: { - vendor_id: vendor.id, + vendor_id: vendor.id }, [Modules.ORDER]: { - order_id: childOrder.id, - }, + order_id: childOrder.id + } }) }) ) } catch (e) { - await Promise.all(createdOrders.map((createdOrder) => { - return cancelOrderWorkflow(container).run({ - input: { - order_id: createdOrder.id, - }, - context, - container, - }) - })) - - throw e + return StepResponse.permanentFailure( + `An error occured while creating vendor orders: ${e}`, + { + created_orders: createdOrders + } + ) } ``` In this snippet, you create multiple child orders for each vendor and link the orders to the vendors. +You use the `promiseAll` utility imported from `@medusajs/framework/utils` that loops over an array of promises and ensures that all transactions within these promises are rolled back in case an error occurs. You also wrap `promiseAll` in a try-catch block, and in the catch block you invoke and return `StepResponse.permanentFailure` which indicates that the step has failed but still invokes the compensation function that you'll implement in a bit. The first parameter of `permanentFailure` is the error message, and the second is the data to pass to the compensation function. + If an error occurs, the created orders in the `createdOrders` array are canceled using Medusa's `cancelOrderWorkflow` from the `@medusajs/medusa/core-flows` package. The order's data is formatted using the `prepareOrderData` function. Replace its definition with the following: @@ -1165,7 +1162,7 @@ const createVendorOrdersWorkflow = createWorkflow( (input: WorkflowInput) => { const { data: carts } = useQueryGraphStep({ entity: "cart", - fields: ["items.*"], + fields: ["id", "items.*"], filters: { id: input.cart_id }, options: { throwIfKeyNotFound: true, @@ -1179,7 +1176,7 @@ const createVendorOrdersWorkflow = createWorkflow( }) const { vendorsItems } = groupVendorItemsStep({ - cart: carts[0].id, + cart: carts[0] }) const order = getOrderDetailWorkflow.runAsStep({ diff --git a/www/apps/resources/generated/edit-dates.mjs b/www/apps/resources/generated/edit-dates.mjs index b56f4b98fec8e..43b651839065a 100644 --- a/www/apps/resources/generated/edit-dates.mjs +++ b/www/apps/resources/generated/edit-dates.mjs @@ -130,7 +130,7 @@ export const generatedEditDates = { "app/recipes/digital-products/page.mdx": "2024-10-03T13:07:44.147Z", "app/recipes/ecommerce/page.mdx": "2024-10-22T11:01:01.218Z", "app/recipes/integrate-ecommerce-stack/page.mdx": "2024-10-16T08:52:16.760Z", - "app/recipes/marketplace/examples/vendors/page.mdx": "2024-10-16T08:52:24.906Z", + "app/recipes/marketplace/examples/vendors/page.mdx": "2024-11-27T10:30:50.653Z", "app/recipes/marketplace/page.mdx": "2024-10-03T13:07:44.153Z", "app/recipes/multi-region-store/page.mdx": "2024-10-03T13:07:13.813Z", "app/recipes/omnichannel/page.mdx": "2024-10-03T13:07:14.384Z", @@ -3252,7 +3252,7 @@ export const generatedEditDates = { "references/types/HttpTypes/interfaces/types.HttpTypes.AdminBatchProductVariantRequest/page.mdx": "2024-11-25T17:49:26.851Z", "references/types/WorkflowTypes/ProductWorkflow/interfaces/types.WorkflowTypes.ProductWorkflow.ExportProductsDTO/page.mdx": "2024-11-12T09:36:24.232Z", "app/contribution-guidelines/admin-translations/page.mdx": "2024-11-14T08:54:15.369Z", - "app/integrations/guides/sanity/page.mdx": "2024-11-19T10:07:24.519Z", + "app/integrations/guides/sanity/page.mdx": "2024-11-27T10:10:12.100Z", "references/api_key/types/api_key.FindConfigOrder/page.mdx": "2024-11-25T17:49:28.715Z", "references/auth/types/auth.FindConfigOrder/page.mdx": "2024-11-25T17:49:28.887Z", "references/cart/types/cart.FindConfigOrder/page.mdx": "2024-11-25T17:49:29.455Z",