feat(locking): Locking module (#9524)

**What**
- Locking Module to manage concurrency
- Default `in-memory` provider
This commit is contained in:
Carlos R. L. Rodrigues
2024-10-11 16:30:06 +00:00
committed by GitHub
parent 5c9e289c4d
commit c8b375ae2d
28 changed files with 806 additions and 39 deletions
+17 -15
View File
@@ -1,36 +1,37 @@
import { Knex } from "@mikro-orm/knex"
import { RemoteLink } from "@medusajs/modules-sdk"
import { AwilixContainer, ResolveOptions } from "awilix"
import { Modules, ContainerRegistrationKeys } from "@medusajs/utils"
import {
Logger,
ConfigModule,
ModuleImplementations,
RemoteQueryFunction,
IApiKeyModuleService,
IAuthModuleService,
ICacheService,
ICartModuleService,
ICurrencyModuleService,
ICustomerModuleService,
IEventBusModuleService,
IFileModuleService,
IFulfillmentModuleService,
IInventoryService,
ILockingModule,
INotificationModuleService,
IOrderModuleService,
IPaymentModuleService,
IPricingModuleService,
IProductModuleService,
IPromotionModuleService,
IRegionModuleService,
ISalesChannelModuleService,
ITaxModuleService,
IFulfillmentModuleService,
IStockLocationService,
IStoreModuleService,
ITaxModuleService,
IUserModuleService,
IWorkflowEngineService,
IRegionModuleService,
IOrderModuleService,
IApiKeyModuleService,
IStoreModuleService,
ICurrencyModuleService,
IFileModuleService,
INotificationModuleService,
Logger,
ModuleImplementations,
RemoteQueryFunction,
} from "@medusajs/types"
import { ContainerRegistrationKeys, Modules } from "@medusajs/utils"
import { Knex } from "@mikro-orm/knex"
import { AwilixContainer, ResolveOptions } from "awilix"
declare module "@medusajs/types" {
export interface ModuleImplementations {
@@ -63,6 +64,7 @@ declare module "@medusajs/types" {
[Modules.CURRENCY]: ICurrencyModuleService
[Modules.FILE]: IFileModuleService
[Modules.NOTIFICATION]: INotificationModuleService
[Modules.LOCKING]: ILockingModule
}
}
+33 -21
View File
@@ -16,7 +16,7 @@ export const ModulesDefinition: {
label: upperCaseFirst(Modules.EVENT_BUS),
isRequired: true,
isQueryable: false,
dependencies: ["logger"],
dependencies: [ContainerRegistrationKeys.LOGGER],
defaultModuleDeclaration: {
scope: MODULE_SCOPE.INTERNAL,
resources: MODULE_RESOURCE_TYPE.SHARED,
@@ -63,7 +63,7 @@ export const ModulesDefinition: {
label: upperCaseFirst(Modules.PRODUCT),
isRequired: false,
isQueryable: true,
dependencies: [Modules.EVENT_BUS, "logger"],
dependencies: [Modules.EVENT_BUS, ContainerRegistrationKeys.LOGGER],
defaultModuleDeclaration: {
scope: MODULE_SCOPE.INTERNAL,
resources: MODULE_RESOURCE_TYPE.SHARED,
@@ -75,7 +75,7 @@ export const ModulesDefinition: {
label: upperCaseFirst(Modules.PRICING),
isRequired: false,
isQueryable: true,
dependencies: [Modules.EVENT_BUS, "logger"],
dependencies: [Modules.EVENT_BUS, ContainerRegistrationKeys.LOGGER],
defaultModuleDeclaration: {
scope: MODULE_SCOPE.INTERNAL,
resources: MODULE_RESOURCE_TYPE.SHARED,
@@ -87,7 +87,7 @@ export const ModulesDefinition: {
label: upperCaseFirst(Modules.PROMOTION),
isRequired: false,
isQueryable: true,
dependencies: ["logger"],
dependencies: [ContainerRegistrationKeys.LOGGER],
defaultModuleDeclaration: {
scope: MODULE_SCOPE.INTERNAL,
resources: MODULE_RESOURCE_TYPE.SHARED,
@@ -99,7 +99,7 @@ export const ModulesDefinition: {
label: upperCaseFirst(Modules.AUTH),
isRequired: false,
isQueryable: true,
dependencies: ["logger"],
dependencies: [ContainerRegistrationKeys.LOGGER],
defaultModuleDeclaration: {
scope: MODULE_SCOPE.INTERNAL,
resources: MODULE_RESOURCE_TYPE.SHARED,
@@ -111,7 +111,7 @@ export const ModulesDefinition: {
label: upperCaseFirst(Modules.WORKFLOW_ENGINE),
isRequired: false,
isQueryable: true,
dependencies: ["logger"],
dependencies: [ContainerRegistrationKeys.LOGGER],
__passSharedContainer: true,
defaultModuleDeclaration: {
scope: MODULE_SCOPE.INTERNAL,
@@ -124,7 +124,7 @@ export const ModulesDefinition: {
label: upperCaseFirst(Modules.SALES_CHANNEL),
isRequired: false,
isQueryable: true,
dependencies: ["logger"],
dependencies: [ContainerRegistrationKeys.LOGGER],
defaultModuleDeclaration: {
scope: MODULE_SCOPE.INTERNAL,
resources: MODULE_RESOURCE_TYPE.SHARED,
@@ -136,7 +136,7 @@ export const ModulesDefinition: {
label: upperCaseFirst(Modules.FULFILLMENT),
isRequired: false,
isQueryable: true,
dependencies: ["logger", Modules.EVENT_BUS],
dependencies: [ContainerRegistrationKeys.LOGGER, Modules.EVENT_BUS],
defaultModuleDeclaration: {
scope: MODULE_SCOPE.INTERNAL,
resources: MODULE_RESOURCE_TYPE.SHARED,
@@ -148,7 +148,7 @@ export const ModulesDefinition: {
label: upperCaseFirst(Modules.CART),
isRequired: false,
isQueryable: true,
dependencies: ["logger"],
dependencies: [ContainerRegistrationKeys.LOGGER],
defaultModuleDeclaration: {
scope: MODULE_SCOPE.INTERNAL,
resources: MODULE_RESOURCE_TYPE.SHARED,
@@ -160,7 +160,7 @@ export const ModulesDefinition: {
label: upperCaseFirst(Modules.CUSTOMER),
isRequired: false,
isQueryable: true,
dependencies: ["logger"],
dependencies: [ContainerRegistrationKeys.LOGGER],
defaultModuleDeclaration: {
scope: MODULE_SCOPE.INTERNAL,
resources: MODULE_RESOURCE_TYPE.SHARED,
@@ -172,7 +172,7 @@ export const ModulesDefinition: {
label: upperCaseFirst(Modules.PAYMENT),
isRequired: false,
isQueryable: true,
dependencies: ["logger"],
dependencies: [ContainerRegistrationKeys.LOGGER],
defaultModuleDeclaration: {
scope: MODULE_SCOPE.INTERNAL,
resources: MODULE_RESOURCE_TYPE.SHARED,
@@ -184,7 +184,7 @@ export const ModulesDefinition: {
label: upperCaseFirst(Modules.USER),
isRequired: false,
isQueryable: true,
dependencies: [Modules.EVENT_BUS, "logger"],
dependencies: [Modules.EVENT_BUS, ContainerRegistrationKeys.LOGGER],
defaultModuleDeclaration: {
scope: MODULE_SCOPE.INTERNAL,
resources: MODULE_RESOURCE_TYPE.SHARED,
@@ -196,7 +196,7 @@ export const ModulesDefinition: {
label: upperCaseFirst(Modules.REGION),
isRequired: false,
isQueryable: true,
dependencies: ["logger"],
dependencies: [ContainerRegistrationKeys.LOGGER],
defaultModuleDeclaration: {
scope: MODULE_SCOPE.INTERNAL,
resources: MODULE_RESOURCE_TYPE.SHARED,
@@ -208,7 +208,7 @@ export const ModulesDefinition: {
label: upperCaseFirst(Modules.ORDER),
isRequired: false,
isQueryable: true,
dependencies: ["logger", Modules.EVENT_BUS],
dependencies: [ContainerRegistrationKeys.LOGGER, Modules.EVENT_BUS],
defaultModuleDeclaration: {
scope: MODULE_SCOPE.INTERNAL,
resources: MODULE_RESOURCE_TYPE.SHARED,
@@ -220,7 +220,7 @@ export const ModulesDefinition: {
label: upperCaseFirst(Modules.TAX),
isRequired: false,
isQueryable: true,
dependencies: ["logger", Modules.EVENT_BUS],
dependencies: [ContainerRegistrationKeys.LOGGER, Modules.EVENT_BUS],
defaultModuleDeclaration: {
scope: MODULE_SCOPE.INTERNAL,
resources: MODULE_RESOURCE_TYPE.SHARED,
@@ -232,7 +232,7 @@ export const ModulesDefinition: {
label: upperCaseFirst(Modules.API_KEY),
isRequired: false,
isQueryable: true,
dependencies: ["logger"],
dependencies: [ContainerRegistrationKeys.LOGGER],
defaultModuleDeclaration: {
scope: MODULE_SCOPE.INTERNAL,
resources: MODULE_RESOURCE_TYPE.SHARED,
@@ -244,7 +244,7 @@ export const ModulesDefinition: {
label: upperCaseFirst(Modules.STORE),
isRequired: false,
isQueryable: true,
dependencies: ["logger"],
dependencies: [ContainerRegistrationKeys.LOGGER],
defaultModuleDeclaration: {
scope: MODULE_SCOPE.INTERNAL,
resources: MODULE_RESOURCE_TYPE.SHARED,
@@ -256,7 +256,7 @@ export const ModulesDefinition: {
label: upperCaseFirst(Modules.CURRENCY),
isRequired: false,
isQueryable: true,
dependencies: ["logger"],
dependencies: [ContainerRegistrationKeys.LOGGER],
defaultModuleDeclaration: {
scope: MODULE_SCOPE.INTERNAL,
resources: MODULE_RESOURCE_TYPE.SHARED,
@@ -268,7 +268,7 @@ export const ModulesDefinition: {
label: upperCaseFirst(Modules.FILE),
isRequired: false,
isQueryable: true,
dependencies: ["logger"],
dependencies: [ContainerRegistrationKeys.LOGGER],
defaultModuleDeclaration: {
scope: MODULE_SCOPE.INTERNAL,
resources: MODULE_RESOURCE_TYPE.SHARED,
@@ -280,7 +280,7 @@ export const ModulesDefinition: {
label: upperCaseFirst(Modules.NOTIFICATION),
isRequired: false,
isQueryable: true,
dependencies: [Modules.EVENT_BUS, "logger"],
dependencies: [Modules.EVENT_BUS, ContainerRegistrationKeys.LOGGER],
defaultModuleDeclaration: {
scope: MODULE_SCOPE.INTERNAL,
resources: MODULE_RESOURCE_TYPE.SHARED,
@@ -294,7 +294,7 @@ export const ModulesDefinition: {
isQueryable: false,
dependencies: [
Modules.EVENT_BUS,
"logger",
ContainerRegistrationKeys.LOGGER,
ContainerRegistrationKeys.REMOTE_QUERY,
ContainerRegistrationKeys.QUERY,
],
@@ -303,6 +303,18 @@ export const ModulesDefinition: {
resources: MODULE_RESOURCE_TYPE.SHARED,
},
},
[Modules.LOCKING]: {
key: Modules.LOCKING,
defaultPackage: false,
label: upperCaseFirst(Modules.LOCKING),
isRequired: false,
isQueryable: false,
dependencies: [ContainerRegistrationKeys.LOGGER],
defaultModuleDeclaration: {
scope: MODULE_SCOPE.INTERNAL,
resources: MODULE_RESOURCE_TYPE.SHARED,
},
},
}
export const MODULE_DEFINITIONS: ModuleDefinition[] =
+2 -2
View File
@@ -84,7 +84,7 @@ export async function loadModules(args: {
sharedResourcesConfig,
migrationOnly = false,
loaderOnly = false,
workerMode = "server" as ModuleBootstrapOptions["workerMode"],
workerMode = "shared" as ModuleBootstrapOptions["workerMode"],
} = args
const allModules = {} as any
@@ -307,7 +307,7 @@ async function MedusaApp_({
injectedDependencies = {},
migrationOnly = false,
loaderOnly = false,
workerMode = "server",
workerMode = "shared",
}: MedusaAppOptions & {
migrationOnly?: boolean
} = {}): Promise<MedusaAppOutput> {
+1
View File
@@ -20,6 +20,7 @@ export * from "./index-data"
export * from "./inventory"
export * from "./joiner"
export * from "./link-modules"
export * from "./locking"
export * from "./logger"
export * from "./modules-sdk"
export * from "./notification"
+69
View File
@@ -0,0 +1,69 @@
import { Context } from "../shared-context"
export interface ILockingProvider {
execute<T>(
keys: string | string[],
job: () => Promise<T>,
args?: {
timeout?: number
},
sharedContext?: Context
): Promise<T>
acquire(
keys: string | string[],
args?: {
ownerId?: string | null
expire?: number
},
sharedContext?: Context
): Promise<void>
release(
keys: string | string[],
args?: {
ownerId?: string | null
},
sharedContext?: Context
): Promise<boolean>
releaseAll(
args?: {
ownerId?: string | null
},
sharedContext?: Context
): Promise<void>
}
export interface ILockingModule {
execute<T>(
keys: string | string[],
job: () => Promise<T>,
args?: {
timeout?: number
provider?: string
},
sharedContext?: Context
): Promise<T>
acquire(
keys: string | string[],
args?: {
ownerId?: string | null
expire?: number
provider?: string
},
sharedContext?: Context
): Promise<void>
release(
keys: string | string[],
args?: {
ownerId?: string | null
provider?: string
},
sharedContext?: Context
): Promise<boolean>
releaseAll(
args?: {
ownerId?: string | null
provider?: string
},
sharedContext?: Context
): Promise<void>
}
@@ -8,4 +8,5 @@ export type ModuleProvider = {
resolve: string | ModuleProviderExports
id: string
options?: Record<string, unknown>
is_default?: boolean
}
@@ -24,6 +24,7 @@ export const Modules = {
FILE: "file",
NOTIFICATION: "notification",
INDEX: "index",
LOCKING: "locking",
} as const
export const MODULE_PACKAGE_NAMES = {
@@ -52,6 +53,7 @@ export const MODULE_PACKAGE_NAMES = {
[Modules.FILE]: "@medusajs/medusa/file",
[Modules.NOTIFICATION]: "@medusajs/medusa/notification",
[Modules.INDEX]: "@medusajs/medusa/index-module",
[Modules.LOCKING]: "@medusajs/medusa/locking",
}
export const REVERSED_MODULE_PACKAGE_NAMES = Object.entries(
@@ -9,7 +9,7 @@ import {
PerformedActions,
UpsertWithReplaceConfig,
} from "@medusajs/types"
import type { EntitySchema, EntityClass } from "@mikro-orm/core"
import type { EntityClass, EntitySchema } from "@mikro-orm/core"
import {
doNotForceTransaction,
isDefined,