chore(): Improve caching rollout (#13702)
* chore(): Improve caching rollout * Create bright-cobras-complain.md * chore(): Improve caching rollout * downgrade orm to 6.4.3 * chore(): Improve caching rollout * chore(): Improve caching rollout * chore(): Improve caching rollout * chore(): Improve caching rollout * chore(): Improve caching rollout * fix * update changeset * update modules definition * update engine tests * update engine tests * improve integration * improve integration * gracefully disconnect * update test * another attempt * another attempt * fix workflow storage * fix remote joiner * fix remote joiner --------- Co-authored-by: Oli Juhl <59018053+olivermrbl@users.noreply.github.com>
This commit is contained in:
co-authored by
Oli Juhl
parent
e9b7a8c1f3
commit
0cbd9f0bc3
@@ -1,9 +1,8 @@
|
||||
import { MedusaContainer } from "@medusajs/framework/types"
|
||||
import {
|
||||
IRegionModuleService,
|
||||
IStoreModuleService,
|
||||
MedusaContainer,
|
||||
} from "@medusajs/framework/types"
|
||||
import { MedusaError, Modules, useCache } from "@medusajs/framework/utils"
|
||||
ContainerRegistrationKeys,
|
||||
MedusaError,
|
||||
} from "@medusajs/framework/utils"
|
||||
import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk"
|
||||
|
||||
/**
|
||||
@@ -17,45 +16,54 @@ export type FindOneOrAnyRegionStepInput = {
|
||||
}
|
||||
|
||||
async function fetchRegionById(regionId: string, container: MedusaContainer) {
|
||||
const service = container.resolve<IRegionModuleService>(Modules.REGION)
|
||||
const query = container.resolve(ContainerRegistrationKeys.QUERY)
|
||||
|
||||
const args = [
|
||||
regionId,
|
||||
const { data } = await query.graph(
|
||||
{
|
||||
relations: ["countries"],
|
||||
entity: "region",
|
||||
filters: { id: regionId },
|
||||
fields: ["*", "countries.*"],
|
||||
},
|
||||
] as Parameters<IRegionModuleService["retrieveRegion"]>
|
||||
{
|
||||
cache: { enable: true },
|
||||
}
|
||||
)
|
||||
|
||||
return await useCache(async () => service.retrieveRegion(...args), {
|
||||
container,
|
||||
key: args,
|
||||
})
|
||||
return data?.[0]
|
||||
}
|
||||
|
||||
async function fetchDefaultStore(container: MedusaContainer) {
|
||||
const storeModule = container.resolve<IStoreModuleService>(Modules.STORE)
|
||||
const query = container.resolve(ContainerRegistrationKeys.QUERY)
|
||||
|
||||
return await useCache(async () => storeModule.listStores(), {
|
||||
container,
|
||||
key: "find-one-or-any-region-default-store",
|
||||
})
|
||||
const { data } = await query.graph(
|
||||
{
|
||||
entity: "store",
|
||||
fields: ["*"],
|
||||
},
|
||||
{
|
||||
cache: { enable: true },
|
||||
}
|
||||
)
|
||||
|
||||
return data?.[0]
|
||||
}
|
||||
|
||||
async function fetchDefaultRegion(
|
||||
defaultRegionId: string,
|
||||
container: MedusaContainer
|
||||
) {
|
||||
const service = container.resolve<IRegionModuleService>(Modules.REGION)
|
||||
const query = container.resolve(ContainerRegistrationKeys.QUERY)
|
||||
|
||||
const args = [
|
||||
{ id: defaultRegionId },
|
||||
{ relations: ["countries"] },
|
||||
] as Parameters<IRegionModuleService["listRegions"]>
|
||||
const { data } = await query.graph(
|
||||
{
|
||||
entity: "region",
|
||||
filters: { id: defaultRegionId },
|
||||
fields: ["*", "countries.*"],
|
||||
},
|
||||
{ cache: { enable: true } }
|
||||
)
|
||||
|
||||
return await useCache(async () => service.listRegions(...args), {
|
||||
container,
|
||||
key: args,
|
||||
})
|
||||
return data?.[0]
|
||||
}
|
||||
|
||||
export const findOneOrAnyRegionStepId = "find-one-or-any-region"
|
||||
@@ -74,16 +82,13 @@ export const findOneOrAnyRegionStep = createStep(
|
||||
}
|
||||
}
|
||||
|
||||
const [store] = await fetchDefaultStore(container)
|
||||
const store = await fetchDefaultStore(container)
|
||||
|
||||
if (!store) {
|
||||
throw new MedusaError(MedusaError.Types.NOT_FOUND, "Store not found")
|
||||
}
|
||||
|
||||
const [region] = await fetchDefaultRegion(
|
||||
store.default_region_id!,
|
||||
container
|
||||
)
|
||||
const region = await fetchDefaultRegion(store.default_region_id!, container)
|
||||
|
||||
if (!region) {
|
||||
return new StepResponse(null)
|
||||
|
||||
@@ -24,7 +24,6 @@ import {
|
||||
createRemoteLinkStep,
|
||||
emitEventStep,
|
||||
useQueryGraphStep,
|
||||
useRemoteQueryStep,
|
||||
} from "../../common"
|
||||
import { acquireLockStep } from "../../locking/steps/acquire-lock"
|
||||
import { releaseLockStep } from "../../locking/steps/release-lock"
|
||||
@@ -118,17 +117,19 @@ export const completeCartWorkflow = createWorkflow(
|
||||
return orderCart?.data?.order_id
|
||||
})
|
||||
|
||||
const cart = useRemoteQueryStep({
|
||||
entry_point: "cart",
|
||||
const cartData = useQueryGraphStep({
|
||||
entity: "cart",
|
||||
fields: completeCartFields,
|
||||
variables: { id: input.id },
|
||||
list: false,
|
||||
filters: { id: input.id },
|
||||
options: {
|
||||
isList: false,
|
||||
},
|
||||
}).config({
|
||||
name: "cart-query",
|
||||
})
|
||||
|
||||
// this needs to be before the validation step
|
||||
const paymentSessions = validateCartPaymentsStep({ cart })
|
||||
const paymentSessions = validateCartPaymentsStep({ cart: cartData.data })
|
||||
// purpose of this step is to run compensation if cart completion fails
|
||||
// and tries to refund the payment if captured
|
||||
compensatePaymentIfNeededStep({
|
||||
@@ -137,48 +138,58 @@ export const completeCartWorkflow = createWorkflow(
|
||||
|
||||
const validate = createHook("validate", {
|
||||
input,
|
||||
cart,
|
||||
cart: cartData.data,
|
||||
})
|
||||
|
||||
// If order ID does not exist, we are completing the cart for the first time
|
||||
const order = when("create-order", { orderId }, ({ orderId }) => {
|
||||
return !orderId
|
||||
}).then(() => {
|
||||
const cartOptionIds = transform({ cart }, ({ cart }) => {
|
||||
const cartOptionIds = transform({ cart: cartData.data }, ({ cart }) => {
|
||||
return cart.shipping_methods?.map((sm) => sm.shipping_option_id)
|
||||
})
|
||||
|
||||
const shippingOptions = useRemoteQueryStep({
|
||||
entry_point: "shipping_option",
|
||||
const shippingOptionsData = useQueryGraphStep({
|
||||
entity: "shipping_option",
|
||||
fields: ["id", "shipping_profile_id"],
|
||||
variables: { id: cartOptionIds },
|
||||
list: true,
|
||||
filters: { id: cartOptionIds },
|
||||
options: {
|
||||
cache: {
|
||||
enable: true,
|
||||
},
|
||||
},
|
||||
}).config({
|
||||
name: "shipping-options-query",
|
||||
})
|
||||
|
||||
validateShippingStep({ cart, shippingOptions })
|
||||
|
||||
const { variants, sales_channel_id } = transform({ cart }, (data) => {
|
||||
const variantsMap: Record<string, any> = {}
|
||||
const allItems = data.cart?.items?.map((item) => {
|
||||
variantsMap[item.variant_id] = item.variant
|
||||
|
||||
return {
|
||||
id: item.id,
|
||||
variant_id: item.variant_id,
|
||||
quantity: item.quantity,
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
variants: Object.values(variantsMap),
|
||||
items: allItems,
|
||||
sales_channel_id: data.cart.sales_channel_id,
|
||||
}
|
||||
validateShippingStep({
|
||||
cart: cartData.data,
|
||||
shippingOptions: shippingOptionsData.data,
|
||||
})
|
||||
|
||||
const cartToOrder = transform({ cart }, ({ cart }) => {
|
||||
const { variants, sales_channel_id } = transform(
|
||||
{ cart: cartData.data },
|
||||
(data) => {
|
||||
const variantsMap: Record<string, any> = {}
|
||||
const allItems = data.cart?.items?.map((item) => {
|
||||
variantsMap[item.variant_id] = item.variant
|
||||
|
||||
return {
|
||||
id: item.id,
|
||||
variant_id: item.variant_id,
|
||||
quantity: item.quantity,
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
variants: Object.values(variantsMap),
|
||||
items: allItems,
|
||||
sales_channel_id: data.cart.sales_channel_id,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const cartToOrder = transform({ cart: cartData.data }, ({ cart }) => {
|
||||
const allItems = (cart.items ?? []).map((item) => {
|
||||
const input: PrepareLineItemDataInput = {
|
||||
item,
|
||||
@@ -290,15 +301,18 @@ export const completeCartWorkflow = createWorkflow(
|
||||
prepareConfirmInventoryInput
|
||||
)
|
||||
|
||||
const updateCompletedAt = transform({ cart }, ({ cart }) => {
|
||||
return {
|
||||
id: cart.id,
|
||||
completed_at: new Date(),
|
||||
const updateCompletedAt = transform(
|
||||
{ cart: cartData.data },
|
||||
({ cart }) => {
|
||||
return {
|
||||
id: cart.id,
|
||||
completed_at: new Date(),
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
const promotionUsage = transform(
|
||||
{ cart },
|
||||
{ cart: cartData.data },
|
||||
({ cart }: { cart: CartWorkflowDTO }) => {
|
||||
const promotionUsage: UsageComputedActions[] = []
|
||||
|
||||
@@ -329,7 +343,7 @@ export const completeCartWorkflow = createWorkflow(
|
||||
)
|
||||
|
||||
const linksToCreate = transform(
|
||||
{ cart, createdOrder },
|
||||
{ cart: cartData.data, createdOrder },
|
||||
({ cart, createdOrder }) => {
|
||||
const links: LinkDefinition[] = [
|
||||
{
|
||||
@@ -414,7 +428,7 @@ export const completeCartWorkflow = createWorkflow(
|
||||
*/
|
||||
createHook("orderCreated", {
|
||||
order_id: createdOrder.id,
|
||||
cart_id: cart.id,
|
||||
cart_id: cartData.data.id,
|
||||
})
|
||||
|
||||
return createdOrder
|
||||
|
||||
+27
-16
@@ -1,4 +1,8 @@
|
||||
import { isDefined, ShippingOptionPriceType } from "@medusajs/framework/utils"
|
||||
import {
|
||||
isDefined,
|
||||
QueryContext,
|
||||
ShippingOptionPriceType,
|
||||
} from "@medusajs/framework/utils"
|
||||
import {
|
||||
createHook,
|
||||
createWorkflow,
|
||||
@@ -11,6 +15,7 @@ import {
|
||||
AdditionalData,
|
||||
CalculateShippingOptionPriceDTO,
|
||||
ListShippingOptionsForCartWithPricingWorkflowInput,
|
||||
QueryContextType,
|
||||
} from "@medusajs/framework/types"
|
||||
|
||||
import { useQueryGraphStep, validatePresenceOfStep } from "../../common"
|
||||
@@ -206,14 +211,21 @@ export const listShippingOptionsForCartWithPricingWorkflow = createWorkflow(
|
||||
setShippingOptionsContext.getResult()
|
||||
|
||||
const commonOptions = transform(
|
||||
{ input, cart, fulfillmentSetIds, setShippingOptionsContextResult },
|
||||
{
|
||||
input,
|
||||
cart,
|
||||
fulfillmentSetIds,
|
||||
optionIds,
|
||||
setShippingOptionsContextResult,
|
||||
},
|
||||
({
|
||||
input,
|
||||
cart,
|
||||
fulfillmentSetIds,
|
||||
optionIds,
|
||||
setShippingOptionsContextResult,
|
||||
}) => ({
|
||||
context: {
|
||||
context: QueryContext({
|
||||
...(setShippingOptionsContextResult
|
||||
? setShippingOptionsContextResult
|
||||
: {}),
|
||||
@@ -223,9 +235,10 @@ export const listShippingOptionsForCartWithPricingWorkflow = createWorkflow(
|
||||
: input.enabled_in_store
|
||||
? "true"
|
||||
: "false",
|
||||
},
|
||||
}),
|
||||
|
||||
filters: {
|
||||
id: optionIds.length ? optionIds : undefined,
|
||||
fulfillment_set_id: fulfillmentSetIds,
|
||||
|
||||
address: {
|
||||
@@ -238,21 +251,19 @@ export const listShippingOptionsForCartWithPricingWorkflow = createWorkflow(
|
||||
})
|
||||
)
|
||||
|
||||
const typeQueryFilters = transform(
|
||||
{ optionIds, commonOptions },
|
||||
({ optionIds, commonOptions }) => ({
|
||||
id: optionIds.length ? optionIds : undefined,
|
||||
...commonOptions,
|
||||
})
|
||||
)
|
||||
|
||||
/**
|
||||
* We need to prefetch exact same SO as in the final result but only to determine pricing calculations first.
|
||||
*/
|
||||
const initialOptions = useRemoteQueryStep({
|
||||
entry_point: "shipping_options",
|
||||
variables: typeQueryFilters,
|
||||
const { data: initialOptions } = useQueryGraphStep({
|
||||
entity: "shipping_options",
|
||||
fields: ["id", "price_type"],
|
||||
filters: commonOptions.filters,
|
||||
context: commonOptions.context as QueryContextType,
|
||||
options: {
|
||||
cache: {
|
||||
enable: true,
|
||||
},
|
||||
},
|
||||
}).config({ name: "shipping-options-price-type-query" })
|
||||
|
||||
/**
|
||||
@@ -261,7 +272,7 @@ export const listShippingOptionsForCartWithPricingWorkflow = createWorkflow(
|
||||
const { flatRateOptionsQuery, calculatedShippingOptionsQuery } = transform(
|
||||
{
|
||||
cart,
|
||||
initialOptions,
|
||||
initialOptions: initialOptions,
|
||||
commonOptions,
|
||||
},
|
||||
({ cart, initialOptions, commonOptions }) => {
|
||||
|
||||
@@ -83,12 +83,16 @@ export const transferCartCustomerWorkflow = createWorkflow(
|
||||
entity: "customer",
|
||||
filters: { id: input.customer_id },
|
||||
fields: ["id", "email"],
|
||||
options: { throwIfKeyNotFound: true },
|
||||
options: {
|
||||
throwIfKeyNotFound: true,
|
||||
isList: false,
|
||||
cache: { enable: true },
|
||||
},
|
||||
}).config({ name: "get-customer" })
|
||||
|
||||
const customer = transform(
|
||||
{ customerQuery },
|
||||
({ customerQuery }) => customerQuery.data[0]
|
||||
({ customerQuery }) => customerQuery.data
|
||||
)
|
||||
|
||||
// If its the same customer, we don't want the email to be overridden, so we skip the
|
||||
|
||||
@@ -72,11 +72,17 @@ export const listShippingOptionsForOrderWorkflow = createWorkflow(
|
||||
entity: "sales_channels",
|
||||
filters: { id: order.sales_channel_id },
|
||||
fields: [
|
||||
"id",
|
||||
"stock_locations.fulfillment_sets.id",
|
||||
"stock_locations.id",
|
||||
"stock_locations.name",
|
||||
"stock_locations.address.*",
|
||||
],
|
||||
options: {
|
||||
cache: {
|
||||
enable: true,
|
||||
},
|
||||
},
|
||||
}).config({ name: "sales_channels-fulfillment-query" })
|
||||
|
||||
const scFulfillmentSets = transform(
|
||||
|
||||
@@ -70,10 +70,10 @@ export const maybeRefreshShippingMethodsWorkflowId =
|
||||
/**
|
||||
* This workflows refreshes shipping method prices of an order and its changes. It's used in Return Merchandise Authorization (RMA) flows. It's used
|
||||
* by other workflows, such as {@link refreshExchangeShippingWorkflow}.
|
||||
*
|
||||
*
|
||||
* You can use this workflow within your customizations or your own custom workflows, allowing you to wrap custom logic around
|
||||
* refreshing shipping methods in your custom flows.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* const { result } = await maybeRefreshShippingMethodsWorkflow(container)
|
||||
* .run({
|
||||
@@ -92,9 +92,9 @@ export const maybeRefreshShippingMethodsWorkflowId =
|
||||
* }
|
||||
* }
|
||||
* })
|
||||
*
|
||||
*
|
||||
* @summary
|
||||
*
|
||||
*
|
||||
* Refreshes the shipping method prices of an order and its changes.
|
||||
*/
|
||||
export const maybeRefreshShippingMethodsWorkflow = createWorkflow(
|
||||
@@ -116,6 +116,11 @@ export const maybeRefreshShippingMethodsWorkflow = createWorkflow(
|
||||
entity: "shipping_option",
|
||||
fields: [...COMMON_OPTIONS_FIELDS],
|
||||
filters: { id: shippingMethod.shipping_option_id },
|
||||
options: {
|
||||
cache: {
|
||||
enable: true,
|
||||
},
|
||||
},
|
||||
}).config({ name: "calculated-option" })
|
||||
|
||||
const shippingOption = transform(shippingOptionQuery, ({ data }) => data[0])
|
||||
|
||||
Reference in New Issue
Block a user