Skip to content

Commit 97a63f9

Browse files
Update prod (#418)
* imp(limiter): do not count events for already blocked workspaces * Revert "imp(limiter): do not count events for already blocked workspaces" This reverts commit 83961aa. * Imp(limiter): perfomance improvement (#414) * imp(limiter): do not count events for already blocked workspaces * imp(limiter): do not count events for blocked workspaces * imp(): remove redundant condition * fix(release): release worker dies (#417) * fix(release): check that file.content is not empty * fix(release): delete inside of the Promise.all * feat(paymaster): add paidUntil recharge logic (#416) * feat(paymaster): add paidUntil recharge logic * test(paymaster): cover paidUntil recharge logic * imp(paymaster): isTimeToRecharge added * fix(): expect ts error * imp(): comment --------- Co-authored-by: e11sy <130844513+e11sy@users.noreply.github.com>
1 parent e0a2d30 commit 97a63f9

4 files changed

Lines changed: 121 additions & 18 deletions

File tree

lib/utils/hasValue.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/**
22
* Returns true if specified value is not undefined, null and empty string
3+
*
34
* @param v - value to check
45
*/
56
export function hasValue<T>(v: T | undefined | null): v is T {

workers/paymaster/src/index.ts

Lines changed: 50 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -60,24 +60,47 @@ export default class PaymasterWorker extends Worker {
6060
/**
6161
* Check if today is a payday for passed timestamp
6262
*
63-
* Pay day is calculated by formula: last charge date + 30 days
64-
*
6563
* @param date - last charge date
6664
* @param paidUntil - paid until date
6765
* @param isDebug - flag for debug purposes
6866
*/
69-
private static isTimeToPay(date: Date, paidUntil: Date, isDebug = false): boolean {
70-
const expectedPayDay = paidUntil ? new Date(paidUntil) : new Date(date);
67+
private static isTimeToPay(date: Date, paidUntil?: Date, isDebug = false): boolean {
68+
const expectedPayDay = paidUntil ? new Date(paidUntil) : this.composeBillingPeriodEndDate(date, isDebug);
69+
const now = new Date();
70+
71+
return now >= expectedPayDay;
72+
}
73+
74+
/**
75+
* Check if today is a recharge day for passed timestamp
76+
* It equals to the isTimeToPay in all cases except prePaid workspaces
77+
*
78+
* @param date - last charge date
79+
* @param isDebug - flag for debug purposes
80+
*/
81+
private static isTimeToRecharge(date: Date, isDebug = false): boolean {
82+
const nexTimeToRecharge = this.composeBillingPeriodEndDate(date, isDebug);
83+
const now = new Date();
84+
85+
return now >= nexTimeToRecharge;
86+
}
87+
88+
/**
89+
* Returns the date - end of the billing period
90+
*
91+
* @param date - last charge date
92+
* @param isDebug - flag for debug workspaces
93+
*/
94+
private static composeBillingPeriodEndDate(date: Date, isDebug = false): Date {
95+
const endDate = new Date(date);
7196

7297
if (isDebug) {
73-
expectedPayDay.setDate(date.getDate() + 1);
74-
} else if (!paidUntil) {
75-
expectedPayDay.setMonth(date.getMonth() + 1);
98+
endDate.setDate(date.getDate() + 1);
99+
} else {
100+
endDate.setMonth(date.getMonth() + 1);
76101
}
77102

78-
const now = new Date().getTime();
79-
80-
return now >= expectedPayDay.getTime();
103+
return endDate;
81104
}
82105

83106
/**
@@ -214,6 +237,12 @@ export default class PaymasterWorker extends Worker {
214237
// @ts-expect-error debug
215238
const isTimeToPay = PaymasterWorker.isTimeToPay(workspace.lastChargeDate, workspace.paidUntil, workspace.isDebug);
216239

240+
/**
241+
* Is it time to recharge workspace limits
242+
*/
243+
// @ts-expect-error debug
244+
const isTimeToRecharge = PaymasterWorker.isTimeToRecharge(workspace.lastChargeDate, workspace.isDebug);
245+
217246
/**
218247
* How many days have passed since payments the expected day of payments
219248
*/
@@ -237,7 +266,17 @@ export default class PaymasterWorker extends Worker {
237266
*/
238267
if (!isTimeToPay) {
239268
/**
240-
* If workspace was manually unblocked (reset of billingPeriodEventsCount and lastChargeDate) in db
269+
* If it is time to recharge workspace limits, but not time to pay
270+
* Start new month - recharge billing period events count and update last charge date
271+
*/
272+
if (isTimeToRecharge) {
273+
await this.updateLastChargeDate(workspace, date);
274+
await this.clearBillingPeriodEventsCount(workspace);
275+
}
276+
277+
/**
278+
* If workspace is blocked, but it is not time to pay
279+
* This case could be reached by prepaid workspaces and manually recharged ones
241280
*/
242281
if (workspace.isBlocked) {
243282
await this.unblockWorkspace(workspace);

workers/paymaster/tests/index.test.ts

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -481,11 +481,6 @@ describe('PaymasterWorker', () => {
481481
MockDate.reset();
482482
});
483483

484-
afterAll(async () => {
485-
await connection.close();
486-
MockDate.reset();
487-
});
488-
489484
test('Should send notification if payday is coming for workspace with paidUntil value', async () => {
490485
/**
491486
* Arrange
@@ -542,4 +537,62 @@ describe('PaymasterWorker', () => {
542537

543538
MockDate.reset();
544539
});
540+
541+
test('Should recharge workspace billing period when month passes since last charge date and paidUntil is set to several months in the future', async () => {
542+
/**
543+
* Arrange
544+
*/
545+
const currentDate = new Date();
546+
const lastChargeDate = new Date(currentDate.getTime());
547+
548+
lastChargeDate.setMonth(lastChargeDate.getMonth() - 1); // Set last charge date to 1 month ago
549+
550+
const paidUntil = new Date(currentDate.getTime());
551+
552+
paidUntil.setMonth(paidUntil.getMonth() + 3); // Set paidUntil to 3 months in the future
553+
554+
const plan = createPlanMock({
555+
monthlyCharge: 100,
556+
isDefault: true,
557+
});
558+
const workspace = createWorkspaceMock({
559+
plan,
560+
subscriptionId: null,
561+
lastChargeDate,
562+
isBlocked: false,
563+
billingPeriodEventsCount: 10,
564+
paidUntil,
565+
});
566+
567+
await fillDatabaseWithMockedData({
568+
workspace,
569+
plan,
570+
});
571+
572+
MockDate.set(currentDate);
573+
574+
/**
575+
* Act
576+
*/
577+
const worker = new PaymasterWorker();
578+
579+
await worker.start();
580+
await worker.handle(WORKSPACE_SUBSCRIPTION_CHECK);
581+
await worker.finish();
582+
583+
/**
584+
* Assert
585+
*/
586+
const updatedWorkspace = await workspacesCollection.findOne({ _id: workspace._id });
587+
588+
expect(updatedWorkspace.lastChargeDate).toEqual(currentDate);
589+
expect(updatedWorkspace.billingPeriodEventsCount).toEqual(0);
590+
591+
MockDate.reset();
592+
});
593+
594+
afterAll(async () => {
595+
await connection.close();
596+
MockDate.reset();
597+
});
545598
});

workers/release/src/index.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,17 +179,23 @@ export default class ReleaseWorker extends Worker {
179179
const fileInfo = await this.saveFile(map);
180180

181181
/**
182-
* Remove 'content' and save id of saved file instead
182+
* Save id of saved file instead
183183
*/
184184
map._id = fileInfo._id;
185-
delete map.content;
186185

187186
return map;
188187
} catch (error) {
189188
this.logger.error(`Map ${map.mapFileName} was not saved: ${error}`);
190189
}
191190
}));
192191

192+
/**
193+
* Delete file content after it is saved to the GridFS
194+
*/
195+
savedFiles.forEach(file => {
196+
delete file.content;
197+
})
198+
193199
/**
194200
* Filter unsaved maps
195201
*/
@@ -282,6 +288,10 @@ export default class ReleaseWorker extends Worker {
282288
*/
283289
private saveFile(file: SourceMapDataExtended): Promise<SourceMapFileChunk> {
284290
return new Promise((resolve, reject) => {
291+
if (!file.content) {
292+
return reject(new Error('Source map content is empty'));
293+
}
294+
285295
const readable = Readable.from([ file.content ]);
286296
const writeStream = this.db.getBucket().openUploadStream(file.mapFileName);
287297

0 commit comments

Comments
 (0)