diff --git a/timeless-api/pom.xml b/timeless-api/pom.xml
index 154c661..e6004a7 100644
--- a/timeless-api/pom.xml
+++ b/timeless-api/pom.xml
@@ -71,6 +71,10 @@
quarkus-langchain4j-openai
${quarkus-langchain4j-openai.version}
+
+ io.quarkiverse.amazonservices
+ quarkus-messaging-amazon-sqs
+
io.quarkiverse.amazonservices
quarkus-amazon-sqs
diff --git a/timeless-api/src/main/java/dev/matheuscruz/infra/queue/SQS.java b/timeless-api/src/main/java/dev/matheuscruz/infra/queue/SQS.java
index 6aae662..297af47 100644
--- a/timeless-api/src/main/java/dev/matheuscruz/infra/queue/SQS.java
+++ b/timeless-api/src/main/java/dev/matheuscruz/infra/queue/SQS.java
@@ -14,20 +14,20 @@
import dev.matheuscruz.infra.ai.data.RecognizedTransaction;
import dev.matheuscruz.infra.ai.data.SimpleMessage;
import io.quarkus.narayana.jta.QuarkusTransaction;
-import io.quarkus.scheduler.Scheduled;
+import io.smallrye.mutiny.Multi;
import jakarta.enterprise.context.ApplicationScoped;
-import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Optional;
-import java.util.UUID;
-import org.eclipse.microprofile.config.inject.ConfigProperty;
+import org.eclipse.microprofile.reactive.messaging.Incoming;
+import org.eclipse.microprofile.reactive.messaging.Message;
+import org.eclipse.microprofile.reactive.messaging.Outgoing;
import org.jboss.logging.Logger;
import software.amazon.awssdk.services.sqs.SqsClient;
@ApplicationScoped
public class SQS {
- final String incomingMessagesUrl;
- final String processedMessagesUrl;
final SqsClient sqs;
final ObjectMapper objectMapper;
final TextAiService aiService;
@@ -39,43 +39,47 @@ public class SQS {
private static final ObjectReader AI_RESPONSE_READER = new ObjectMapper().readerFor(RecognizedOperation.class);
- public SQS(SqsClient sqs, @ConfigProperty(name = "whatsapp.incoming-message.queue-url") String incomingMessagesUrl,
- @ConfigProperty(name = "whatsapp.recognized-message.queue-url") String messagesProcessedUrl,
- ObjectMapper objectMapper, TextAiService aiService, RecordRepository recordRepository,
+ public SQS(SqsClient sqs, ObjectMapper objectMapper, TextAiService aiService, RecordRepository recordRepository,
UserRepository userRepository) {
this.sqs = sqs;
- this.incomingMessagesUrl = incomingMessagesUrl;
- this.processedMessagesUrl = messagesProcessedUrl;
this.objectMapper = objectMapper;
this.aiService = aiService;
this.recordRepository = recordRepository;
this.userRepository = userRepository;
}
- @Scheduled(every = "5s")
- public void receiveMessages() {
- sqs.receiveMessage(req -> req.maxNumberOfMessages(10).queueUrl(incomingMessagesUrl)).messages()
- .forEach(message -> processMessage(message.body(), message.receiptHandle()));
- }
-
- private void processMessage(String body, String receiptHandle) {
+ @Incoming("whatsapp-incoming")
+ @Outgoing("whatsapp-recognized")
+ public Multi> receiveMessages(Message message) {
+ String body = message.getPayload();
IncomingMessage incomingMessage = parseIncomingMessage(body);
- if (!MessageKind.TEXT.equals(incomingMessage.kind()))
- return;
+
+ if (!MessageKind.TEXT.equals(incomingMessage.kind())) {
+ return Multi.createFrom().item(message);
+ }
Optional user = this.userRepository.findByPhoneNumber(incomingMessage.sender());
if (user.isEmpty()) {
- logger.error("User not found. Deleting message from queue.");
- deleteMessageUsing(receiptHandle);
- return;
+ logger.error("User not found.");
+ return Multi.createFrom().item(message);
}
- handleUserMessage(user.get(), incomingMessage, receiptHandle);
+ return Multi.createFrom().iterable(handleUserMessage(user.get(), incomingMessage)).map(processedMessage -> {
+ try {
+ String processedBody = objectMapper.writeValueAsString(processedMessage);
+ return Message.of(processedBody).withAck(() -> message.ack())
+ .withNack(throwable -> message.nack(throwable));
+ } catch (JsonProcessingException e) {
+ logger.error("Failed to serialize message", e);
+ throw new RuntimeException(e);
+ }
+ });
}
- private void handleUserMessage(User user, IncomingMessage message, String receiptHandle) {
+ private List