5 changed files with 153 additions and 5 deletions
-
3api/src/gateway/gateway.module.ts
-
4api/src/gateway/gateway.service.ts
-
6api/src/gateway/schemas/sms.schema.ts
-
77api/src/gateway/tasks/sms-status-update.task.spec.ts
-
68api/src/gateway/tasks/sms-status-update.task.ts
@ -0,0 +1,77 @@ |
|||
import { Test, TestingModule } from '@nestjs/testing'; |
|||
import { getModelToken } from '@nestjs/mongoose'; |
|||
import { SmsStatusUpdateTask } from './sms-status-update.task'; |
|||
import { SMS } from '../schemas/sms.schema'; |
|||
import { SMSBatch } from '../schemas/sms-batch.schema'; |
|||
import { Model } from 'mongoose'; |
|||
|
|||
describe('SmsStatusUpdateTask', () => { |
|||
let task: SmsStatusUpdateTask; |
|||
let smsModel: Model<SMS>; |
|||
let smsBatchModel: Model<SMSBatch>; |
|||
|
|||
beforeEach(async () => { |
|||
const module: TestingModule = await Test.createTestingModule({ |
|||
providers: [ |
|||
SmsStatusUpdateTask, |
|||
{ |
|||
provide: getModelToken(SMS.name), |
|||
useValue: { |
|||
updateMany: jest.fn().mockResolvedValue({ modifiedCount: 5 }), |
|||
}, |
|||
}, |
|||
{ |
|||
provide: getModelToken(SMSBatch.name), |
|||
useValue: { |
|||
updateMany: jest.fn().mockResolvedValue({ modifiedCount: 2 }), |
|||
}, |
|||
}, |
|||
], |
|||
}).compile(); |
|||
|
|||
task = module.get<SmsStatusUpdateTask>(SmsStatusUpdateTask); |
|||
smsModel = module.get<Model<SMS>>(getModelToken(SMS.name)); |
|||
smsBatchModel = module.get<Model<SMSBatch>>(getModelToken(SMSBatch.name)); |
|||
}); |
|||
|
|||
it('should be defined', () => { |
|||
expect(task).toBeDefined(); |
|||
}); |
|||
|
|||
describe('handlePendingSmsTimeout', () => { |
|||
it('should update stale pending SMS messages to unknown status', async () => { |
|||
jest.spyOn(smsModel, 'updateMany'); |
|||
jest.spyOn(smsBatchModel, 'updateMany'); |
|||
|
|||
await task.handlePendingSmsTimeout(); |
|||
|
|||
// Check that SMS model was updated with correct query
|
|||
expect(smsModel.updateMany).toHaveBeenCalledWith( |
|||
expect.objectContaining({ |
|||
status: 'pending', |
|||
requestedAt: expect.any(Object), |
|||
}), |
|||
{ |
|||
$set: { |
|||
status: 'unknown', |
|||
errorMessage: 'Status update timeout - no response received after 20 minutes', |
|||
}, |
|||
}, |
|||
); |
|||
|
|||
// Check that SMSBatch model was updated with correct query
|
|||
expect(smsBatchModel.updateMany).toHaveBeenCalledWith( |
|||
expect.objectContaining({ |
|||
status: 'pending', |
|||
createdAt: expect.any(Object), |
|||
}), |
|||
{ |
|||
$set: { |
|||
status: 'unknown', |
|||
error: 'Status update timeout - no response received after 20 minutes', |
|||
}, |
|||
}, |
|||
); |
|||
}); |
|||
}); |
|||
}); |
|||
@ -0,0 +1,68 @@ |
|||
import { Injectable, Logger } from '@nestjs/common'; |
|||
import { Cron, CronExpression } from '@nestjs/schedule'; |
|||
import { InjectModel } from '@nestjs/mongoose'; |
|||
import { Model } from 'mongoose'; |
|||
import { SMS } from '../schemas/sms.schema'; |
|||
import { SMSBatch } from '../schemas/sms-batch.schema'; |
|||
|
|||
|
|||
@Injectable() |
|||
export class SmsStatusUpdateTask { |
|||
private readonly logger = new Logger(SmsStatusUpdateTask.name); |
|||
|
|||
constructor( |
|||
@InjectModel(SMS.name) private smsModel: Model<SMS>, |
|||
@InjectModel(SMSBatch.name) private smsBatchModel: Model<SMSBatch>, |
|||
) {} |
|||
|
|||
/** |
|||
* Cron job that runs every 5 minutes to update the status of SMS messages |
|||
* that have been pending for more than 20 minutes without any status updates. |
|||
*/ |
|||
@Cron(CronExpression.EVERY_5_MINUTES) |
|||
async handlePendingSmsTimeout() { |
|||
this.logger.log('Running cron job to update stale pending SMS messages'); |
|||
|
|||
const twentyMinutesAgo = new Date(); |
|||
twentyMinutesAgo.setMinutes(twentyMinutesAgo.getMinutes() - 20); |
|||
|
|||
try { |
|||
|
|||
const result = await this.smsModel.updateMany( |
|||
{ |
|||
status: 'pending', |
|||
requestedAt: { $lt: twentyMinutesAgo }, |
|||
}, |
|||
{ |
|||
$set: { |
|||
status: 'unknown', |
|||
errorMessage: 'Status update timeout - no response received after 20 minutes' |
|||
} |
|||
} |
|||
); |
|||
|
|||
|
|||
|
|||
this.logger.log(`Updated ${result.modifiedCount} SMS messages from 'pending' to 'unknown' status`); |
|||
|
|||
const batchResult = await this.smsBatchModel.updateMany( |
|||
{ |
|||
status: 'pending', |
|||
createdAt: { $lt: twentyMinutesAgo } |
|||
}, |
|||
{ |
|||
$set: { |
|||
status: 'unknown', |
|||
error: 'Status update timeout - no response received after 20 minutes' |
|||
} |
|||
} |
|||
); |
|||
|
|||
|
|||
|
|||
this.logger.log(`Updated ${batchResult.modifiedCount} SMS batches from 'pending' to 'unknown' status`); |
|||
} catch (error) { |
|||
this.logger.error('Error updating stale pending SMS messages', error); |
|||
} |
|||
} |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue