@unchainedshop/core-orders 4.8.20 → 4.8.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,10 @@
1
+ import { mongodb } from '@unchainedshop/mongodb';
2
+ export interface OrderLock {
3
+ key: string;
4
+ uniqueValue: string;
5
+ expireAt: Date;
6
+ }
7
+ export declare const OrderLocksCollection: (db: mongodb.Db) => Promise<mongodb.Collection<OrderLock>>;
8
+ export declare const acquireLock: (OrderLocks: mongodb.Collection<OrderLock>, key: string, ttl: number) => Promise<{
9
+ release: () => Promise<void>;
10
+ }>;
@@ -0,0 +1,40 @@
1
+ import { mongodb, buildDbIndexes } from '@unchainedshop/mongodb';
2
+ import { setTimeout as sleep } from 'node:timers/promises';
3
+ const DUPLICATE_KEY = 11000;
4
+ const LOCK_RETRIES = 10;
5
+ const LOCK_RETRY_DELAY_MS = 200;
6
+ export const OrderLocksCollection = async (db) => {
7
+ const OrderLocks = db.collection('locco-locks');
8
+ const success = await buildDbIndexes(OrderLocks, [
9
+ { index: { key: 1 }, options: { unique: true } },
10
+ { index: { expireAt: 1 }, options: { expireAfterSeconds: 0 } },
11
+ ], { rebuild: false });
12
+ if (!success) {
13
+ throw new Error('Could not ensure the unique index backing order locks, refusing to start');
14
+ }
15
+ return OrderLocks;
16
+ };
17
+ export const acquireLock = async (OrderLocks, key, ttl) => {
18
+ const uniqueValue = crypto.randomUUID();
19
+ for (let attempt = 0; attempt < LOCK_RETRIES; attempt += 1) {
20
+ try {
21
+ await OrderLocks.updateOne({ key, expireAt: { $lt: new Date() } }, { $set: { key, uniqueValue, expireAt: new Date(Date.now() + ttl) } }, { upsert: true });
22
+ return {
23
+ release: async () => {
24
+ try {
25
+ await OrderLocks.deleteOne({ key, uniqueValue, expireAt: { $gt: new Date() } });
26
+ }
27
+ catch {
28
+ }
29
+ },
30
+ };
31
+ }
32
+ catch (error) {
33
+ if (error?.code !== DUPLICATE_KEY)
34
+ throw error;
35
+ if (attempt < LOCK_RETRIES - 1)
36
+ await sleep(LOCK_RETRY_DELAY_MS);
37
+ }
38
+ }
39
+ throw new Error(`Could not acquire lock ${key}`);
40
+ };
@@ -115,7 +115,9 @@ export declare const configureOrdersModule: ({ db, migrationRepository, options:
115
115
  status: OrderStatus | null;
116
116
  info?: string;
117
117
  }) => Promise<mongodb.WithId<Order> | null>;
118
- acquireLock: (orderId: string, identifier: string, timeout?: number) => Promise<import("@kontsedal/locco").Lock>;
118
+ acquireLock: (orderId: string, identifier: string, timeout?: number) => Promise<{
119
+ release: () => Promise<void>;
120
+ }>;
119
121
  setDeliveryProvider: (orderId: string, deliveryProviderId: string) => Promise<mongodb.WithId<Order> | null>;
120
122
  setPaymentProvider: (orderId: string, paymentProviderId: string) => Promise<mongodb.WithId<Order> | null>;
121
123
  create: ({ userId, orderNumber, currencyCode, countryCode, billingAddress, contact, context, }: {
@@ -1,6 +1,6 @@
1
- import { Locker, MongoAdapter } from '@kontsedal/locco';
2
1
  import { generateDbFilterById, mongodb } from '@unchainedshop/mongodb';
3
2
  import { OrderDeliveriesCollection } from "../db/OrderDeliveriesCollection.js";
3
+ import { OrderLocksCollection, acquireLock } from "../db/OrderLocksCollection.js";
4
4
  import { OrderDiscountsCollection } from "../db/OrderDiscountsCollection.js";
5
5
  import { OrderPaymentsCollection } from "../db/OrderPaymentsCollection.js";
6
6
  import { OrderPositionsCollection } from "../db/OrderPositionsCollection.js";
@@ -31,15 +31,7 @@ export const configureOrdersModule = async ({ db, migrationRepository, options:
31
31
  const OrderDiscounts = await OrderDiscountsCollection(db);
32
32
  const OrderPayments = await OrderPaymentsCollection(db);
33
33
  const OrderPositions = await OrderPositionsCollection(db);
34
- const mongoAdapter = new MongoAdapter({
35
- client: {
36
- db: () => db,
37
- },
38
- });
39
- const locker = new Locker({
40
- adapter: mongoAdapter,
41
- retrySettings: { retryDelay: 200, retryTimes: 10 },
42
- });
34
+ const OrderLocks = await OrderLocksCollection(db);
43
35
  const orderQueries = configureOrdersModuleQueries({ Orders });
44
36
  const orderMutations = configureOrderModuleMutations({
45
37
  Orders,
@@ -139,7 +131,7 @@ export const configureOrdersModule = async ({ db, migrationRepository, options:
139
131
  return modificationResult.value || Orders.findOne(selector, {});
140
132
  },
141
133
  acquireLock: async (orderId, identifier, timeout = 5000) => {
142
- return await locker.lock(`order:${identifier}:${orderId}`, timeout).acquire();
134
+ return acquireLock(OrderLocks, `order:${identifier}:${orderId}`, timeout);
143
135
  },
144
136
  setDeliveryProvider: async (orderId, deliveryProviderId) => {
145
137
  const delivery = await OrderDeliveries.findOne({
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@unchainedshop/core-orders",
3
3
  "description": "Order management module for the Unchained Engine",
4
- "version": "4.8.20",
4
+ "version": "4.8.22",
5
5
  "main": "lib/orders-index.js",
6
6
  "types": "lib/orders-index.d.ts",
7
7
  "type": "module",
@@ -35,9 +35,8 @@
35
35
  },
36
36
  "homepage": "https://github.com/unchainedshop/unchained#readme",
37
37
  "dependencies": {
38
- "@kontsedal/locco": "^1.1.0",
39
38
  "@unchainedshop/events": "^4.8.12",
40
- "@unchainedshop/logger": "^4.8.12",
39
+ "@unchainedshop/mongodb": "^4.8.12",
41
40
  "@unchainedshop/utils": "^4.8.12"
42
41
  },
43
42
  "devDependencies": {