Goal
We want to add asynchronous email sending to an Hello World Application already hosted on Poja that exposes the /hello?to=email@address.com
endpoint, for which it answers ... world!
and sends an email to the specified email address.
How-to in 2 steps
Step 1: Add email sending to your endpoint
package com.my.company.endpoint.rest.controller;
import com.my.company.mail.Email;
import com.my.company.mail.Mailer;
import jakarta.mail.internet.InternetAddress;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@AllArgsConstructor
public class HelloWorldController {
private final Mailer mailer;
@GetMapping("/hello")
@SneakyThrows
public String helloWorld(@RequestParam String to) {
var email =
new Email(new InternetAddress(to), List.of(), List.of(), "Hello world", "... world!", List.of());
mailer.accept(email);
return "... world!";
}
}
Step 2: Make it asynchronous
Update the environment’s configuration
Select the preprod environment to update, click one Edit button on the Poja Configuration section and then:
Set Queues NB to 2
Click on the Save button at the bottom
Updating environment configuration
When the Poja Configuration of an environment is modified:
Changes will be pushed on the environment’s branch (prod or preprod)
A new deployment will be triggered for the specified environment
Write the asynchronous code
In the context of Poja, asychronous code refers to an Event driven code executing in Workers. Follow the instructions below to write the asynchronous email sending:
Create the event class
SendEmailRequested
with the propertyto
which refers to the recipient address of the email inside the packagecom.my.company.endpoint.event.model
Create the service
SendEmailRequestedService
which will consume the event object and send the email inside the packagecom.my.company.service.event
Produce the event when the user sends a request to the
/hello
endpoint and provides an email address
Important !
Event classes must be located inside the
your.package.name.endpoint.event.model
packageEvent processing services must be located inside the
your.package.name.service.event
Event processing services should be named must be named as follows
{event_name}Service
Example:SendEmailRequested
andSendEmailRequestedService
package com.my.company.endpoint.event.model;
import java.time.Duration;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
@NoArgsConstructor
@AllArgsConstructor
@Builder(toBuilder = true)
@Data
@EqualsAndHashCode(callSuper = false)
@ToString
public class SendEmailRequested extends PojaEvent {
private String to;
@Override
public Duration maxConsumerDuration() {
return Duration.ofSeconds(45);
}
@Override
public Duration maxConsumerBackoffBetweenRetries() {
return Duration.ofSeconds(30);
}
}
package com.my.company.service.event;
import com.my.company.endpoint.event.model.SendEmailRequested;
import com.my.company.mail.Email;
import com.my.company.mail.Mailer;
import jakarta.mail.internet.InternetAddress;
import java.util.List;
import java.util.function.Consumer;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.stereotype.Service;
@Service
@AllArgsConstructor
public class SendEmailRequestedService implements Consumer<SendEmailRequested> {
private final Mailer mailer;
@SneakyThrows
@Override
public void accept(SendEmailRequested sendEmailRequested) {
InternetAddress recipientAddress = new InternetAddress(sendEmailRequested.getTo());
mailer.accept(new Email(recipientAddress, List.of(), List.of(), "", "... world!", List.of()));
}
}
Now, update the previously created HelloWorldController to produce an event instead of directly sending the email:
package com.my.company.endpoint.rest.controller;
import com.my.company.endpoint.event.EventProducer;
import com.my.company.endpoint.event.model.SendEmailRequested;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@AllArgsConstructor
public class HelloWorldController {
private final EventProducer<SendEmailRequested> eventProducer;
@GetMapping("/hello")
@SneakyThrows
public String helloWorld(@RequestParam String to) {
var event = SendEmailRequested.builder().to(to).build();
eventProducer.accept(List.of(event));
return "... world!";
}
}
To trigger a deployment, just commit and push the code to the preprod branch of the repository. Wait. And voilà!