Verified Commit fe248571 authored by aguestuser's avatar aguestuser

[215][wip] add `recycleRepository.processRecycleRequests`

parent ef3f6d54
const defaults = {
recyclePhoneNumberInterval: 1000 * 15, // 30 secs
recycleGracePeriod: 1000 * 60 * 2, // 3 mins
recycleInterval: 1000 * 60 * 60, // 1 hr
recycleGracePeriod: 1000 * 60 * 60 * 24, // 1 day
inviteDeletionInterval: 1000 * 60 * 60, // 1 hour
inviteExpiryInMillis: 1000 * 60 * 60 * 24 * 14, // 2 weeks
hotlineMessageExpiryInMillis: 1000 * 60 * 60 * 24 * 28, // 4 weeks
}
const development = {
...defaults,
recycleInterval: 1000 * 5, // 5 secs
recycleGracePeriod: 1000 * 30, // 30 sec
}
const test = {
...defaults,
inviteDeletionInterval: 100, // 100 millis
......@@ -13,7 +19,7 @@ const test = {
}
module.exports = {
development: defaults,
development,
test,
production: defaults,
}
const { Op } = require('sequelize')
const moment = require('moment')
const app = require('../../../app')
const phoneNumberRegistrar = require('../../registrar/phoneNumber')
const { loggerOf } = require('../../util')
const { repeatEvery } = require('../../util')
const { mapInvoke } = require('lodash')
const {
job: { recycleInterval, recycleGracePeriod },
} = require('../../config')
const logger = loggerOf('repository.recycleRequest')
// (string) -> Promise<{ recycleRequest: RecycleRequest, wasCreated: boolean }>
const requestToRecycle = phoneNumber =>
......@@ -9,48 +20,38 @@ const requestToRecycle = phoneNumber =>
wasCreated,
}))
/**
* RECYCLING HELPER FUNCTIONS
*/
// const {
// job: { recyclePhoneNumberInterval, recycleGracePeriod },
// } = require('../../config')
//
// // (String) -> Promise
// const dequeue = channelPhoneNumber =>
// app.db.recycleRequest.destroy({ where: { channelPhoneNumber } })
//
// const recyclePhoneNumbers = async () => {
// const recycleablePhoneNumbers = await app.db.recycleRequest.findAll({})
// // get/await recycleablePhoneNumbers => messageCounts
// // find messageCount based on channelPhoneNumber
// // dequeue recycleableNumbers that were used within recycleDelay window
// recycleablePhoneNumbers
// .filter(usedRecently)
// .forEach(async ({ channelPhoneNumber }) => await dequeue(channelPhoneNumber))
//
// // recycle channel if enqueued before recycleDelay window
// recycleablePhoneNumbers.filter(enqueuedAwhileAgo).forEach(async ({ channelPhoneNumber }) => {
// await dequeue(channelPhoneNumber)
// await recycle(channelPhoneNumber)
// })
// }
//
// // (Object) -> boolean
// const enqueuedAwhileAgo = ({ createdAt }) => {
// // difference between now and grace period
// const recycleDelayWindow = moment().subtract(recycleGracePeriod)
// return moment(createdAt).diff(recycleDelayWindow) < 0
// }
//
// // (Object) -> boolean
// const usedRecently = async ({ channelPhoneNumber }) => {
// const channel = await channelRepository.findDeep(channelPhoneNumber)
//
// const lastUsed = moment(channel.messageCount.updatedAt)
// const recycleDelayWindow = moment().subtract(recycleGracePeriod)
// return lastUsed.diff(recycleDelayWindow) > 0
// }
module.exports = { requestToRecycle }
const processRecycleRequests = async () => {
// admins have a "grace period" of 1 day to use channels before they are recycled
const gracePeriodStart = moment().subtract(recycleGracePeriod, 'ms')
// find all the recycle requests issued over a day ago
const matureRequests = await app.db.recycleRequest.find({
where: {
createdAt: { [Op.lte]: gracePeriodStart },
},
})
// find all the channel phone numbers that haven't been used in the last day
const unredeemedChannelPhoneNumbers = mapInvoke(
await app.db.messageCount.find({
where: {
channelPhoneNumber: { [Op.in]: mapInvoke(matureRequests, 'phoneNumber') },
updatedAt: { [Op.lte]: gracePeriodStart },
},
}),
'channelPhoneNumber',
)
// recycle all the phone numbers that haven't been used during the 1-day grace period
await Promise.all(unredeemedChannelPhoneNumbers.map(phoneNumberRegistrar.recycle))
// destroy all mature requests (whose numbers have now either been recycled or redeemed)
return app.db.recycleRequest.destroy({
where: { phoneNumber: { [Op.in]: mapInvoke(matureRequests, 'phoneNumber') } },
})
}
const launchRecycleJob = () =>
repeatEvery(() => processRecycleRequests.catch(logger.error), recycleInterval)
module.exports = { requestToRecycle, processRecycleRequests, launchRecycleJob }
......@@ -4,7 +4,7 @@ const inviteRepository = require('./db/repositories/invite')
const smsSenderRepository = require('./db/repositories/smsSender')
const hotlineMessageRepository = require('./db/repositories/hotlineMessage')
const diagnostics = require('./diagnostics')
// const recycleRequestRepository = require('./db/repositories/recycleRequest')
const recycleRequestRepository = require('./db/repositories/recycleRequest')
const run = async () => {
logger.log('--- Running startup jobs...')
......@@ -29,9 +29,9 @@ const run = async () => {
inviteRepository.launchInviteDeletionJob()
logger.log('----- Launched data cleaning jobs.')
// logger.log('----- Launching job to check for recycleable numbers...')
// recycleRequestRepository.checkForRecycleablePhoneNumbers()
// logger.log('----- Launched recycleable numbers job')
logger.log('----- Launching job to check for recycleable numbers...')
recycleRequestRepository.launchRecycleJob()
logger.log('----- Launched recycleable numbers job')
logger.log('---- Launching healthcheck job...')
diagnostics.launchHealthcheckJob()
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment