Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | 3x 3x 3x 3x 3x 3x 3x 3x 3x 26x 26x 7x 7x 3x 3x 3x 3x 1x 1x 1x 1x 3x 4x 4x 1x 1x 3x 3x 3x 3x 3x 2x 1x 1x 3x 3x 3x | import { Inject, Injectable, InternalServerErrorException, Logger, ServiceUnavailableException, forwardRef, } from '@nestjs/common' import { Cron } from '@nestjs/schedule' import { ObjectId } from 'mongoose' import { MailData, MailEvent } from '../../db/entities/mail-event.entity' import { MailEventDBService } from '../../db/services/mail-event.service' import { MailSendService } from './send.service' /** * @description Service reliable for scheduling the sending of emails */ @Injectable() export class MailScheduleService { private readonly logger = new Logger(MailScheduleService.name) constructor( @Inject(forwardRef(() => MailSendService)) private readonly mailSendService: MailSendService, private readonly mailEventService: MailEventDBService, ) {} async scheduleMailNow(mail: MailData): Promise<void> { try { await this.mailSendService.sendMail(mail) } catch (error) { this.logger.error( `Encountered error while trying to send email: ${error}`, ) throw new ServiceUnavailableException( 'We are experiencing issues within our backend, please try again later', ) } } async scheduleMailAtDate(scheduleDate: Date, mail: MailData): Promise<void> { const mailEvent: Partial<MailEvent> = { scheduledAt: scheduleDate, hasBeenSent: false, hasBeenRescheduled: false, content: mail, } try { await this.mailEventService.createEvent(mailEvent) } catch (error) /* istanbul ignore next */ { this.logger.warn(`MailEvent could not be inserted into the database`) throw new InternalServerErrorException('Mailevent could not be scheduled') } } private async rescheduleMails( ids: ObjectId[], newSendDate?: Date, ): Promise<void> { if (ids.length == 0) return if (!newSendDate) { newSendDate = new Date() // Reschedule 5 hours later by default newSendDate.setHours(newSendDate.getHours() + 5) } await this.mailEventService.rescheduleMails(ids, newSendDate) } // Run every hour @Cron('0 * * * *') async sendScheduledMails(): Promise<void> { const mails = await this.mailEventService.getOpenEventsBefore(new Date()) if (mails.length == 0) { this.logger.log(`No scheduled mails for cron`) return } // TODO: This lacks error handling const successIds: ObjectId[] = [] const failureIds: ObjectId[] = [] for (const mail of mails) { try { await this.mailSendService.sendMail(mail.content) successIds.push(mail._id) } catch (error) { this.logger.warn( `Could not send scheduled mail due to an error ${error}`, ) failureIds.push(mail._id) } } this.logger.log( `Send ${successIds.length} scheduled mails, failed to send ${failureIds.length}`, ) await this.mailEventService.markMailsAsSend(successIds) await this.rescheduleMails(failureIds) } } |