Skip to content

Commit 6eccb50

Browse files
authored
Merge pull request #319 from xxcxy/feature/payment-scheduler
use payment scheduler step identifiers
2 parents 98d9b05 + 2118902 commit 6eccb50

File tree

5 files changed

+62
-48
lines changed

5 files changed

+62
-48
lines changed

app-constants.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,22 @@ const PaymentProcessingSwitch = {
9797
OFF: 'OFF'
9898
}
9999

100+
const PaymentSchedulerStatus = {
101+
START_PROCESS: 'start-process',
102+
CREATE_CHALLENGE: 'create-challenge',
103+
ASSIGN_MEMBER: 'assign-member',
104+
ACTIVATE_CHALLENGE: 'activate-challenge',
105+
GET_USER_ID: 'get-userId',
106+
CLOSE_CHALLENGE: 'close-challenge'
107+
}
108+
100109
module.exports = {
101110
UserRoles,
102111
FullManagePermissionRoles,
103112
Scopes,
104113
Interviews,
105114
ChallengeStatus,
106115
WorkPeriodPaymentStatus,
116+
PaymentSchedulerStatus,
107117
PaymentProcessingSwitch
108118
}

config/default.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -202,11 +202,11 @@ module.exports = {
202202
PER_MINUTE_RESOURCE_REQUEST_MAX_COUNT: parseInt(process.env.PAYMENT_PROCESSING_PER_MINUTE_CHALLENGE_REQUEST_MAX_COUNT || 20),
203203
// the default step fix delay, unit: ms
204204
FIX_DELAY_STEP: parseInt(process.env.PAYMENT_PROCESSING_FIX_DELAY_STEP || 500),
205-
// the fix delay between step one and step two, unit: ms
206-
FIX_DELAY_STEP_1_2: parseInt(process.env.PAYMENT_PROCESSING_FIX_DELAY_STEP_1_2 || process.env.PAYMENT_PROCESSING_FIX_DELAY_STEP || 500),
207-
// the fix delay between step two and step three, unit: ms
208-
FIX_DELAY_STEP_2_3: parseInt(process.env.PAYMENT_PROCESSING_FIX_DELAY_STEP_2_3 || process.env.PAYMENT_PROCESSING_FIX_DELAY_STEP || 500),
209-
// the fix delay between step three and step four, unit: ms
210-
FIX_DELAY_STEP_3_4: parseInt(process.env.PAYMENT_PROCESSING_FIX_DELAY_STEP_3_4 || process.env.PAYMENT_PROCESSING_FIX_DELAY_STEP || 500)
205+
// the fix delay after step of create challenge, unit: ms
206+
FIX_DELAY_STEP_CREATE_CHALLENGE: parseInt(process.env.PAYMENT_PROCESSING_FIX_DELAY_STEP_CREATE_CHALLENGE || process.env.PAYMENT_PROCESSING_FIX_DELAY_STEP || 500),
207+
// the fix delay after step of assign member, unit: ms
208+
FIX_DELAY_STEP_ASSIGN_MEMBER: parseInt(process.env.PAYMENT_PROCESSING_FIX_DELAY_STEP_ASSIGN_MEMBER || process.env.PAYMENT_PROCESSING_FIX_DELAY_STEP || 500),
209+
// the fix delay after step of activate challenge, unit: ms
210+
FIX_DELAY_STEP_ACTIVATE_CHALLENGE: parseInt(process.env.PAYMENT_PROCESSING_FIX_DELAY_STEP_ACTIVATE_CHALLENGE || process.env.PAYMENT_PROCESSING_FIX_DELAY_STEP || 500)
211211
}
212212
}

migrations/2021-05-29-create-payment-scheduler-table-add-status-details-to-payment.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
const config = require('config')
44
const _ = require('lodash')
5+
const { PaymentSchedulerStatus } = require('../app-constants')
56

