Skip to content

Commit 9c1f6e7

Browse files
committed
Merge branch 'master' of github.com:codex-team/hawk.workers into new-diff
2 parents 13057d6 + cd245f5 commit 9c1f6e7

19 files changed

Lines changed: 325 additions & 139 deletions

File tree

lib/worker.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -327,10 +327,8 @@ export abstract class Worker {
327327
};
328328
}
329329

330-
331330
console.log('handle error');
332331
console.log(e);
333-
334332

335333
HawkCatcher.send(e, context);
336334

package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"migrate:down": "migrate-mongo down",
1717
"lint": "eslint -c ./.eslintrc.js --ext .ts,.js --fix .",
1818
"test": "jest --coverage --runInBand",
19+
"test:archiver": "jest workers/archiver",
1920
"test:base": "jest lib/worker",
2021
"test:db": "jest lib/db/",
2122
"test:cache": "jest lib/cache",
@@ -29,6 +30,7 @@
2930
"test:diff": "jest ./workers/grouper/tests/diff.test.ts",
3031
"test:paymaster": "jest workers/paymaster",
3132
"test:notifier": "jest workers/notifier",
33+
"test:js": "jest workers/javascript",
3234
"test:clear": "jest --clearCache",
3335
"run-default": "yarn worker hawk-worker-default",
3436
"run-sentry": "yarn worker hawk-worker-sentry",
@@ -69,7 +71,9 @@
6971
"typescript": "^4.9.4",
7072
"uuid": "^8.3.0",
7173
"winston": "^3.2.1",
72-
"yup": "^0.28.5"
74+
"yup": "^0.28.5",
75+
"@babel/parser": "^7.26.9",
76+
"@babel/traverse": "7.26.9"
7377
},
7478
"devDependencies": {
7579
"@shelf/jest-mongodb": "^1.2.3",

workers/archiver/src/index.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { DatabaseController } from '../../../lib/db/controller';
22
import { Worker } from '../../../lib/worker';
33
import * as pkg from '../package.json';
44
import asyncForEach from '../../../lib/utils/asyncForEach';
5-
import { Collection, Db, GridFSBucket, ObjectId } from 'mongodb';
5+
import { Collection, Db, GridFSBucket, ObjectId, ObjectID } from 'mongodb';
66
import axios from 'axios';
77
import { ReleaseFileData, ReleaseRecord, ReportData, ReportDataByProject } from './types';
88
import * as path from 'path';
@@ -348,13 +348,25 @@ export default class ArchiverWorker extends Worker {
348348
* @param project - project to handle
349349
*/
350350
private async removeOldReleases(project: ProjectDBScheme): Promise<number> {
351-
const RELEASES_COUNT_TO_REMOVE = 3;
351+
const RELEASES_COUNT_TO_STAY = 2;
352+
const maxDaysInSeconds = +process.env.MAX_DAYS_NUMBER * HOURS_IN_DAY * MINUTES_IN_HOUR * SECONDS_IN_MINUTE;
353+
/**
354+
* Create timestamp for one month ago
355+
*/
356+
const maxOldTimestamp = (new Date().getTime()) / MS_IN_SEC - maxDaysInSeconds;
357+
358+
/**
359+
* Create mongo ObjectId for record that was inserted one month ago
360+
*/
361+
const objectIdThreshold = ObjectID.createFromTime(maxOldTimestamp);
362+
352363
const releasesToRemove = await this.releasesCollection
353364
.find({
354365
projectId: project._id.toString(),
366+
_id: { $lt: objectIdThreshold },
355367
})
356368
.sort({ _id: -1 })
357-
.skip(RELEASES_COUNT_TO_REMOVE)
369+
.skip(RELEASES_COUNT_TO_STAY)
358370
.toArray();
359371

360372
const filesToDelete = releasesToRemove.reduce<ReleaseFileData[]>(

workers/archiver/tests/index.test.ts

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ describe('Archiver worker', () => {
5151
await eventsCollection.insertMany(mockedEvents);
5252
});
5353

54+
beforeEach(async () => {
55+
await db.collection('releases').deleteMany({});
56+
})
57+
5458
test('Should correctly remove old events', async () => {
5559
/**
5660
* Worker initialization
@@ -111,6 +115,22 @@ describe('Archiver worker', () => {
111115
test('Should remove old releases', async () => {
112116
await db.collection('releases').insertMany(mockedReleases);
113117

118+
const mockedReleasesLength = mockedReleases.length;
119+
120+
const releasesToStay = {
121+
_id: new ObjectId(),
122+
projectId: '5e4ff518628a6c714515f4da',
123+
release: 'releasetostay',
124+
files: [ {
125+
_id: new ObjectId('5eb119ec6570b9405cdc5b48'),
126+
} ],
127+
};
128+
129+
/**
130+
* Insert one release with object id based on current time, it should not be removed
131+
*/
132+
await db.collection('releases').insert(releasesToStay)
133+
114134
const worker = new ArchiverWorker();
115135

116136
await worker.start();
@@ -122,11 +142,41 @@ describe('Archiver worker', () => {
122142
.find({})
123143
.toArray();
124144

125-
expect(newReleasesCollection).toEqual(mockedReleases.slice(mockedReleases.length - 3));
126-
expect(gridFsDeleteMock).toHaveBeenCalledTimes(mockedReleases.length - 3);
145+
expect(newReleasesCollection).toEqual([
146+
mockedReleases[mockedReleasesLength - 2],
147+
mockedReleases[mockedReleasesLength - 1],
148+
releasesToStay,
149+
]);
150+
151+
expect(gridFsDeleteMock).toHaveBeenCalledTimes(mockedReleases.length - 2);
127152
await worker.finish();
128153
});
129154

155+
test('Should leave two releases if all of the releases are more than month old', async () => {
156+
/**
157+
* Clear collection after previous test
158+
*/
159+
await db.collection('releases').insertMany(mockedReleases);
160+
161+
const mockedReleasesLength = mockedReleases.length;
162+
163+
const worker = new ArchiverWorker();
164+
165+
await worker.start();
166+
167+
await worker['removeOldReleases'](mockedProject);
168+
169+
const newReleasesCollection = await db.collection('releases')
170+
.find({})
171+
.toArray();
172+
173+
expect(newReleasesCollection).toEqual([
174+
mockedReleases[mockedReleasesLength - 2],
175+
mockedReleases[mockedReleasesLength - 1],
176+
])
177+
await worker.finish();
178+
})
179+
130180
afterAll(async () => {
131181
await db.dropCollection('releases');
132182
await db.dropCollection('projects');

workers/archiver/tests/releases.mock.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,79 +2,79 @@ import { ObjectId } from 'mongodb';
22

33
const mockedReleases = [
44
{
5-
_id: new ObjectId('5eb119ec6570b9405cdc5b48'),
5+
_id: new ObjectId('5e7119ec6570b9405cdc5b48'),
66
projectId: '5e4ff518628a6c714515f4da',
77
release: 'kjjцувgfchfc',
88
files: [ {
99
_id: new ObjectId('5eb119ec6570b9405cdc5b48'),
1010
} ],
1111
},
1212
{
13-
_id: new ObjectId('5eb119f16570b9405cdc5b4b'),
13+
_id: new ObjectId('5e7119f16570b9405cdc5b4b'),
1414
projectId: '5e4ff518628a6c714515f4da',
1515
release: 'kwedewdc',
1616
files: [ {
1717
_id: new ObjectId('5eb119ec6570b9405cdc5b48'),
1818
} ],
1919
},
2020
{
21-
_id: new ObjectId('5eb119f56570b9405cdc5b4e'),
21+
_id: new ObjectId('5e7119f56570b9405cdc5b4e'),
2222
projectId: '5e4ff518628a6c714515f4da',
2323
release: 'f43fwew',
2424
files: [ {
2525
_id: new ObjectId('5eb119ec6570b9405cdc5b48'),
2626
} ],
2727
},
2828
{
29-
_id: new ObjectId('5eb127776570b9405cdc5b51'),
29+
_id: new ObjectId('5e7127776570b9405cdc5b51'),
3030
projectId: '5e4ff518628a6c714515f4da',
3131
release: 'f43fwerferfeferfew',
3232
files: [ {
3333
_id: new ObjectId('5eb119ec6570b9405cdc5b48'),
3434
} ],
3535
},
3636
{
37-
_id: new ObjectId('5eb1277b6570b9405cdc5b54'),
37+
_id: new ObjectId('5e71277b6570b9405cdc5b54'),
3838
projectId: '5e4ff518628a6c714515f4da',
3939
release: 'f43fweerferfrferfeferfew',
4040
files: [ {
4141
_id: new ObjectId('5eb119ec6570b9405cdc5b48'),
4242
} ],
4343
},
4444
{
45-
_id: new ObjectId('5eb127816570b9405cdc5b57'),
45+
_id: new ObjectId('5e7127816570b9405cdc5b57'),
4646
projectId: '5e4ff518628a6c714515f4da',
4747
release: 'f4erferg4few',
4848
files: [ {
4949
_id: new ObjectId('5eb119ec6570b9405cdc5b48'),
5050
} ],
5151
},
5252
{
53-
_id: new ObjectId('5eb1278a6570b9405cdc5b5a'),
53+
_id: new ObjectId('5e71278a6570b9405cdc5b5a'),
5454
projectId: '5e4ff518628a6c714515f4da',
5555
release: 'ff34f34f34',
5656
files: [ {
5757
_id: new ObjectId('5eb119ec6570b9405cdc5b48'),
5858
} ],
5959
},
6060
{
61-
_id: new ObjectId('5eb127926570b9405cdc5b5d'),
61+
_id: new ObjectId('5e7127926570b9405cdc5b5d'),
6262
projectId: '5e4ff518628a6c714515f4da',
6363
release: '34df34re',
6464
files: [ {
6565
_id: new ObjectId('5eb119ec6570b9405cdc5b48'),
6666
} ],
6767
},
6868
{
69-
_id: new ObjectId('5eb127ac6570b9405cdc5b60'),
69+
_id: new ObjectId('5e7127ac6570b9405cdc5b60'),
7070
projectId: '5e4ff518628a6c714515f4da',
7171
release: 'wefwefweghbrvd',
7272
files: [ {
7373
_id: new ObjectId('5eb119ec6570b9405cdc5b48'),
7474
} ],
7575
},
7676
{
77-
_id: new ObjectId('5eb127b56570b9405cdc5b63'),
77+
_id: new ObjectId('5e7127b56570b9405cdc5b63'),
7878
projectId: '5e4ff518628a6c714515f4da',
7979
release: '45gfewd',
8080
files: [ {

workers/email/src/templates/extensions.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ Twig.extendFilter('leftTrim', ((value: string, maxLen: number): string => {
4646
if (value.length > maxLen) {
4747
return '…' + value.slice(value.length - maxLen);
4848
}
49+
4950
return value;
5051
}) as unknown as (value: any, params: false | any[]) => string); // tmp case. We need to check if TS says correct types or our implementation is correct
5152

workers/grouper/src/index.ts

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,7 @@ export default class GrouperWorker extends Worker {
9898
/**
9999
* Find event by group hash.
100100
*/
101-
let existedEvent = await this.getEvent(task.projectId, {
102-
groupHash: uniqueEventHash,
103-
});
101+
let existedEvent = await this.getEvent(task.projectId, uniqueEventHash);
104102

105103
/**
106104
* If we couldn't group by group hash (title), try grouping by Levenshtein distance with last N events
@@ -134,7 +132,7 @@ export default class GrouperWorker extends Worker {
134132

135133
if (isFirstOccurrence) {
136134
try {
137-
const incrementAffectedUsers = task.event.user ? true : false;
135+
const incrementAffectedUsers = !!task.event.user;
138136

139137
/**
140138
* Insert new event
@@ -147,6 +145,13 @@ export default class GrouperWorker extends Worker {
147145
usersAffected: incrementAffectedUsers ? 1 : 0,
148146
} as GroupedEventDBScheme);
149147

148+
const eventCacheKey = await this.getEventCacheKey(task.projectId, uniqueEventHash);
149+
150+
/**
151+
* If event is saved, then cached event state is no longer actual, so we should remove it
152+
*/
153+
this.cache.del(eventCacheKey);
154+
150155
/**
151156
* Increment daily affected users for the first event
152157
*/
@@ -158,7 +163,7 @@ export default class GrouperWorker extends Worker {
158163
*/
159164
if (e.code?.toString() === DB_DUPLICATE_KEY_ERROR) {
160165
console.log('DB_DUPLICATE_KEY_ERROR');
161-
166+
162167
HawkCatcher.send(new Error('[Grouper] MongoError: E11000 duplicate key error collection'));
163168
await this.handle(task);
164169

@@ -275,7 +280,7 @@ export default class GrouperWorker extends Worker {
275280
})
276281
.limit(count)
277282
.toArray();
278-
},
283+
},
279284
/**
280285
* TimeMs class stores time intervals in milliseconds, however NodeCache ttl needs to be specified in seconds
281286
*/
@@ -300,7 +305,6 @@ export default class GrouperWorker extends Worker {
300305
return [false, false];
301306
}
302307

303-
304308
/**
305309
* Default to true - we'll set to false if conditions are met
306310
*/
@@ -392,25 +396,37 @@ export default class GrouperWorker extends Worker {
392396
* Returns finds event by query from project with passed ID
393397
*
394398
* @param projectId - project's identifier
395-
* @param query - mongo query string
399+
* @param groupHash - group hash of the event
396400
*/
397-
private async getEvent(projectId: string, query: Record<string, unknown>): Promise<GroupedEventDBScheme> {
401+
private async getEvent(projectId: string, groupHash: string): Promise<GroupedEventDBScheme> {
398402
if (!mongodb.ObjectID.isValid(projectId)) {
399403
throw new ValidationError('Controller.saveEvent: Project ID is invalid or missed');
400404
}
401405

402-
const eventCacheKey = `${projectId}:${JSON.stringify(query)}`;
406+
const eventCacheKey = await this.getEventCacheKey(projectId, groupHash);
403407

404408
return this.cache.get(eventCacheKey, async () => {
405409
return this.db.getConnection()
406410
.collection(`events:${projectId}`)
407-
.findOne(query)
411+
.findOne({
412+
groupHash,
413+
})
408414
.catch((err) => {
409415
throw new DatabaseReadWriteError(err);
410416
});
411417
});
412418
}
413419

420+
/**
421+
* Method that returns event cache key based on projectId and groupHash
422+
* @param projectId - used for cache key creation
423+
* @param groupHash - used for cache key creation
424+
* @returns cache key
425+
*/
426+
private async getEventCacheKey(projectId: string, groupHash: string): Promise<string> {
427+
return `${projectId}:${JSON.stringify({groupHash: groupHash})}`
428+
}
429+
414430
/**
415431
* Save event to database
416432
*

workers/grouper/src/redisHelper.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ export default class RedisHelper {
4040
} catch (error) {
4141
console.error('Error creating redis client', error);
4242
}
43-
4443
}
4544

4645
/**

0 commit comments

Comments
 (0)