Skip to content

Commit 94d143b

Browse files
committed
test: profile app to uncover memory issues
1 parent 6582d21 commit 94d143b

File tree

3 files changed

+28
-91
lines changed

3 files changed

+28
-91
lines changed

.circleci/config.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ workflows:
7171
only:
7272
- develop
7373
- fix/challenge-timelines-edit-routes
74+
- test/performance-profile
7475

7576
# Production builds are exectuted only on tagged commits to the
7677
# master branch.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"description": "TopCoder Challenges V5 API",
55
"main": "app.js",
66
"scripts": {
7-
"start": "node app.js",
7+
"start": "node --prof app.js",
88
"lint": "standard",
99
"lint:fix": "standard --fix",
1010
"init-es": "node src/init-es.js",

src/services/ChallengeService.js

Lines changed: 26 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -326,10 +326,10 @@ async function searchChallenges (currentUser, criteria) {
326326
boolQuery.push({ match_phrase: { 'legacy.useSchedulingAPI': criteria.useSchedulingAPI } })
327327
}
328328
if (criteria.selfService) {
329-
boolQuery.push({ match_phrase: { 'legacy.selfService': criteria.selfService}})
329+
boolQuery.push({ match_phrase: { 'legacy.selfService': criteria.selfService } })
330330
}
331331
if (criteria.selfServiceCopilot) {
332-
boolQuery.push({ match_phrase: { 'legacy.selfServiceCopilot': criteria.selfServiceCopilot}})
332+
boolQuery.push({ match_phrase: { 'legacy.selfServiceCopilot': criteria.selfServiceCopilot } })
333333
}
334334
if (criteria.forumId) {
335335
boolQuery.push({ match_phrase: { 'legacy.forumId': criteria.forumId } })
@@ -585,17 +585,17 @@ async function searchChallenges (currentUser, criteria) {
585585
must: [
586586
{ bool: { must_not: { match_phrase: { 'status': constants.challengeStatuses.New } } } },
587587
{ bool: { must_not: { match_phrase: { 'status': constants.challengeStatuses.Draft } } } },
588-
{ bool: { must_not: { match_phrase: { 'status': constants.challengeStatuses.Approved } } } },
588+
{ bool: { must_not: { match_phrase: { 'status': constants.challengeStatuses.Approved } } } }
589589
]
590590
}
591591
},
592-
{ bool: { must: { match_phrase: { 'createdBy': currentUser.handle } } } },
592+
{ bool: { must: { match_phrase: { 'createdBy': currentUser.handle } } } }
593593
] : [
594594
{
595595
bool: {
596596
should: [
597597
{ bool: { must: { match_phrase: { 'status': constants.challengeStatuses.Active } } } },
598-
{ bool: { must: { match_phrase: { 'status': constants.challengeStatuses.Completed } } } },
598+
{ bool: { must: { match_phrase: { 'status': constants.challengeStatuses.Completed } } } }
599599
]
600600
}
601601
}
@@ -935,19 +935,19 @@ async function populatePhases (phases, startDate, timelineTemplateId) {
935935
*/
936936
async function createChallenge (currentUser, challenge, userToken) {
937937
try {
938-
if(challenge.legacy.selfService) {
939-
if(!challenge.projectId) {
938+
if (challenge.legacy.selfService) {
939+
if (!challenge.projectId) {
940940
const selfServiceProjectName = `Self service - ${currentUser.handle} - ${challenge.name}`
941-
challenge.projectId = await helper.createSelfServiceProject(selfServiceProjectName, "N/A", config.NEW_SELF_SERVICE_PROJECT_TYPE, userToken)
941+
challenge.projectId = await helper.createSelfServiceProject(selfServiceProjectName, 'N/A', config.NEW_SELF_SERVICE_PROJECT_TYPE, userToken)
942942
}
943943
} else if (!challenge.projectId) {
944944
throw new errors.BadRequestError('The projectId is required')
945945
}
946946
} catch (e) {
947947
throw new errors.ServiceUnavailableError('Fail to create a self-service project')
948948
}
949-
if(challenge.legacy.selfService && challenge.metadata && challenge.metadata.length > 0) {
950-
for(const entry of challenge.metadata) {
949+
if (challenge.legacy.selfService && challenge.metadata && challenge.metadata.length > 0) {
950+
for (const entry of challenge.metadata) {
951951
if (challenge.description.includes(`{{${entry.name}}}`)) {
952952
challenge.description = challenge.description.split(`{{${entry.name}}}`).join(entry.value)
953953
}
@@ -1094,14 +1094,14 @@ async function createChallenge (currentUser, challenge, userToken) {
10941094
body: ret
10951095
})
10961096

1097-
//If the challenge is self-service, add the creating user as the "client manager", *not* the manager
1098-
//This is necessary for proper handling of the vanilla embed on the self-service work item dashboard
1099-
if(challenge.legacy.selfService) {
1100-
if (currentUser.handle) {
1101-
await helper.createResource(ret.id, ret.createdBy, config.CLIENT_MANAGER_ROLE_ID)
1102-
}
1103-
}
1104-
else{
1097+
// If the challenge is self-service, add the creating user as the "client manager", *not* the manager
1098+
// This is necessary for proper handling of the vanilla embed on the self-service work item dashboard
1099+
1100+
if (challenge.legacy.selfService) {
1101+
if (currentUser.handle) {
1102+
await helper.createResource(ret.id, ret.createdBy, config.CLIENT_MANAGER_ROLE_ID)
1103+
}
1104+
} else {
11051105
// if created by a user, add user as a manager, but only if *not* a self-service challenge
11061106
if (currentUser.handle) {
11071107
// logger.debug(`Adding user as manager ${currentUser.handle}`)
@@ -1325,25 +1325,6 @@ getChallengeStatistics.schema = {
13251325
id: Joi.id()
13261326
}
13271327

1328-
/**
1329-
* Check whether given two phases array are different.
1330-
* @param {Array} phases the first phases array
1331-
* @param {Array} otherPhases the second phases array
1332-
* @returns {Boolean} true if different, false otherwise
1333-
*/
1334-
function isDifferentPhases (phases = [], otherPhases) {
1335-
if (phases.length !== otherPhases.length) {
1336-
return true
1337-
} else {
1338-
for (let i = 0; i < phases.length; i++) {
1339-
if (!_.isEqual(phases[i], otherPhases[i])) {
1340-
return true
1341-
}
1342-
}
1343-
return false
1344-
}
1345-
}
1346-
13471328
/**
13481329
* Check whether given two PrizeSet Array are different.
13491330
* @param {Array} prizeSets the first PrizeSet Array
@@ -1372,13 +1353,13 @@ async function validateWinners (winners, challengeId) {
13721353
if (diffWinners.length + 1 !== filteredWinners.length) {
13731354
throw new errors.BadRequestError(`Duplicate member with placement: ${helper.toString(winner)}`)
13741355
}
1375-
1356+
13761357
// find another member with the placement
13771358
const placementExists = _.find(diffWinners, function (w) { return w.placement === winner.placement })
13781359
if (placementExists && (placementExists.userId !== winner.userId || placementExists.handle !== winner.handle)) {
13791360
throw new errors.BadRequestError(`Only one member can have a placement: ${winner.placement}`)
13801361
}
1381-
1362+
13821363
// find another placement for a member
13831364
const memberExists = _.find(diffWinners, function (w) { return w.userId === winner.userId && w.type === winner.type })
13841365
if (memberExists && memberExists.placement !== winner.placement) {
@@ -1388,49 +1369,6 @@ async function validateWinners (winners, challengeId) {
13881369
}
13891370
}
13901371

1391-
/**
1392-
* Get challenge statistics
1393-
* @param {Object} currentUser the user who perform operation
1394-
* @param {String} id the challenge id
1395-
* @returns {Object} the challenge with given id
1396-
*/
1397-
async function getChallengeStatistics (currentUser, id) {
1398-
const challenge = await getChallenge(currentUser, id)
1399-
// for now, only Data Science challenges are supported
1400-
if (challenge.type !== 'Challenge' && challenge.track !== 'Data Science') {
1401-
throw new errors.BadRequestError(`Challenge of type ${challenge.type} and track ${challenge.track} does not support statistics`)
1402-
}
1403-
// get submissions
1404-
const submissions = await helper.getChallengeSubmissions(challenge.id)
1405-
// for each submission, load member profile
1406-
const map = {}
1407-
for (const submission of submissions) {
1408-
if (!map[submission.memberId]) {
1409-
// Load member profile and cache
1410-
const member = await helper.getMemberById(submission.memberId)
1411-
map[submission.memberId] = {
1412-
photoUrl: member.photoURL,
1413-
rating: _.get(member, 'maxRating.rating', 0),
1414-
ratingColor: _.get(member, 'maxRating.ratingColor', '#9D9FA0'),
1415-
homeCountryCode: member.homeCountryCode,
1416-
handle: member.handle,
1417-
submissions: []
1418-
}
1419-
}
1420-
// add submission
1421-
map[submission.memberId].submissions.push({
1422-
created: submission.created,
1423-
score: _.get(_.find(submission.review || [], r => r.metadata), 'score', 0)
1424-
})
1425-
}
1426-
return _.map(_.keys(map), (userId) => map[userId])
1427-
}
1428-
1429-
getChallengeStatistics.schema = {
1430-
currentUser: Joi.any(),
1431-
id: Joi.id()
1432-
}
1433-
14341372
/**
14351373
* Update challenge.
14361374
* @param {Object} currentUser the user who perform operation
@@ -1459,8 +1397,8 @@ async function update (currentUser, challengeId, data, isFull) {
14591397

14601398
const challenge = await helper.getById('Challenge', challengeId)
14611399
let dynamicDescription = _.cloneDeep(data.description || challenge.description)
1462-
if(challenge.legacy.selfService && data.metadata && data.metadata.length > 0) {
1463-
for(const entry of data.metadata) {
1400+
if (challenge.legacy.selfService && data.metadata && data.metadata.length > 0) {
1401+
for (const entry of data.metadata) {
14641402
const regexp = new RegExp(`{{${entry.name}}}`, 'g')
14651403
dynamicDescription = dynamicDescription.replace(regexp, entry.value)
14661404
}
@@ -1476,7 +1414,7 @@ async function update (currentUser, challengeId, data, isFull) {
14761414
const workItemSummary = _.get(_.find(_.get(challenge, 'metadata', []), m => m.name === 'websitePurpose.description'), 'value', 'N/A')
14771415
await helper.activateProject(challenge.projectId, currentUser, selfServiceProjectName, workItemSummary)
14781416
if (data.status === constants.challengeStatuses.Active) {
1479-
sendActivationEmail = true
1417+
sendActivationEmail = true
14801418
}
14811419
} catch (e) {
14821420
await update(
@@ -1682,7 +1620,6 @@ async function update (currentUser, challengeId, data, isFull) {
16821620
data.endDate = helper.calculateChallengeEndDate(challenge, data)
16831621
}
16841622

1685-
16861623
// PUT HERE
16871624
if (data.status) {
16881625
if (challenge.legacy.selfService && data.status === constants.challengeStatuses.Draft) {
@@ -1952,7 +1889,7 @@ async function update (currentUser, challengeId, data, isFull) {
19521889
// post bus event
19531890
logger.debug(`Post Bus Event: ${constants.Topics.ChallengeUpdated} ${JSON.stringify(challenge)}`)
19541891
const options = {}
1955-
if (challenge.status == 'Completed') {
1892+
if (challenge.status === 'Completed') {
19561893
options.key = `${challenge.id}:${challenge.status}`
19571894
}
19581895
await helper.postBusEvent(constants.Topics.ChallengeUpdated, challenge, options)
@@ -2173,7 +2110,7 @@ fullyUpdateChallenge.schema = {
21732110
pureV5Task: Joi.boolean(),
21742111
pureV5: Joi.boolean(),
21752112
selfService: Joi.boolean(),
2176-
selfServiceCopilot: Joi.string().allow(null),
2113+
selfServiceCopilot: Joi.string().allow(null)
21772114
}).unknown(true),
21782115
cancelReason: Joi.string(),
21792116
billing: Joi.object().keys({
@@ -2398,8 +2335,7 @@ module.exports = {
23982335
partiallyUpdateChallenge,
23992336
deleteChallenge,
24002337
getChallengeStatistics,
2401-
sendNotifications,
2402-
getChallengeStatistics
2338+
sendNotifications
24032339
}
24042340

24052341
logger.buildService(module.exports)

0 commit comments

Comments
 (0)