diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index f323f383..76e0d348 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -44,9 +44,9 @@ jobs: - name: Execute Detekt run: | cd backend - ./gradlew detekt + ./gradlew detekt --info - name: Execute Unit tests run: | cd backend - ./gradlew test + ./gradlew test --info diff --git a/backend/src/main/kotlin/blue/mild/covid/vaxx/dto/internal/PatientEmailRequestDto.kt b/backend/src/main/kotlin/blue/mild/covid/vaxx/dto/internal/PatientEmailRequestDto.kt index 8f47ed56..efbe6de1 100644 --- a/backend/src/main/kotlin/blue/mild/covid/vaxx/dto/internal/PatientEmailRequestDto.kt +++ b/backend/src/main/kotlin/blue/mild/covid/vaxx/dto/internal/PatientEmailRequestDto.kt @@ -4,11 +4,13 @@ import blue.mild.covid.vaxx.dao.model.EntityId import blue.mild.covid.vaxx.dto.response.LocationDtoOut import blue.mild.covid.vaxx.dto.response.VaccinationSlotDtoOut +@Suppress("MagicNumber") data class PatientEmailRequestDto( val firstName: String, val lastName: String, val email: String, val patientId: EntityId, val slot: VaccinationSlotDtoOut, - val location: LocationDtoOut + val location: LocationDtoOut, + val attemptLeft: Int = 10 ) diff --git a/backend/src/main/kotlin/blue/mild/covid/vaxx/routes/PatientRoutes.kt b/backend/src/main/kotlin/blue/mild/covid/vaxx/routes/PatientRoutes.kt index 890856cd..a6327438 100644 --- a/backend/src/main/kotlin/blue/mild/covid/vaxx/routes/PatientRoutes.kt +++ b/backend/src/main/kotlin/blue/mild/covid/vaxx/routes/PatientRoutes.kt @@ -98,7 +98,7 @@ fun NormalOpenAPIRoute.patientRoutes() { val location = locationService.getLocationById(slot.locationId) logger.info { "Slot booked: ${slot.id} for patient $patientId - registration completed." } - logger.debug { "Adding email to the queue." } + emailService.sendEmail( PatientEmailRequestDto( firstName = patientRegistration.firstName, diff --git a/backend/src/main/kotlin/blue/mild/covid/vaxx/service/DispatchService.kt b/backend/src/main/kotlin/blue/mild/covid/vaxx/service/DispatchService.kt index 225f878a..b41f7bfb 100644 --- a/backend/src/main/kotlin/blue/mild/covid/vaxx/service/DispatchService.kt +++ b/backend/src/main/kotlin/blue/mild/covid/vaxx/service/DispatchService.kt @@ -29,8 +29,12 @@ abstract class DispatchService(private val nThreads: Int) { // create a single coroutine, that will handle all emails GlobalScope.launch(dispatcher) { while (true) { - val work = channel.receive() - dispatch(work) + runCatching { + val work = channel.receive() + dispatch(work) + }.onFailure { + logger.error(it) { "An exception during work dispatch!" } + } } } } diff --git a/backend/src/main/kotlin/blue/mild/covid/vaxx/service/MailJetEmailService.kt b/backend/src/main/kotlin/blue/mild/covid/vaxx/service/MailJetEmailService.kt index 407ca6c3..374daaaf 100644 --- a/backend/src/main/kotlin/blue/mild/covid/vaxx/service/MailJetEmailService.kt +++ b/backend/src/main/kotlin/blue/mild/covid/vaxx/service/MailJetEmailService.kt @@ -13,6 +13,7 @@ import org.jetbrains.exposed.sql.update import org.json.JSONArray import org.json.JSONObject import pw.forst.katlib.TimeProvider +import pw.forst.katlib.whenNull import java.io.StringWriter import java.time.Instant import freemarker.template.Configuration as FreemarkerConfiguration @@ -46,25 +47,37 @@ class MailJetEmailService( sendMailBlocking(work) } - private fun sendMailBlocking(emailRequest: PatientEmailRequestDto) { - logger.debug { "Sending an email to ${emailRequest.email}." } + private suspend fun sendMailBlocking(emailRequest: PatientEmailRequestDto) { + if (emailRequest.attemptLeft == 0) { + logger.error { "Not executing email request \"$emailRequest\" - attempts left 0!" } + } - val response = client.post(buildEmailRequest(emailRequest)) + logger.info { "Sending an email to ${emailRequest.email}." } - if (response.status != SUCCESS) { - // TODO consider putting it back to the channel for retry - logger.error { "Sending email to ${emailRequest.email} was not successful details: ${response.data}." } - } else { - logger.debug { "Email to ${emailRequest.email} sent successfully." } - // save information about email sent to the database - // we want to keep this transaction on this thread, so we don't suspend it - transaction { - Patients.update({ Patients.id eq emailRequest.patientId }) { - it[registrationEmailSent] = nowProvider.now() + runCatching { client.post(buildEmailRequest(emailRequest)) } + .onFailure { + // TODO maybe put that back to the queue + logger.error(it) { "Sending email to ${emailRequest.email} has thrown an exception." } + }.getOrNull() + ?.also { + if (it.status != SUCCESS) { + logger.error { + "Sending email to ${emailRequest.email}, patient id ${emailRequest.patientId} was not successful details: ${it.data}." + } + } + }?.takeIf { it.status == SUCCESS } + ?.also { + // save information about email sent to the database + // we want to keep this transaction on this thread, so we don't suspend it + transaction { + Patients.update({ Patients.id eq emailRequest.patientId }) { + it[registrationEmailSent] = nowProvider.now() + } } + logger.info { "Registration mail sent for patient ${emailRequest.patientId}." } + }.whenNull { + dispatch(emailRequest.copy(attemptLeft = emailRequest.attemptLeft - 1)) } - logger.info { "Registration mail sent for patient ${emailRequest.patientId}." } - } } private fun buildEmailRequest(emailRequest: PatientEmailRequestDto): MailjetRequest? { @@ -90,7 +103,7 @@ class MailJetEmailService( JSONObject() .put("Email", emailRequest.email) .put("Name", "${emailRequest.firstName} ${emailRequest.lastName}") - // TODO add slot information from emailRequest.slot + // TODO add slot information from emailRequest.slot ) ) .put(Emailv31.Message.SUBJECT, mailJetConfig.subject)