@chevre/domain 22.11.0-alpha.31 → 22.11.0-alpha.33
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.
- package/example/src/chevre/checkCustomerAttributesLength.ts +109 -0
- package/example/src/chevre/searchEventSeats.ts +1 -1
- package/example/src/chevre/stockHolder/checkRedisKeyCount.ts +4 -4
- package/example/src/chevre/{deleteRunsAtPassedCertainPeriod.ts → task/deleteRunsAtPassedCertainPeriod.ts} +4 -3
- package/example/src/chevre/task/deleteUnexpectedTasks.ts +23 -0
- package/lib/chevre/repo/pendingReservation.js +1 -0
- package/lib/chevre/repo/stockHolder.d.ts +4 -5
- package/lib/chevre/repo/stockHolder.js +52 -36
- package/lib/chevre/repo/task.d.ts +13 -6
- package/lib/chevre/repo/task.js +15 -7
- package/lib/chevre/service/task/aggregateOffers.js +1 -1
- package/lib/chevre/service/task/aggregateScreeningEvent.js +1 -1
- package/lib/chevre/service/task/cancelPendingReservation.js +1 -1
- package/lib/chevre/service/task/cancelReservation.js +1 -1
- package/lib/chevre/service/task/checkResource.js +1 -1
- package/lib/chevre/service/task/voidReserveTransaction.js +1 -1
- package/lib/chevre/service/validation/validateEvent.d.ts +2 -2
- package/lib/chevre/service/validation/validateEvent.js +16 -10
- package/package.json +1 -1
- package/example/src/chevre/stockHolder/checkIfConflicted.ts +0 -76
- package/example/src/chevre/stockHolder/migratePendingReservations.ts +0 -96
- package/example/src/chevre/stockHolder/playAroundStockHolder.ts +0 -256
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
// tslint:disable:no-console
|
|
2
|
+
import * as moment from 'moment';
|
|
3
|
+
import * as mongoose from 'mongoose';
|
|
4
|
+
|
|
5
|
+
import { chevre } from '../../../lib/index';
|
|
6
|
+
|
|
7
|
+
// const project = { id: String(process.env.PROJECT_ID) };
|
|
8
|
+
const MAX_LENGTH = 50;
|
|
9
|
+
const CHECK_DAYS = 60;
|
|
10
|
+
|
|
11
|
+
async function main() {
|
|
12
|
+
await mongoose.connect(<string>process.env.MONGOLAB_URI, { autoIndex: false });
|
|
13
|
+
|
|
14
|
+
const orderRepo = await chevre.repository.Order.createInstance(mongoose.connection);
|
|
15
|
+
|
|
16
|
+
const cursor = orderRepo.getCursor(
|
|
17
|
+
{
|
|
18
|
+
typeOf: { $eq: chevre.factory.order.OrderType.Order },
|
|
19
|
+
orderDate: {
|
|
20
|
+
$gte: moment()
|
|
21
|
+
.add(-CHECK_DAYS, 'days')
|
|
22
|
+
.toDate()
|
|
23
|
+
}
|
|
24
|
+
// _id: { $eq: '67de46777ec0510590b68922' }
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
customer: 1,
|
|
28
|
+
project: 1,
|
|
29
|
+
orderDate: 1
|
|
30
|
+
}
|
|
31
|
+
);
|
|
32
|
+
console.log('docs found');
|
|
33
|
+
|
|
34
|
+
let i = 0;
|
|
35
|
+
let exceededCount = 0;
|
|
36
|
+
await cursor.eachAsync(async (doc) => {
|
|
37
|
+
i += 1;
|
|
38
|
+
const order: Pick<
|
|
39
|
+
chevre.factory.order.IOrder,
|
|
40
|
+
'customer' | 'project' | 'orderDate'
|
|
41
|
+
> = doc.toObject();
|
|
42
|
+
|
|
43
|
+
const attributesNames: (keyof chevre.factory.order.ICustomer)[] = [
|
|
44
|
+
'address',
|
|
45
|
+
'age',
|
|
46
|
+
'email',
|
|
47
|
+
'givenName',
|
|
48
|
+
'familyName',
|
|
49
|
+
'gender',
|
|
50
|
+
'name',
|
|
51
|
+
'url',
|
|
52
|
+
'telephone'
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
const maxLengthNotExceeded = attributesNames.every((attributesName) => {
|
|
56
|
+
const attributesValue = order.customer[attributesName];
|
|
57
|
+
if (attributesValue === undefined) {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
if (typeof attributesValue !== 'string') {
|
|
61
|
+
throw new Error(`${attributesName}: ${attributesValue} must be string. ${order.project.id}`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return attributesValue.length <= MAX_LENGTH;
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
if (maxLengthNotExceeded) {
|
|
68
|
+
// no op
|
|
69
|
+
process.stdout.write('-');
|
|
70
|
+
} else {
|
|
71
|
+
exceededCount += 1;
|
|
72
|
+
console.log('\n');
|
|
73
|
+
console.log('maxLengthExceeded.', order.project.id, order.customer, order.orderDate, i);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
console.log('\n');
|
|
78
|
+
console.log(i, 'docs checked');
|
|
79
|
+
console.log(exceededCount, 'docs exceeded');
|
|
80
|
+
|
|
81
|
+
// let result: any;
|
|
82
|
+
// const attributesNames = [
|
|
83
|
+
// // 'customer.address',
|
|
84
|
+
// // 'customer.age',
|
|
85
|
+
// 'customer.email',
|
|
86
|
+
// 'customer.givenName',
|
|
87
|
+
// 'customer.familyName'
|
|
88
|
+
// // 'customer.gender',
|
|
89
|
+
// // 'customer.name',
|
|
90
|
+
// // 'customer.url',
|
|
91
|
+
// ];
|
|
92
|
+
// for (const attributesName of attributesNames) {
|
|
93
|
+
// console.log('how is', attributesName, '?');
|
|
94
|
+
// result = await orderRepo.checkCustomerAttributesLength({
|
|
95
|
+
// attributesName,
|
|
96
|
+
// length: MAX_LENGTH
|
|
97
|
+
// });
|
|
98
|
+
// // tslint:disable-next-line:no-null-keyword
|
|
99
|
+
// console.dir(result, { depth: null });
|
|
100
|
+
// console.log('how is', attributesName, '?', result.length, 'results found');
|
|
101
|
+
// }
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
main()
|
|
105
|
+
.then(() => {
|
|
106
|
+
console.log('\n');
|
|
107
|
+
console.log('success!');
|
|
108
|
+
})
|
|
109
|
+
.catch(console.error);
|
|
@@ -17,7 +17,7 @@ async function main() {
|
|
|
17
17
|
});
|
|
18
18
|
await client.connect();
|
|
19
19
|
|
|
20
|
-
const itemAvailabilityRepo = await chevre.repository.StockHolder.createInstance(
|
|
20
|
+
const itemAvailabilityRepo = await chevre.repository.StockHolder.createInstance({ connection: mongoose.connection });
|
|
21
21
|
|
|
22
22
|
const result = await itemAvailabilityRepo.searchHolders({
|
|
23
23
|
project,
|
|
@@ -93,10 +93,10 @@ async function main() {
|
|
|
93
93
|
const eventRepo = await chevre.repository.Event.createInstance(mongoose.connection);
|
|
94
94
|
const projectRepo = await chevre.repository.Project.createInstance(mongoose.connection);
|
|
95
95
|
// const settingRepo = await chevre.repository.Setting.createInstance(mongoose.connection);
|
|
96
|
-
const stockHolderRepo = await chevre.repository.StockHolder.createInstance(
|
|
97
|
-
client,
|
|
98
|
-
mongoose.connection
|
|
99
|
-
);
|
|
96
|
+
const stockHolderRepo = await chevre.repository.StockHolder.createInstance({
|
|
97
|
+
redisClient: client,
|
|
98
|
+
connection: mongoose.connection
|
|
99
|
+
});
|
|
100
100
|
|
|
101
101
|
let checkingProjects: string[] = [];
|
|
102
102
|
// 全プロジェクト
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
import * as moment from 'moment';
|
|
3
3
|
import * as mongoose from 'mongoose';
|
|
4
4
|
|
|
5
|
-
import { chevre } from '
|
|
5
|
+
import { chevre } from '../../../../lib/index';
|
|
6
6
|
|
|
7
|
-
const TASK_STORAGE_PERIOD_IN_MINUTES = 43200; // 30*24*60
|
|
7
|
+
// const TASK_STORAGE_PERIOD_IN_MINUTES = 43200; // 30*24*60
|
|
8
|
+
const TASK_STORAGE_PERIOD_IN_MINUTES = 28800; // 20*24*60
|
|
8
9
|
|
|
9
10
|
async function main() {
|
|
10
11
|
const now = new Date();
|
|
@@ -12,7 +13,7 @@ async function main() {
|
|
|
12
13
|
|
|
13
14
|
const taskRepo = await chevre.repository.Task.createInstance(mongoose.connection);
|
|
14
15
|
|
|
15
|
-
let taskInMinutes =
|
|
16
|
+
let taskInMinutes = 44640; // 31*24*60
|
|
16
17
|
// let taskInMinutes = 172800; // 120*24*60
|
|
17
18
|
// tslint:disable-next-line:no-magic-numbers
|
|
18
19
|
while (taskInMinutes > TASK_STORAGE_PERIOD_IN_MINUTES) {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// tslint:disable:no-console
|
|
2
|
+
import * as mongoose from 'mongoose';
|
|
3
|
+
|
|
4
|
+
import { chevre } from '../../../../lib/index';
|
|
5
|
+
|
|
6
|
+
async function main() {
|
|
7
|
+
await mongoose.connect(<string>process.env.MONGOLAB_URI, { autoIndex: false });
|
|
8
|
+
|
|
9
|
+
const taskRepo = await chevre.repository.Task.createInstance(mongoose.connection);
|
|
10
|
+
const result = await taskRepo.taskModel.deleteMany({
|
|
11
|
+
$or: [
|
|
12
|
+
{ name: { $exists: false } },
|
|
13
|
+
{ status: { $exists: false } }
|
|
14
|
+
]
|
|
15
|
+
})
|
|
16
|
+
.exec();
|
|
17
|
+
|
|
18
|
+
console.log('success!', result);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
main()
|
|
22
|
+
.then()
|
|
23
|
+
.catch(console.error);
|
|
@@ -9,7 +9,10 @@ export declare class StockHolderRepo implements AbstractStockHolderRepo {
|
|
|
9
9
|
static KEY_PREFIX_NEW: string;
|
|
10
10
|
private readonly redisClient;
|
|
11
11
|
private readonly pendingReservationRepo;
|
|
12
|
-
constructor(
|
|
12
|
+
constructor(params: {
|
|
13
|
+
redisClient?: RedisClientType;
|
|
14
|
+
connection: Connection;
|
|
15
|
+
});
|
|
13
16
|
private static offer2field;
|
|
14
17
|
private static createKey;
|
|
15
18
|
/**
|
|
@@ -54,10 +57,6 @@ export declare class StockHolderRepo implements AbstractStockHolderRepo {
|
|
|
54
57
|
eventId: string;
|
|
55
58
|
startDate: Date;
|
|
56
59
|
}): Promise<boolean>;
|
|
57
|
-
checkIfConflicted(params: {
|
|
58
|
-
eventId: string;
|
|
59
|
-
startDate: Date;
|
|
60
|
-
}): Promise<void>;
|
|
61
60
|
/**
|
|
62
61
|
* 万が一に備えて、保留予約をredis->mongo移行
|
|
63
62
|
*/
|
|
@@ -13,18 +13,16 @@ exports.StockHolderRepo = void 0;
|
|
|
13
13
|
const createDebug = require("debug");
|
|
14
14
|
const moment = require("moment");
|
|
15
15
|
const factory = require("../factory");
|
|
16
|
-
// import { createSchema, IModel, ISetting, modelName } from './mongoose/schemas/setting';
|
|
17
16
|
const pendingReservation_1 = require("./pendingReservation");
|
|
18
17
|
const debug = createDebug('chevre-domain:repo:stockHolder');
|
|
19
18
|
const SEARCH_OFFERS_MAX_LENGTH = 100;
|
|
20
|
-
const USE_STOCK_HOLDER_CHECK_CONFLICT = process.env.USE_STOCK_HOLDER_CHECK_CONFLICT === '1';
|
|
21
19
|
/**
|
|
22
20
|
* イベントストックホルダーリポジトリ
|
|
23
21
|
*/
|
|
24
22
|
class StockHolderRepo {
|
|
25
|
-
constructor(
|
|
23
|
+
constructor(params) {
|
|
24
|
+
const { redisClient, connection } = params;
|
|
26
25
|
this.redisClient = redisClient;
|
|
27
|
-
// this.settingModel = connection.model(modelName, createSchema());
|
|
28
26
|
this.pendingReservationRepo = new pendingReservation_1.PendingReservationRepo(connection);
|
|
29
27
|
}
|
|
30
28
|
static offer2field(params, hasTicketedSeat) {
|
|
@@ -61,15 +59,15 @@ class StockHolderRepo {
|
|
|
61
59
|
hasTicketedSeat: lockKey.hasTicketedSeat
|
|
62
60
|
});
|
|
63
61
|
if (useMongoose) {
|
|
64
|
-
// throw new factory.errors.NotImplemented('new stock holder repository not implemented');
|
|
65
62
|
return this.pendingReservationRepo.lockIfNotLimitExceeded(lockKey, maximum);
|
|
66
63
|
}
|
|
67
64
|
else {
|
|
65
|
+
if (this.redisClient === undefined) {
|
|
66
|
+
throw new factory.errors.Internal('redisClient required');
|
|
67
|
+
}
|
|
68
68
|
const key = StockHolderRepo.createKey({ eventId: lockKey.eventId, startDate: lockKey.startDate });
|
|
69
69
|
yield this.redisClient.watch(key);
|
|
70
70
|
const hashCount = yield this.redisClient.hLen(key);
|
|
71
|
-
// Process result
|
|
72
|
-
// Heavy and time consuming operation here
|
|
73
71
|
debug('checking hash count...hashCount:', hashCount);
|
|
74
72
|
if (hashCount + lockKey.offers.length > maximum) {
|
|
75
73
|
throw new factory.errors.Argument('Event', 'maximumAttendeeCapacity exceeded');
|
|
@@ -96,10 +94,12 @@ class StockHolderRepo {
|
|
|
96
94
|
const key = StockHolderRepo.createKey({ eventId: lockKey.eventId, startDate: lockKey.startDate });
|
|
97
95
|
// await this.checkIfConflicted({ key, eventId: lockKey.eventId, useMongoose });
|
|
98
96
|
if (useMongoose) {
|
|
99
|
-
// throw new factory.errors.NotImplemented('new stock holder repository not implemented');
|
|
100
97
|
return this.pendingReservationRepo.lock(lockKey);
|
|
101
98
|
}
|
|
102
99
|
else {
|
|
100
|
+
if (this.redisClient === undefined) {
|
|
101
|
+
throw new factory.errors.Internal('redisClient required');
|
|
102
|
+
}
|
|
103
103
|
const value = lockKey.holder;
|
|
104
104
|
const multi = this.redisClient.multi();
|
|
105
105
|
const fields = lockKey.offers.map((offer) => StockHolderRepo.offer2field(offer, lockKey.hasTicketedSeat));
|
|
@@ -160,10 +160,12 @@ class StockHolderRepo {
|
|
|
160
160
|
const key = StockHolderRepo.createKey({ eventId: params.eventId, startDate: params.startDate });
|
|
161
161
|
// await this.checkIfConflicted({ key, eventId: params.eventId, useMongoose });
|
|
162
162
|
if (useMongoose) {
|
|
163
|
-
// throw new factory.errors.NotImplemented('new stock holder repository not implemented');
|
|
164
163
|
return this.pendingReservationRepo.unlock(params);
|
|
165
164
|
}
|
|
166
165
|
else {
|
|
166
|
+
if (this.redisClient === undefined) {
|
|
167
|
+
throw new factory.errors.Internal('redisClient required');
|
|
168
|
+
}
|
|
167
169
|
const field = StockHolderRepo.offer2field(params.offer, params.hasTicketedSeat);
|
|
168
170
|
yield this.redisClient.multi()
|
|
169
171
|
.hDel(key, field)
|
|
@@ -182,10 +184,12 @@ class StockHolderRepo {
|
|
|
182
184
|
startDate: params.event.startDate,
|
|
183
185
|
hasTicketedSeat: params.event.hasTicketedSeat
|
|
184
186
|
})) {
|
|
185
|
-
// throw new factory.errors.NotImplemented('new stock holder repository not implemented');
|
|
186
187
|
return this.pendingReservationRepo.countUnavailableOffers(params);
|
|
187
188
|
}
|
|
188
189
|
else {
|
|
190
|
+
if (this.redisClient === undefined) {
|
|
191
|
+
throw new factory.errors.Internal('redisClient required');
|
|
192
|
+
}
|
|
189
193
|
const key = StockHolderRepo.createKey({ eventId: params.event.id, startDate: params.event.startDate });
|
|
190
194
|
const reply = yield this.redisClient.hLen(key);
|
|
191
195
|
let fieldCount = 0;
|
|
@@ -207,10 +211,12 @@ class StockHolderRepo {
|
|
|
207
211
|
startDate: params.startDate,
|
|
208
212
|
hasTicketedSeat: params.hasTicketedSeat
|
|
209
213
|
})) {
|
|
210
|
-
// throw new factory.errors.NotImplemented('new stock holder repository not implemented');
|
|
211
214
|
return this.pendingReservationRepo.getHolder(params);
|
|
212
215
|
}
|
|
213
216
|
else {
|
|
217
|
+
if (this.redisClient === undefined) {
|
|
218
|
+
throw new factory.errors.Internal('redisClient required');
|
|
219
|
+
}
|
|
214
220
|
const key = StockHolderRepo.createKey({ eventId: params.eventId, startDate: params.startDate });
|
|
215
221
|
const field = StockHolderRepo.offer2field(params.offer, params.hasTicketedSeat);
|
|
216
222
|
return this.redisClient.hGet(key, field);
|
|
@@ -229,10 +235,12 @@ class StockHolderRepo {
|
|
|
229
235
|
startDate: params.startDate,
|
|
230
236
|
hasTicketedSeat: params.hasTicketedSeat
|
|
231
237
|
})) {
|
|
232
|
-
// throw new factory.errors.NotImplemented('new stock holder repository not implemented');
|
|
233
238
|
return this.pendingReservationRepo.searchHolders(params);
|
|
234
239
|
}
|
|
235
240
|
else {
|
|
241
|
+
if (this.redisClient === undefined) {
|
|
242
|
+
throw new factory.errors.Internal('redisClient required');
|
|
243
|
+
}
|
|
236
244
|
const key = StockHolderRepo.createKey({ eventId: params.eventId, startDate: params.startDate });
|
|
237
245
|
const fields = params.offers.map((o) => {
|
|
238
246
|
return StockHolderRepo.offer2field(o, params.hasTicketedSeat);
|
|
@@ -249,6 +257,9 @@ class StockHolderRepo {
|
|
|
249
257
|
}
|
|
250
258
|
redisKeyExists(params) {
|
|
251
259
|
return __awaiter(this, void 0, void 0, function* () {
|
|
260
|
+
if (this.redisClient === undefined) {
|
|
261
|
+
throw new factory.errors.Internal('redisClient required');
|
|
262
|
+
}
|
|
252
263
|
const key = StockHolderRepo.createKey(params);
|
|
253
264
|
const existingRedisKeyCount = yield this.redisClient.exists(key);
|
|
254
265
|
if (typeof existingRedisKeyCount !== 'number') {
|
|
@@ -257,20 +268,24 @@ class StockHolderRepo {
|
|
|
257
268
|
return existingRedisKeyCount > 0;
|
|
258
269
|
});
|
|
259
270
|
}
|
|
260
|
-
checkIfConflicted(params
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
}
|
|
271
|
+
// public async checkIfConflicted(params: {
|
|
272
|
+
// eventId: string;
|
|
273
|
+
// startDate: Date;
|
|
274
|
+
// }): Promise<void> {
|
|
275
|
+
// const redisKeyExists = await this.redisKeyExists(params);
|
|
276
|
+
// const mongoDocExists = await this.pendingReservationRepo.docExists(params);
|
|
277
|
+
// if (redisKeyExists && mongoDocExists) {
|
|
278
|
+
// throw new factory.errors.Internal(`repository conflicted. eventId:${params.eventId}`);
|
|
279
|
+
// }
|
|
280
|
+
// }
|
|
269
281
|
/**
|
|
270
282
|
* 万が一に備えて、保留予約をredis->mongo移行
|
|
271
283
|
*/
|
|
272
284
|
migrate2mongoJustInCase(params) {
|
|
273
285
|
return __awaiter(this, void 0, void 0, function* () {
|
|
286
|
+
if (this.redisClient === undefined) {
|
|
287
|
+
throw new factory.errors.Internal('redisClient required');
|
|
288
|
+
}
|
|
274
289
|
const redisKey = StockHolderRepo.createKey({ eventId: params.eventId, startDate: params.startDate });
|
|
275
290
|
return {
|
|
276
291
|
expireTime: yield this.redisClient.expireTime(redisKey),
|
|
@@ -281,26 +296,27 @@ class StockHolderRepo {
|
|
|
281
296
|
/**
|
|
282
297
|
* 新リポジトリを使用するかどうか
|
|
283
298
|
*/
|
|
299
|
+
// tslint:disable-next-line:prefer-function-over-method
|
|
284
300
|
useMongoose(params) {
|
|
285
301
|
return __awaiter(this, void 0, void 0, function* () {
|
|
286
302
|
if (!(params.startDate instanceof Date)) {
|
|
287
303
|
throw new factory.errors.Argument('startDate', 'must be Date');
|
|
288
304
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
else {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
}
|
|
299
|
-
// check confliction for test
|
|
300
|
-
if (USE_STOCK_HOLDER_CHECK_CONFLICT) {
|
|
301
|
-
|
|
302
|
-
}
|
|
303
|
-
return useMongoose;
|
|
305
|
+
// always use mongo(2025-08-17~)
|
|
306
|
+
return true;
|
|
307
|
+
// let useMongoose = false;
|
|
308
|
+
// const redisKeyExists = await this.redisKeyExists(params);
|
|
309
|
+
// if (redisKeyExists) {
|
|
310
|
+
// useMongoose = false;
|
|
311
|
+
// } else {
|
|
312
|
+
// // redis keyが存在しなければmongo利用
|
|
313
|
+
// useMongoose = true;
|
|
314
|
+
// }
|
|
315
|
+
// // check confliction for test
|
|
316
|
+
// if (USE_STOCK_HOLDER_CHECK_CONFLICT) {
|
|
317
|
+
// await this.checkIfConflicted(params);
|
|
318
|
+
// }
|
|
319
|
+
// return useMongoose;
|
|
304
320
|
});
|
|
305
321
|
}
|
|
306
322
|
}
|
|
@@ -119,12 +119,15 @@ export declare class TaskRepo {
|
|
|
119
119
|
* 実行日時を一定期間過ぎたReadyタスクについて、Runningスタータスに変更した上で、Runningイベントを発生させる
|
|
120
120
|
*/
|
|
121
121
|
emitRunningIfExists(params: {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
122
|
+
/**
|
|
123
|
+
* 必ずタスク名指定で実行する
|
|
124
|
+
*/
|
|
125
|
+
name: {
|
|
126
|
+
$eq: factory.taskName;
|
|
127
|
+
$in?: never;
|
|
128
|
+
} | {
|
|
129
|
+
$eq?: never;
|
|
130
|
+
$in: factory.taskName[];
|
|
128
131
|
};
|
|
129
132
|
runsAt: {
|
|
130
133
|
$lt: Date;
|
|
@@ -133,6 +136,10 @@ export declare class TaskRepo {
|
|
|
133
136
|
numberOfTried?: factory.sortType;
|
|
134
137
|
runsAt?: factory.sortType;
|
|
135
138
|
};
|
|
139
|
+
executor: {
|
|
140
|
+
name: string;
|
|
141
|
+
};
|
|
142
|
+
nameFilterBeforeRunsAt: boolean;
|
|
136
143
|
}, next?: INextFunction): Promise<Pick<factory.task.ITask<factory.taskName>, 'id' | 'name'> | null>;
|
|
137
144
|
/**
|
|
138
145
|
* Readyのままで期限切れのタスクをExpiredに変更する
|
package/lib/chevre/repo/task.js
CHANGED
|
@@ -460,7 +460,7 @@ class TaskRepo {
|
|
|
460
460
|
emitRunningIfExists(params, next // support next function(2025-08-02~)
|
|
461
461
|
) {
|
|
462
462
|
return __awaiter(this, void 0, void 0, function* () {
|
|
463
|
-
var _a
|
|
463
|
+
var _a;
|
|
464
464
|
if (!(params.runsAt.$lt instanceof Date)) {
|
|
465
465
|
throw new factory.errors.Argument('runsAt.$lt', 'must be Date');
|
|
466
466
|
}
|
|
@@ -471,12 +471,20 @@ class TaskRepo {
|
|
|
471
471
|
};
|
|
472
472
|
const nameEq = (_a = params.name) === null || _a === void 0 ? void 0 : _a.$eq;
|
|
473
473
|
// const nameNin = params.name?.$nin;
|
|
474
|
-
const nameIn =
|
|
475
|
-
const
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
474
|
+
// const nameIn = params.name?.$in;
|
|
475
|
+
const { nameFilterBeforeRunsAt } = params;
|
|
476
|
+
const filter = Object.assign(Object.assign(Object.assign({ status: { $eq: factory.taskStatus.Ready } }, (nameFilterBeforeRunsAt) ? { name: params.name } : undefined), { runsAt: { $lt: params.runsAt.$lt } }), (!nameFilterBeforeRunsAt) ? { name: params.name } : undefined
|
|
477
|
+
// ...(typeof nameEq === 'string' || Array.isArray(nameIn))
|
|
478
|
+
// ? {
|
|
479
|
+
// name: {
|
|
480
|
+
// ...(typeof nameEq === 'string') ? { $eq: nameEq } : undefined,
|
|
481
|
+
// // ...(Array.isArray(nameNin)) ? { $nin: nameNin } : undefined
|
|
482
|
+
// ...(Array.isArray(nameIn)) ? { $in: nameIn } : undefined
|
|
483
|
+
// }
|
|
484
|
+
// }
|
|
485
|
+
// : undefined
|
|
486
|
+
);
|
|
487
|
+
const doc = yield this.taskModel.findOneAndUpdate(filter, {
|
|
480
488
|
$set: {
|
|
481
489
|
status: factory.taskStatus.Running, // 実行中に変更
|
|
482
490
|
lastTriedAt: new Date(),
|
|
@@ -32,7 +32,7 @@ function call(data) {
|
|
|
32
32
|
yield (0, aggregateOffers_1.aggregateOffers)(data)({
|
|
33
33
|
aggregateReservation: new aggregateReservation_1.AggregateReservationRepo(connection),
|
|
34
34
|
event: new event_1.EventRepo(connection),
|
|
35
|
-
stockHolder: new stockHolder_1.StockHolderRepo(redisClient, connection),
|
|
35
|
+
stockHolder: new stockHolder_1.StockHolderRepo({ redisClient, connection }),
|
|
36
36
|
offer: new unitPriceInCatalog_1.OfferRepo(connection),
|
|
37
37
|
offerCatalog: new offerCatalog_1.OfferCatalogRepo(connection),
|
|
38
38
|
offerRateLimit: new offer_1.OfferRateLimitRepo(redisClient),
|
|
@@ -32,7 +32,7 @@ function call(data) {
|
|
|
32
32
|
}
|
|
33
33
|
yield AggregationService.event.aggregateScreeningEvent(data)({
|
|
34
34
|
event: new event_1.EventRepo(connection),
|
|
35
|
-
stockHolder: new stockHolder_1.StockHolderRepo(redisClient, connection),
|
|
35
|
+
stockHolder: new stockHolder_1.StockHolderRepo({ redisClient, connection }),
|
|
36
36
|
offer: new unitPriceInCatalog_1.OfferRepo(connection),
|
|
37
37
|
offerCatalog: new offerCatalog_1.OfferCatalogRepo(connection),
|
|
38
38
|
offerRateLimit: new offer_1.OfferRateLimitRepo(redisClient),
|
|
@@ -43,7 +43,7 @@ function call(params) {
|
|
|
43
43
|
yield (0, cancelReservation_1.cancelPendingReservation)({ purpose: data.purpose })({
|
|
44
44
|
action: new action_1.ActionRepo(connection),
|
|
45
45
|
assetTransaction: new assetTransaction_1.AssetTransactionRepo(connection),
|
|
46
|
-
stockHolder: new stockHolder_1.StockHolderRepo(redisClient, connection),
|
|
46
|
+
stockHolder: new stockHolder_1.StockHolderRepo({ redisClient, connection }),
|
|
47
47
|
offerRateLimit: new offer_1.OfferRateLimitRepo(redisClient),
|
|
48
48
|
reservation: new reservation_1.ReservationRepo(connection),
|
|
49
49
|
setting: new setting_1.SettingRepo(connection),
|
|
@@ -34,7 +34,7 @@ function call(data) {
|
|
|
34
34
|
task: new task_1.TaskRepo(connection),
|
|
35
35
|
assetTransaction: new assetTransaction_1.AssetTransactionRepo(connection),
|
|
36
36
|
offerRateLimit: new offer_1.OfferRateLimitRepo(redisClient),
|
|
37
|
-
stockHolder: new stockHolder_1.StockHolderRepo(redisClient, connection)
|
|
37
|
+
stockHolder: new stockHolder_1.StockHolderRepo({ redisClient, connection })
|
|
38
38
|
}
|
|
39
39
|
// settings
|
|
40
40
|
);
|
|
@@ -59,7 +59,7 @@ function call(data) {
|
|
|
59
59
|
project: { id: data.project.id }
|
|
60
60
|
})({
|
|
61
61
|
event: new event_1.EventRepo(connection),
|
|
62
|
-
stockHolder: new stockHolder_1.StockHolderRepo(redisClient, connection)
|
|
62
|
+
stockHolder: new stockHolder_1.StockHolderRepo({ redisClient, connection })
|
|
63
63
|
});
|
|
64
64
|
break;
|
|
65
65
|
default:
|
|
@@ -64,7 +64,7 @@ function call(params) {
|
|
|
64
64
|
yield (0, voidTransaction_1.voidTransaction)(Object.assign(Object.assign({}, params.data), { project: { id: params.project.id }, sameAs: { id: params.id } }))({
|
|
65
65
|
action: new action_1.ActionRepo(connection),
|
|
66
66
|
assetTransaction: new assetTransaction_1.AssetTransactionRepo(connection),
|
|
67
|
-
stockHolder: new stockHolder_1.StockHolderRepo(redisClient, connection),
|
|
67
|
+
stockHolder: new stockHolder_1.StockHolderRepo({ redisClient, connection }),
|
|
68
68
|
offerRateLimit: new offer_1.OfferRateLimitRepo(redisClient),
|
|
69
69
|
orderInTransaction: new orderInTransaction_1.OrderInTransactionRepo(connection),
|
|
70
70
|
reservation: new reservation_1.ReservationRepo(connection),
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { EventRepo } from '../../repo/event';
|
|
2
2
|
import type { StockHolderRepo } from '../../repo/stockHolder';
|
|
3
|
-
export declare function validateEvent(
|
|
3
|
+
export declare function validateEvent(__: {
|
|
4
4
|
id: string;
|
|
5
5
|
project: {
|
|
6
6
|
id: string;
|
|
7
7
|
};
|
|
8
|
-
}): (
|
|
8
|
+
}): (__2: {
|
|
9
9
|
event: EventRepo;
|
|
10
10
|
stockHolder: StockHolderRepo;
|
|
11
11
|
}) => Promise<void>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
// import * as createDebug from 'debug';
|
|
2
3
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
4
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
5
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -10,15 +11,20 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
11
|
};
|
|
11
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
13
|
exports.validateEvent = validateEvent;
|
|
13
|
-
|
|
14
|
-
const debug = createDebug('chevre-domain:service:validation');
|
|
15
|
-
function validateEvent(
|
|
16
|
-
return (
|
|
17
|
-
const event
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
14
|
+
// import * as factory from '../../factory';
|
|
15
|
+
// const debug = createDebug('chevre-domain:service:validation');
|
|
16
|
+
function validateEvent(__) {
|
|
17
|
+
return (__2) => __awaiter(this, void 0, void 0, function* () {
|
|
18
|
+
// const event: Pick<factory.event.screeningEvent.IEvent, 'id' | 'startDate'> =
|
|
19
|
+
// await repos.event.projectEventFieldsById<factory.eventType.ScreeningEvent>(
|
|
20
|
+
// { id: params.id },
|
|
21
|
+
// ['startDate']
|
|
22
|
+
// );
|
|
23
|
+
// discontinue redis(2025-08-17~)
|
|
24
|
+
// debug('validateEvent: conflicted?', params.project.id, event.id, event.startDate);
|
|
25
|
+
// await repos.stockHolder.checkIfConflicted({
|
|
26
|
+
// eventId: event.id,
|
|
27
|
+
// startDate: event.startDate
|
|
28
|
+
// });
|
|
23
29
|
});
|
|
24
30
|
}
|
package/package.json
CHANGED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
// tslint:disable:no-console
|
|
2
|
-
import * as moment from 'moment';
|
|
3
|
-
import * as mongoose from 'mongoose';
|
|
4
|
-
import * as redis from 'redis';
|
|
5
|
-
|
|
6
|
-
import { chevre } from '../../../../lib/index';
|
|
7
|
-
|
|
8
|
-
// const project = { id: String(process.env.PROJECT_ID) };
|
|
9
|
-
const excludedProject = { id: String(process.env.EXCLUDED_PROJECT_ID) };
|
|
10
|
-
|
|
11
|
-
const client = redis.createClient<redis.RedisDefaultModules, Record<string, never>, Record<string, never>>({
|
|
12
|
-
socket: {
|
|
13
|
-
port: Number(<string>process.env.REDIS_PORT),
|
|
14
|
-
host: <string>process.env.REDIS_HOST
|
|
15
|
-
},
|
|
16
|
-
password: <string>process.env.REDIS_KEY
|
|
17
|
-
})
|
|
18
|
-
.on('error', (err) => {
|
|
19
|
-
// eslint-disable-next-line no-console
|
|
20
|
-
console.error('createDefaultRedisClient: client onError:', err);
|
|
21
|
-
// reject(err);
|
|
22
|
-
});
|
|
23
|
-
client.connect();
|
|
24
|
-
mongoose.connect(<string>process.env.MONGOLAB_URI, { autoIndex: false });
|
|
25
|
-
|
|
26
|
-
// tslint:disable-next-line:max-func-body-length
|
|
27
|
-
async function main() {
|
|
28
|
-
const eventRepo = await chevre.repository.Event.createInstance(mongoose.connection);
|
|
29
|
-
const stockHolderRepo = await chevre.repository.StockHolder.createInstance(
|
|
30
|
-
client,
|
|
31
|
-
mongoose.connection
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
const cursor = eventRepo.getCursor(
|
|
35
|
-
{
|
|
36
|
-
'project.id': { $ne: excludedProject.id },
|
|
37
|
-
startDate: {
|
|
38
|
-
$gte: moment()
|
|
39
|
-
.add(-1, 'days')
|
|
40
|
-
.toDate()
|
|
41
|
-
},
|
|
42
|
-
typeOf: { $eq: chevre.factory.eventType.ScreeningEvent }
|
|
43
|
-
// _id: { $eq: 'blyk9q24f' }
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
_id: 1,
|
|
47
|
-
// offers: 1,
|
|
48
|
-
startDate: 1,
|
|
49
|
-
project: 1,
|
|
50
|
-
typeOf: 1
|
|
51
|
-
}
|
|
52
|
-
);
|
|
53
|
-
console.log('events found');
|
|
54
|
-
|
|
55
|
-
let i = 0;
|
|
56
|
-
await cursor.eachAsync(async (doc) => {
|
|
57
|
-
i += 1;
|
|
58
|
-
const event: Pick<
|
|
59
|
-
chevre.factory.event.screeningEvent.IEvent,
|
|
60
|
-
'id' | 'startDate' | 'project' | 'typeOf'
|
|
61
|
-
> = doc.toObject();
|
|
62
|
-
|
|
63
|
-
console.log(
|
|
64
|
-
'conflicted?', event.project.id, event.typeOf, event.id, event.startDate, i);
|
|
65
|
-
await stockHolderRepo.checkIfConflicted({
|
|
66
|
-
eventId: event.id,
|
|
67
|
-
startDate: event.startDate
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
console.log(i, 'events checked');
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
main()
|
|
75
|
-
.then()
|
|
76
|
-
.catch(console.error);
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
// tslint:disable:no-console
|
|
2
|
-
import * as moment from 'moment-timezone';
|
|
3
|
-
import * as mongoose from 'mongoose';
|
|
4
|
-
import * as redis from 'redis';
|
|
5
|
-
import { ILockKey } from '../../../../lib/chevre/repo/stockHolderAbstract';
|
|
6
|
-
import { chevre } from '../../../../lib/index';
|
|
7
|
-
|
|
8
|
-
const client = redis.createClient<redis.RedisDefaultModules, Record<string, never>, Record<string, never>>({
|
|
9
|
-
socket: {
|
|
10
|
-
port: Number(<string>process.env.REDIS_PORT),
|
|
11
|
-
host: <string>process.env.REDIS_HOST
|
|
12
|
-
},
|
|
13
|
-
password: <string>process.env.REDIS_KEY
|
|
14
|
-
})
|
|
15
|
-
.on('error', (err) => {
|
|
16
|
-
// eslint-disable-next-line no-console
|
|
17
|
-
console.error('createDefaultRedisClient: client onError:', err);
|
|
18
|
-
// reject(err);
|
|
19
|
-
});
|
|
20
|
-
client.connect();
|
|
21
|
-
mongoose.connect(<string>process.env.MONGOLAB_URI, { autoIndex: false });
|
|
22
|
-
|
|
23
|
-
const EVENT_ID = 'cm8dwc74c';
|
|
24
|
-
|
|
25
|
-
async function main() {
|
|
26
|
-
// 万が一に備えて、保留予約をredis->mongo移行するスクリプト
|
|
27
|
-
const assetTransactionRepo = await chevre.repository.AssetTransaction.createInstance(mongoose.connection);
|
|
28
|
-
const eventRepo = await chevre.repository.Event.createInstance(mongoose.connection);
|
|
29
|
-
// const pendingReservationRepo = await chevre.repository.PendingReservation.createInstance(mongoose.connection);
|
|
30
|
-
const stockHolderRepo = await chevre.repository.StockHolder.createInstance(client, mongoose.connection);
|
|
31
|
-
|
|
32
|
-
const event = await eventRepo.projectEventFieldsById(
|
|
33
|
-
{ id: EVENT_ID },
|
|
34
|
-
['startDate', 'organizer', 'project', 'offers']
|
|
35
|
-
);
|
|
36
|
-
const hasTicketedSeat = event.offers.itemOffered.serviceOutput?.reservedTicket?.ticketedSeat?.typeOf === chevre.factory.placeType.Seat;
|
|
37
|
-
const { expireTime, hash } = await stockHolderRepo.migrate2mongoJustInCase({
|
|
38
|
-
eventId: EVENT_ID,
|
|
39
|
-
startDate: event.startDate
|
|
40
|
-
// project: { id: event.project.id },
|
|
41
|
-
// provider: { id: event.organizer.id }
|
|
42
|
-
});
|
|
43
|
-
console.log(expireTime, hash);
|
|
44
|
-
|
|
45
|
-
const lockKeys: ILockKey[] = [];
|
|
46
|
-
const reservationNumbers: string[] = [...new Set(Object.values(hash))];
|
|
47
|
-
const expires: Date = moment.unix(expireTime)
|
|
48
|
-
.toDate();
|
|
49
|
-
console.log('reservationNumbers:', reservationNumbers);
|
|
50
|
-
console.log('expires:', expires);
|
|
51
|
-
|
|
52
|
-
// 予約番号ごとにlockKeyを作成する
|
|
53
|
-
for (const reservationNumber of reservationNumbers) {
|
|
54
|
-
const reserveTransaction = (await assetTransactionRepo.search<chevre.factory.assetTransactionType.Reserve>(
|
|
55
|
-
{
|
|
56
|
-
limit: 1,
|
|
57
|
-
page: 1,
|
|
58
|
-
transactionNumber: { $eq: reservationNumber },
|
|
59
|
-
typeOf: chevre.factory.assetTransactionType.Reserve,
|
|
60
|
-
status: { $in: [chevre.factory.transactionStatusType.Confirmed] }
|
|
61
|
-
},
|
|
62
|
-
['object', 'startDate']
|
|
63
|
-
)).shift();
|
|
64
|
-
if (reserveTransaction === undefined) {
|
|
65
|
-
throw new Error(`reserveTransaction not found ${reservationNumber}`);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const fields: string[] = Object.keys(hash)
|
|
69
|
-
.filter((field) => hash[field] === reservationNumber);
|
|
70
|
-
const lockKey: ILockKey = {
|
|
71
|
-
project: { id: event.project.id },
|
|
72
|
-
provider: { id: event.organizer.id },
|
|
73
|
-
eventId: EVENT_ID,
|
|
74
|
-
startDate: event.startDate,
|
|
75
|
-
hasTicketedSeat,
|
|
76
|
-
offers: fields.map((field) => {
|
|
77
|
-
const splitedField = field.split(':');
|
|
78
|
-
|
|
79
|
-
return {
|
|
80
|
-
seatSection: splitedField[0],
|
|
81
|
-
seatNumber: splitedField[1]
|
|
82
|
-
};
|
|
83
|
-
}),
|
|
84
|
-
expires,
|
|
85
|
-
holder: reservationNumber,
|
|
86
|
-
bookingTime: reserveTransaction.startDate
|
|
87
|
-
};
|
|
88
|
-
console.log('lockKey:', lockKey);
|
|
89
|
-
lockKeys.push(lockKey);
|
|
90
|
-
// await pendingReservationRepo.lock(lockKey);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
main()
|
|
95
|
-
.then(console.log)
|
|
96
|
-
.catch(console.error);
|
|
@@ -1,256 +0,0 @@
|
|
|
1
|
-
// tslint:disable:no-console
|
|
2
|
-
import * as moment from 'moment-timezone';
|
|
3
|
-
import * as mongoose from 'mongoose';
|
|
4
|
-
import * as redis from 'redis';
|
|
5
|
-
import { chevre } from '../../../../lib/index';
|
|
6
|
-
|
|
7
|
-
const today = moment()
|
|
8
|
-
.tz('Asia/Tokyo')
|
|
9
|
-
.format('YYYYMMDD');
|
|
10
|
-
const project = { id: String(process.env.PROJECT_ID) };
|
|
11
|
-
const providerId = 'sampleProviderId';
|
|
12
|
-
const eventId = `sampleEventId${today}:03`;
|
|
13
|
-
const eventStartDate = new Date('2025-05-01T00:00:00Z');
|
|
14
|
-
const expires = moment(eventStartDate)
|
|
15
|
-
.add(1, 'week')
|
|
16
|
-
.toDate();
|
|
17
|
-
const seatSection = 'SampleSectionNameXXXXXXXXXXXXXXXXXXX';
|
|
18
|
-
// tslint:disable-next-line:no-magic-numbers prefer-array-literal
|
|
19
|
-
const allSeatNumbers = [...Array(10000)].map((__, seatKey) => `SampleSeatNumber-${seatKey}`);
|
|
20
|
-
const OPERATION_INTERVAL = 2000;
|
|
21
|
-
// const MAXIMUM_CAPACITY = 10002;
|
|
22
|
-
|
|
23
|
-
mongoose.Model.on('index', (...args) => {
|
|
24
|
-
console.error('******** index event emitted. ********\n', args);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
async function sleep(waitTime: number): Promise<void> {
|
|
28
|
-
return new Promise<void>((resolve) => {
|
|
29
|
-
setTimeout(
|
|
30
|
-
() => {
|
|
31
|
-
resolve();
|
|
32
|
-
},
|
|
33
|
-
waitTime
|
|
34
|
-
);
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const client = redis.createClient<redis.RedisDefaultModules, Record<string, never>, Record<string, never>>({
|
|
39
|
-
socket: {
|
|
40
|
-
port: Number(<string>process.env.REDIS_PORT),
|
|
41
|
-
host: <string>process.env.REDIS_HOST
|
|
42
|
-
},
|
|
43
|
-
password: <string>process.env.REDIS_KEY
|
|
44
|
-
})
|
|
45
|
-
.on('error', (err) => {
|
|
46
|
-
// eslint-disable-next-line no-console
|
|
47
|
-
console.error('createDefaultRedisClient: client onError:', err);
|
|
48
|
-
// reject(err);
|
|
49
|
-
});
|
|
50
|
-
client.connect();
|
|
51
|
-
mongoose.connect(<string>process.env.MONGOLAB_URI, { autoIndex: false });
|
|
52
|
-
|
|
53
|
-
const formatter = new Intl.NumberFormat('ja-JP');
|
|
54
|
-
// => "1,000"
|
|
55
|
-
|
|
56
|
-
// tslint:disable-next-line:max-func-body-length
|
|
57
|
-
async function lockSeatsForcibly(params: {
|
|
58
|
-
maximumCapacity?: number;
|
|
59
|
-
}) {
|
|
60
|
-
const { maximumCapacity } = params;
|
|
61
|
-
let startTime: [number, number] = process.hrtime();
|
|
62
|
-
let diff: [number, number] = process.hrtime(startTime);
|
|
63
|
-
|
|
64
|
-
const stockHolderRepo = await chevre.repository.StockHolder.createInstance(
|
|
65
|
-
client,
|
|
66
|
-
mongoose.connection
|
|
67
|
-
);
|
|
68
|
-
|
|
69
|
-
startTime = process.hrtime();
|
|
70
|
-
console.log('counting unavailableOffers...');
|
|
71
|
-
let countUnavailableOffersResult = await stockHolderRepo.countUnavailableOffers({
|
|
72
|
-
project: { id: project.id },
|
|
73
|
-
event: {
|
|
74
|
-
id: eventId,
|
|
75
|
-
startDate: eventStartDate,
|
|
76
|
-
hasTicketedSeat: true
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
console.log('countUnavailableOffersResult:', countUnavailableOffersResult);
|
|
80
|
-
console.log('diff:', [diff[0], formatter.format(diff[1])]);
|
|
81
|
-
|
|
82
|
-
await sleep(OPERATION_INTERVAL);
|
|
83
|
-
startTime = process.hrtime();
|
|
84
|
-
console.log('counting searching holders...');
|
|
85
|
-
const searchHoldersResult = await stockHolderRepo.searchHolders({
|
|
86
|
-
project: { id: project.id },
|
|
87
|
-
eventId,
|
|
88
|
-
startDate: eventStartDate,
|
|
89
|
-
hasTicketedSeat: true,
|
|
90
|
-
offers: [
|
|
91
|
-
// tslint:disable-next-line:no-magic-numbers
|
|
92
|
-
...allSeatNumbers.slice(0, 100)
|
|
93
|
-
.map((seatNumber) => ({ seatSection, seatNumber }))
|
|
94
|
-
]
|
|
95
|
-
});
|
|
96
|
-
diff = process.hrtime(startTime);
|
|
97
|
-
console.log('searchHoldersResult.length:', searchHoldersResult.length);
|
|
98
|
-
console.log('diff:', [diff[0], formatter.format(diff[1])]);
|
|
99
|
-
|
|
100
|
-
// select 2 seats
|
|
101
|
-
// tslint:disable-next-line:insecure-random
|
|
102
|
-
const seatNumber1 = allSeatNumbers[Math.floor(allSeatNumbers.length * Math.random())];
|
|
103
|
-
const seatNumber2 = allSeatNumbers.filter((seatNumber) => seatNumber !== seatNumber1)[
|
|
104
|
-
// tslint:disable-next-line:insecure-random
|
|
105
|
-
Math.floor((allSeatNumbers.length - 1) * Math.random())
|
|
106
|
-
];
|
|
107
|
-
|
|
108
|
-
const seatNumbers = [seatNumber1, seatNumber2];
|
|
109
|
-
console.log('seats selected.', seatNumbers);
|
|
110
|
-
|
|
111
|
-
let locked = false;
|
|
112
|
-
while (!locked) {
|
|
113
|
-
await sleep(OPERATION_INTERVAL);
|
|
114
|
-
startTime = process.hrtime();
|
|
115
|
-
const currentHolders: string[] = [];
|
|
116
|
-
for (const seatNumber of seatNumbers) {
|
|
117
|
-
const currentHolder = await stockHolderRepo.getHolder({
|
|
118
|
-
project: { id: project.id },
|
|
119
|
-
eventId,
|
|
120
|
-
startDate: eventStartDate,
|
|
121
|
-
hasTicketedSeat: true,
|
|
122
|
-
offer: { seatSection, seatNumber }
|
|
123
|
-
});
|
|
124
|
-
if (typeof currentHolder === 'string') {
|
|
125
|
-
currentHolders.push(currentHolder);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
diff = process.hrtime(startTime);
|
|
129
|
-
console.log('currentHolders:', currentHolders);
|
|
130
|
-
console.log('diff:', [diff[0], formatter.format(diff[1])]);
|
|
131
|
-
|
|
132
|
-
try {
|
|
133
|
-
await sleep(OPERATION_INTERVAL);
|
|
134
|
-
const newHolder = Date.now()
|
|
135
|
-
.toString();
|
|
136
|
-
const bookingTime = new Date();
|
|
137
|
-
startTime = process.hrtime();
|
|
138
|
-
console.log('locking...', newHolder, seatSection, seatNumbers);
|
|
139
|
-
if (typeof maximumCapacity === 'number') {
|
|
140
|
-
try {
|
|
141
|
-
await stockHolderRepo.lockIfNotLimitExceeded(
|
|
142
|
-
{
|
|
143
|
-
project: { id: project.id },
|
|
144
|
-
provider: { id: providerId },
|
|
145
|
-
eventId,
|
|
146
|
-
startDate: eventStartDate,
|
|
147
|
-
hasTicketedSeat: true,
|
|
148
|
-
offers: seatNumbers.map((seatNumber) => ({ seatSection, seatNumber })),
|
|
149
|
-
expires,
|
|
150
|
-
holder: newHolder,
|
|
151
|
-
bookingTime
|
|
152
|
-
},
|
|
153
|
-
maximumCapacity
|
|
154
|
-
);
|
|
155
|
-
} catch (error) {
|
|
156
|
-
if (error.message === 'maximumAttendeeCapacity exceeded') {
|
|
157
|
-
// ok
|
|
158
|
-
} else {
|
|
159
|
-
throw error;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
} else {
|
|
163
|
-
await stockHolderRepo.lock({
|
|
164
|
-
project: { id: project.id },
|
|
165
|
-
provider: { id: providerId },
|
|
166
|
-
eventId,
|
|
167
|
-
startDate: eventStartDate,
|
|
168
|
-
hasTicketedSeat: true,
|
|
169
|
-
offers: seatNumbers.map((seatNumber) => ({ seatSection, seatNumber })),
|
|
170
|
-
expires,
|
|
171
|
-
holder: newHolder,
|
|
172
|
-
bookingTime
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
diff = process.hrtime(startTime);
|
|
176
|
-
console.log('locked.', newHolder);
|
|
177
|
-
console.log('diff:', [diff[0], formatter.format(diff[1])]);
|
|
178
|
-
locked = true;
|
|
179
|
-
} catch (error) {
|
|
180
|
-
if (error instanceof chevre.factory.errors.AlreadyInUse) {
|
|
181
|
-
console.log('lockResult:', error.name, error.message);
|
|
182
|
-
} else {
|
|
183
|
-
console.error(error);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
await sleep(OPERATION_INTERVAL);
|
|
188
|
-
for (const currentHolder of currentHolders) {
|
|
189
|
-
for (const seatNumber of seatNumbers) {
|
|
190
|
-
startTime = process.hrtime();
|
|
191
|
-
console.log('unlocking...', currentHolder, seatSection, seatNumber);
|
|
192
|
-
const unlockResult = await stockHolderRepo.unlock({
|
|
193
|
-
project: { id: project.id },
|
|
194
|
-
eventId,
|
|
195
|
-
startDate: eventStartDate,
|
|
196
|
-
hasTicketedSeat: true,
|
|
197
|
-
offer: { seatSection, seatNumber },
|
|
198
|
-
holder: currentHolder
|
|
199
|
-
});
|
|
200
|
-
diff = process.hrtime(startTime);
|
|
201
|
-
console.log('unlockResult:', unlockResult);
|
|
202
|
-
console.log('diff:', [diff[0], formatter.format(diff[1])]);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
await sleep(OPERATION_INTERVAL);
|
|
208
|
-
countUnavailableOffersResult = await stockHolderRepo.countUnavailableOffers({
|
|
209
|
-
project: { id: project.id },
|
|
210
|
-
event: {
|
|
211
|
-
id: eventId,
|
|
212
|
-
startDate: eventStartDate,
|
|
213
|
-
hasTicketedSeat: true
|
|
214
|
-
}
|
|
215
|
-
});
|
|
216
|
-
console.log('countUnavailableOffersResult:', countUnavailableOffersResult);
|
|
217
|
-
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
async function main() {
|
|
221
|
-
// tslint:disable-next-line:no-magic-numbers
|
|
222
|
-
const numLock = (typeof process.argv[2] === 'string') ? Number(process.argv[2]) : 1;
|
|
223
|
-
// tslint:disable-next-line:no-magic-numbers
|
|
224
|
-
const maximumCapacity = (typeof process.argv[3] === 'string') ? Number(process.argv[3]) : undefined;
|
|
225
|
-
|
|
226
|
-
const LOCK_INTERVAL = 300;
|
|
227
|
-
let i = 0;
|
|
228
|
-
let lockedCount = 0;
|
|
229
|
-
let timeout: NodeJS.Timeout;
|
|
230
|
-
const processStartDate = new Date();
|
|
231
|
-
function onSeatsLocked() {
|
|
232
|
-
lockedCount += 1;
|
|
233
|
-
console.log(lockedCount, 'lockSeatsForcibly executed!');
|
|
234
|
-
console.log('processed.', processStartDate, '~', new Date());
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
timeout = setInterval(
|
|
238
|
-
() => {
|
|
239
|
-
if (i >= numLock) {
|
|
240
|
-
clearInterval(timeout);
|
|
241
|
-
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
i += 1;
|
|
246
|
-
lockSeatsForcibly({ maximumCapacity })
|
|
247
|
-
.then(onSeatsLocked)
|
|
248
|
-
.catch(console.error);
|
|
249
|
-
},
|
|
250
|
-
LOCK_INTERVAL
|
|
251
|
-
);
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
main()
|
|
255
|
-
.then()
|
|
256
|
-
.catch(console.error);
|