Skip to content

Commit d03b289

Browse files
Handle concurrent order taking: User PerOrderIdMutex in takeBuy and takeSell [2/2] (#824)
* Move PerOrderIdMutex to util * Code formatting * Improve concurrency handling for order taking * Remove debug messages
1 parent 6978372 commit d03b289

1 file changed

Lines changed: 72 additions & 63 deletions

File tree

bot/modules/orders/takeOrder.ts

Lines changed: 72 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import { logger } from '../../../logger';
22
import { Block, Order, User } from '../../../models';
33
import { UserDocument } from '../../../models/user';
4-
import { deleteOrderFromChannel, generateRandomImage } from '../../../util';
4+
import {
5+
deleteOrderFromChannel,
6+
generateRandomImage,
7+
PerOrderIdMutex,
8+
} from '../../../util';
59
import * as messages from '../../messages';
610
import { HasTelegram, MainContext } from '../../start';
711
import {
@@ -55,41 +59,43 @@ export const takebuy = async (
5559
orderId: string,
5660
) => {
5761
try {
58-
if (!orderId) return;
59-
const { user } = ctx;
60-
if (!(await validateObjectId(ctx, orderId))) return;
61-
const order = await Order.findOne({ _id: orderId });
62-
if (!order) return;
62+
await PerOrderIdMutex.instance.runExclusive(orderId, async () => {
63+
if (!orderId) return;
64+
const { user } = ctx;
65+
if (!(await validateObjectId(ctx, orderId))) return;
66+
const order = await Order.findOne({ _id: orderId });
67+
if (!order) return;
6368

64-
const userOffer = await User.findOne({ _id: order.buyer_id });
69+
const userOffer = await User.findOne({ _id: order.buyer_id });
6570

66-
if (!userOffer) {
67-
return await messages.notFoundUserMessage(ctx);
68-
} else if (await checkBlockingStatus(ctx, user, userOffer)) {
69-
return;
70-
}
71+
if (!userOffer) {
72+
return await messages.notFoundUserMessage(ctx);
73+
} else if (await checkBlockingStatus(ctx, user, userOffer)) {
74+
return;
75+
}
7176

72-
// We verify if the user is not banned on this community
73-
if (await isBannedFromCommunity(user, order.community_id))
74-
return await messages.bannedUserErrorMessage(ctx, user);
77+
// We verify if the user is not banned on this community
78+
if (await isBannedFromCommunity(user, order.community_id))
79+
return await messages.bannedUserErrorMessage(ctx, user);
7580

76-
if (!(await validateTakeBuyOrder(ctx, bot, user, order))) return;
81+
if (!(await validateTakeBuyOrder(ctx, bot, user, order))) return;
7782

78-
const { randomImage } = generateRandomImage(user._id.toString());
83+
const { randomImage } = generateRandomImage(user._id.toString());
7984

80-
order.status = 'WAITING_PAYMENT';
81-
order.seller_id = user._id;
82-
order.taken_at = new Date(Date.now());
85+
order.status = 'WAITING_PAYMENT';
86+
order.seller_id = user._id;
87+
order.taken_at = new Date(Date.now());
8388

84-
order.random_image = randomImage;
89+
order.random_image = randomImage;
8590

86-
await order.save();
87-
order.status = 'in-progress';
88-
OrderEvents.orderUpdated(order);
91+
await order.save();
92+
order.status = 'in-progress';
93+
OrderEvents.orderUpdated(order);
8994

90-
await deleteOrderFromChannel(order, bot.telegram);
95+
await deleteOrderFromChannel(order, bot.telegram);
9196

92-
await messages.beginTakeBuyMessage(ctx, bot, user, order);
97+
await messages.beginTakeBuyMessage(ctx, bot, user, order);
98+
});
9399
} catch (error) {
94100
logger.error(error);
95101
}
@@ -100,44 +106,47 @@ export const takesell = async (
100106
orderId: string,
101107
) => {
102108
try {
103-
const { user } = ctx;
104-
if (!orderId) return;
105-
const order = await Order.findOne({ _id: orderId });
106-
if (!order) return;
107-
const seller = await User.findOne({ _id: order.seller_id });
108-
if (seller === null) {
109-
throw new Error('seller is null');
110-
}
111-
112-
const sellerIsBlocked = await Block.exists({
113-
blocker_tg_id: user.tg_id,
114-
blocked_tg_id: seller.tg_id,
115-
});
116-
const buyerIsBlocked = await Block.exists({
117-
blocker_tg_id: seller.tg_id,
118-
blocked_tg_id: user.tg_id,
109+
await PerOrderIdMutex.instance.runExclusive(orderId, async () => {
110+
const { user } = ctx;
111+
if (!orderId) return;
112+
const order = await Order.findOne({ _id: orderId });
113+
if (!order) return;
114+
const seller = await User.findOne({ _id: order.seller_id });
115+
if (seller === null) {
116+
throw new Error('seller is null');
117+
}
118+
119+
const sellerIsBlocked = await Block.exists({
120+
blocker_tg_id: user.tg_id,
121+
blocked_tg_id: seller.tg_id,
122+
});
123+
const buyerIsBlocked = await Block.exists({
124+
blocker_tg_id: seller.tg_id,
125+
blocked_tg_id: user.tg_id,
126+
});
127+
128+
if (sellerIsBlocked)
129+
return await messages.userOrderIsBlockedByUserTaker(ctx, user);
130+
131+
if (buyerIsBlocked)
132+
return await messages.userTakerIsBlockedByUserOrder(ctx, user);
133+
134+
// We verify if the user is not banned on this community
135+
if (await isBannedFromCommunity(user, order.community_id))
136+
return await messages.bannedUserErrorMessage(ctx, user);
137+
if (!(await validateTakeSellOrder(ctx, bot, user, order))) return;
138+
order.status = 'WAITING_BUYER_INVOICE';
139+
order.buyer_id = user._id;
140+
order.taken_at = new Date(Date.now());
141+
142+
await order.save();
143+
144+
order.status = 'in-progress';
145+
OrderEvents.orderUpdated(order);
146+
// We delete the messages related to that order from the channel
147+
await deleteOrderFromChannel(order, bot.telegram);
148+
await messages.beginTakeSellMessage(ctx, bot, user, order);
119149
});
120-
121-
if (sellerIsBlocked)
122-
return await messages.userOrderIsBlockedByUserTaker(ctx, user);
123-
124-
if (buyerIsBlocked)
125-
return await messages.userTakerIsBlockedByUserOrder(ctx, user);
126-
127-
// We verify if the user is not banned on this community
128-
if (await isBannedFromCommunity(user, order.community_id))
129-
return await messages.bannedUserErrorMessage(ctx, user);
130-
if (!(await validateTakeSellOrder(ctx, bot, user, order))) return;
131-
order.status = 'WAITING_BUYER_INVOICE';
132-
order.buyer_id = user._id;
133-
order.taken_at = new Date(Date.now());
134-
135-
await order.save();
136-
order.status = 'in-progress';
137-
OrderEvents.orderUpdated(order);
138-
// We delete the messages related to that order from the channel
139-
await deleteOrderFromChannel(order, bot.telegram);
140-
await messages.beginTakeSellMessage(ctx, bot, user, order);
141150
} catch (error) {
142151
logger.error(error);
143152
}

0 commit comments

Comments
 (0)