67
/**
78
* Create `payment_schedulers` table & relations.
@@ -35,7 +36,7 @@ module.exports = {
3536
}
3637
},
3738
step: {
38-
type: Sequelize.INTEGER,
39+
type: Sequelize.ENUM(_.values(PaymentSchedulerStatus)),
3940
allowNull: false
4041
},
4142
status: {
@@ -87,11 +88,13 @@ module.exports = {
8788
down: async (queryInterface, Sequelize) => {
8889
const table = { schema: config.DB_SCHEMA_NAME, tableName: 'payment_schedulers' }
8990
const statusTypeName = `${table.schema}.enum_${table.tableName}_status`
91+
const stepTypeName = `${table.schema}.enum_${table.tableName}_step`
9092
const transaction = await queryInterface.sequelize.transaction()
9193
try {
9294
await queryInterface.dropTable(table, { transaction })
93-
// drop enum type for status column
95+
// drop enum type for status and step column
9496
await queryInterface.sequelize.query(`DROP TYPE ${statusTypeName}`, { transaction })
97+
await queryInterface.sequelize.query(`DROP TYPE ${stepTypeName}`, { transaction })
9598

9699
await queryInterface.changeColumn({ tableName: 'work_period_payments', schema: config.DB_SCHEMA_NAME }, 'challenge_id',
97100
{ type: Sequelize.UUID, allowNull: false },

src/models/PaymentScheduler.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
const { Sequelize, Model } = require('sequelize')
22
const config = require('config')
3+
const _ = require('lodash')
34
const errors = require('../common/errors')
5+
const { PaymentSchedulerStatus } = require('../../app-constants')
46

57
module.exports = (sequelize) => {
68
class PaymentScheduler extends Model {
@@ -48,7 +50,7 @@ module.exports = (sequelize) => {
4850
allowNull: false
4951
},
5052
step: {
51-
type: Sequelize.INTEGER,
53+
type: Sequelize.ENUM(_.values(PaymentSchedulerStatus)),
5254
allowNull: false
5355
},
5456
status: {

src/services/PaymentSchedulerService.js

Lines changed: 38 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ const models = require('../models')
55
const { getV3MemberDetailsByHandle, getChallenge, getChallengeResource, sleep, postEvent } = require('../common/helper')
66
const logger = require('../common/logger')
77
const { createChallenge, addResourceToChallenge, activateChallenge, closeChallenge } = require('./PaymentService')
8-
const { ChallengeStatus, PaymentProcessingSwitch } = require('../../app-constants')
8+
const { ChallengeStatus, PaymentSchedulerStatus, PaymentProcessingSwitch } = require('../../app-constants')
99

1010
const WorkPeriodPayment = models.WorkPeriodPayment
1111
const WorkPeriod = models.WorkPeriod
1212
const PaymentScheduler = models.PaymentScheduler
1313
const {
1414
SWITCH, BATCH_SIZE, IN_PROGRESS_EXPIRED, MAX_RETRY_COUNT, RETRY_BASE_DELAY, RETRY_MAX_DELAY, PER_REQUEST_MAX_TIME, PER_PAYMENT_MAX_TIME,
1515
PER_MINUTE_PAYMENT_MAX_COUNT, PER_MINUTE_CHALLENGE_REQUEST_MAX_COUNT, PER_MINUTE_RESOURCE_REQUEST_MAX_COUNT,
16-
FIX_DELAY_STEP_1_2, FIX_DELAY_STEP_2_3, FIX_DELAY_STEP_3_4
16+
FIX_DELAY_STEP_CREATE_CHALLENGE, FIX_DELAY_STEP_ASSIGN_MEMBER, FIX_DELAY_STEP_ACTIVATE_CHALLENGE
1717
} = config.PAYMENT_PROCESSING
1818
const processStatus = {
1919
perMin: {
@@ -30,7 +30,6 @@ const processStatus = {
3030
paymentStartTime: 0,
3131
requestStartTime: 0
3232
}
33-
const stepEnum = ['start-process', 'create-challenge', 'assign-member', 'activate-challenge', 'get-userId', 'close-challenge']
3433
const processResult = {
3534
SUCCESS: 'success',
3635
FAIL: 'fail',
@@ -94,21 +93,21 @@ async function processPayment (workPeriodPayment) {
9493
await postEvent(config.TAAS_WORK_PERIOD_PAYMENT_UPDATE_TOPIC, updated.toJSON(), { oldValue })
9594
}
9695
// Check whether the number of processed records per minute exceeds the specified number, if it exceeds, wait for the next minute before processing
97-
await checkWait(stepEnum[0])
96+
await checkWait(PaymentSchedulerStatus.START_PROCESS)
9897
localLogger.info(`Processing workPeriodPayment ${workPeriodPayment.id}`, 'processPayment')
9998

10099
const workPeriod = await WorkPeriod.findById(workPeriodPayment.workPeriodId)
101100
try {
102101
if (!paymentScheduler) {
103102
// 1. create challenge
104-
const challengeId = await withRetry(createChallenge, [getCreateChallengeParam(workPeriod, workPeriodPayment)], validateError, stepEnum[1])
105-
paymentScheduler = await PaymentScheduler.create({ challengeId, step: 1, workPeriodPaymentId: workPeriodPayment.id, userHandle: workPeriod.userHandle, status: 'in-progress' })
103+
const challengeId = await withRetry(createChallenge, [getCreateChallengeParam(workPeriod, workPeriodPayment)], validateError, PaymentSchedulerStatus.CREATE_CHALLENGE)
104+
paymentScheduler = await PaymentScheduler.create({ challengeId, step: PaymentSchedulerStatus.CREATE_CHALLENGE, workPeriodPaymentId: workPeriodPayment.id, userHandle: workPeriod.userHandle, status: 'in-progress' })
106105
} else {
107106
// If the paymentScheduler already exists, it means that this is a record caused by an abnormal shutdown
108107
await setPaymentSchedulerStep(paymentScheduler)
109108
}
110109
// Start from unprocessed step, perform the process step by step
111-
while (paymentScheduler.step < 5) {
110+
while (paymentScheduler.step !== PaymentSchedulerStatus.CLOSE_CHALLENGE) {
112111
await processStep(paymentScheduler)
113112
}
114113

@@ -118,7 +117,7 @@ async function processPayment (workPeriodPayment) {
118117
// Update the modified status to es
119118
await postEvent(config.TAAS_WORK_PERIOD_PAYMENT_UPDATE_TOPIC, updated.toJSON(), { oldValue })
120119

121-
await paymentScheduler.update({ step: 5, userId: paymentScheduler.userId, status: 'completed' })
120+
await paymentScheduler.update({ step: PaymentSchedulerStatus.CLOSE_CHALLENGE, userId: paymentScheduler.userId, status: 'completed' })
122121

123122
localLogger.info(`Processed workPeriodPayment ${workPeriodPayment.id} successfully`, 'processPayment')
124123
return processResult.SUCCESS
@@ -132,7 +131,7 @@ async function processPayment (workPeriodPayment) {
132131
await postEvent(config.TAAS_WORK_PERIOD_PAYMENT_UPDATE_TOPIC, updated.toJSON(), { oldValue })
133132

134133
if (paymentScheduler) {
135-
await paymentScheduler.update({ step: 5, userId: paymentScheduler.userId, status: 'failed' })
134+
await paymentScheduler.update({ step: PaymentSchedulerStatus.CLOSE_CHALLENGE, userId: paymentScheduler.userId, status: 'failed' })
136135
}
137136
localLogger.error(`Processed workPeriodPayment ${workPeriodPayment.id} failed`, 'processPayment')
138137
return processResult.FAIL
@@ -144,23 +143,23 @@ async function processPayment (workPeriodPayment) {
144143
* @param {Object} paymentScheduler the payment scheduler
145144
*/
146145
async function processStep (paymentScheduler) {
147-
if (paymentScheduler.step === 1) {
146+
if (paymentScheduler.step === PaymentSchedulerStatus.CREATE_CHALLENGE) {
148147
// 2. assign member to the challenge
149-
await withRetry(addResourceToChallenge, [paymentScheduler.challengeId, paymentScheduler.userHandle], validateError, stepEnum[2])
150-
paymentScheduler.step = 2
151-
} else if (paymentScheduler.step === 2) {
148+
await withRetry(addResourceToChallenge, [paymentScheduler.challengeId, paymentScheduler.userHandle], validateError, PaymentSchedulerStatus.ASSIGN_MEMBER)
149+
paymentScheduler.step = PaymentSchedulerStatus.ASSIGN_MEMBER
150+
} else if (paymentScheduler.step === PaymentSchedulerStatus.ASSIGN_MEMBER) {
152151
// 3. active the challenge
153-
await withRetry(activateChallenge, [paymentScheduler.challengeId], validateError, stepEnum[3])
154-
paymentScheduler.step = 3
155-
} else if (paymentScheduler.step === 3) {
152+
await withRetry(activateChallenge, [paymentScheduler.challengeId], validateError, PaymentSchedulerStatus.ACTIVATE_CHALLENGE)
153+
paymentScheduler.step = PaymentSchedulerStatus.ACTIVATE_CHALLENGE
154+
} else if (paymentScheduler.step === PaymentSchedulerStatus.ACTIVATE_CHALLENGE) {
156155
// 4.1. get user id
157-
const { userId } = await withRetry(getV3MemberDetailsByHandle, [paymentScheduler.userHandle], validateError, stepEnum[4])
156+
const { userId } = await withRetry(getV3MemberDetailsByHandle, [paymentScheduler.userHandle], validateError, PaymentSchedulerStatus.GET_USER_ID)
158157
paymentScheduler.userId = userId
159-
paymentScheduler.step = 4
160-
} else if (paymentScheduler.step === 4) {
158+
paymentScheduler.step = PaymentSchedulerStatus.GET_USER_ID
159+
} else if (paymentScheduler.step === PaymentSchedulerStatus.GET_USER_ID) {
161160
// 4.2. close the challenge
162-
await withRetry(closeChallenge, [paymentScheduler.challengeId, paymentScheduler.userId, paymentScheduler.userHandle], validateError, stepEnum[5])
163-
paymentScheduler.step = 5
161+
await withRetry(closeChallenge, [paymentScheduler.challengeId, paymentScheduler.userId, paymentScheduler.userHandle], validateError, PaymentSchedulerStatus.CLOSE_CHALLENGE)
162+
paymentScheduler.step = PaymentSchedulerStatus.CLOSE_CHALLENGE
164163
}
165164
}
166165

@@ -171,17 +170,17 @@ async function processStep (paymentScheduler) {
171170
async function setPaymentSchedulerStep (paymentScheduler) {
172171
const challenge = await getChallenge(paymentScheduler.challengeId)
173172
if (SWITCH === PaymentProcessingSwitch.OFF) {
174-
paymentScheduler.step = 5
173+
paymentScheduler.step = PaymentSchedulerStatus.CLOSE_CHALLENGE
175174
} else if (challenge.status === ChallengeStatus.COMPLETED) {
176-
paymentScheduler.step = 5
175+
paymentScheduler.step = PaymentSchedulerStatus.CLOSE_CHALLENGE
177176
} else if (challenge.status === ChallengeStatus.ACTIVE) {
178-
paymentScheduler.step = 3
177+
paymentScheduler.step = PaymentSchedulerStatus.ACTIVATE_CHALLENGE
179178
} else {
180179
const resource = await getChallengeResource(paymentScheduler.challengeId, paymentScheduler.userHandle, config.ROLE_ID_SUBMITTER)
181180
if (resource) {
182-
paymentScheduler.step = 2
181+
paymentScheduler.step = PaymentSchedulerStatus.ASSIGN_MEMBER
183182
} else {
184-
paymentScheduler.step = 1
183+
paymentScheduler.step = PaymentSchedulerStatus.CREATE_CHALLENGE
185184
}
186185
}
187186
// The main purpose is updating the updatedAt of payment scheduler to avoid simultaneous processing
@@ -213,26 +212,26 @@ function getCreateChallengeParam (workPeriod, workPeriodPayment) {
213212
async function checkWait (step, tryCount) {
214213
// When calculating the retry time later, we need to subtract the time that has been waited before
215214
let lapse = 0
216-
if (step === stepEnum[0]) {
215+
if (step === PaymentSchedulerStatus.START_PROCESS) {
217216
lapse += await checkPerMinThreshold('paymentsProcessed')
218-
} else if (step === stepEnum[1]) {
217+
} else if (step === PaymentSchedulerStatus.CREATE_CHALLENGE) {
219218
await checkPerMinThreshold('challengeRequested')
220-
} else if (step === stepEnum[2]) {
219+
} else if (step === PaymentSchedulerStatus.ASSIGN_MEMBER) {
221220
// Only when tryCount = 0, it comes from the previous step, and it is necessary to wait for a fixed time
222-
if (FIX_DELAY_STEP_1_2 > 0 && tryCount === 0) {
223-
await sleep(FIX_DELAY_STEP_1_2)
221+
if (FIX_DELAY_STEP_CREATE_CHALLENGE > 0 && tryCount === 0) {
222+
await sleep(FIX_DELAY_STEP_CREATE_CHALLENGE)
224223
}
225224
lapse += await checkPerMinThreshold('resourceRequested')
226-
} else if (step === stepEnum[3]) {
225+
} else if (step === PaymentSchedulerStatus.ACTIVATE_CHALLENGE) {
227226
// Only when tryCount = 0, it comes from the previous step, and it is necessary to wait for a fixed time
228-
if (FIX_DELAY_STEP_2_3 > 0 && tryCount === 0) {
229-
await sleep(FIX_DELAY_STEP_2_3)
227+
if (FIX_DELAY_STEP_ASSIGN_MEMBER > 0 && tryCount === 0) {
228+
await sleep(FIX_DELAY_STEP_ASSIGN_MEMBER)
230229
}
231230
lapse += await checkPerMinThreshold('challengeRequested')
232-
} else if (step === stepEnum[5]) {
231+
} else if (step === PaymentSchedulerStatus.CLOSE_CHALLENGE) {
233232
// Only when tryCount = 0, it comes from the previous step, and it is necessary to wait for a fixed time
234-
if (FIX_DELAY_STEP_3_4 > 0 && tryCount === 0) {
235-
await sleep(FIX_DELAY_STEP_3_4)
233+
if (FIX_DELAY_STEP_ACTIVATE_CHALLENGE > 0 && tryCount === 0) {
234+
await sleep(FIX_DELAY_STEP_ACTIVATE_CHALLENGE)
236235
}
237236
lapse += await checkPerMinThreshold('challengeRequested')
238237
}
@@ -305,9 +304,9 @@ async function withRetry (func, argArr, predictFunc, step) {
305304
if (SWITCH === PaymentProcessingSwitch.OFF) {
306305
// without actual API calls by adding delay (for example 1 second for each step), to simulate the act
307306
sleep(1000)
308-
if (step === stepEnum[1]) {
307+
if (step === PaymentSchedulerStatus.CREATE_CHALLENGE) {
309308
return '00000000-0000-0000-0000-000000000000'
310-
} else if (step === stepEnum[4]) {
309+
} else if (step === PaymentSchedulerStatus.GET_USER_ID) {
311310
return { userId: 100001 }
312311
}
313312
return

0 commit comments

Comments
 (0)