Skip to content

Commit d6e5d19

Browse files
committed
document sns-sqs-ses
1 parent a670f6e commit d6e5d19

8 files changed

Lines changed: 451 additions & 0 deletions

File tree

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
version: "3.8"
2+
3+
services:
4+
localstack:
5+
container_name: "${LOCALSTACK_DOCKER_NAME-localstack-main}"
6+
image: localstack/localstack-pro
7+
ports:
8+
- "127.0.0.1:4510-4559:4510-4559" # external service port range
9+
- "127.0.0.1:4566:4566" # LocalStack Edge Proxy
10+
environment:
11+
- DEBUG=1
12+
- LAMBDA_EXECUTOR=${LAMBDA_EXECUTOR-}
13+
- HOST_TMP_FOLDER=${TMPDIR:-/tmp/}localstack
14+
- DOCKER_HOST=unix:///var/run/docker.sock
15+
- LOCALSTACK_AUTH_TOKEN=${LOCALSTACK_AUTH_TOKEN-}
16+
- SMTP_HOST=smtp:1025
17+
volumes:
18+
- "${LOCALSTACK_VOLUME_DIR:-./volume}:/var/lib/localstack"
19+
- "/var/run/docker.sock:/var/run/docker.sock"
20+
21+
smtp:
22+
image: mailhog/mailhog
23+
ports:
24+
- "1025"
25+
- "8025:8025"
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
2+
# **AWS Messaging : Spring Boot avec LocalStack**
3+
4+
Ce projet d’application Spring Boot montre comment :
5+
6+
* Déployer une infrastructure CloudFormation sur LocalStack
7+
* Configurer des abonnements SNS → SQS via CloudFormation
8+
* Recevoir des messages SQS avec le SDK Java AWS
9+
* Envoyer des emails avec AWS SES via le SDK Java AWS
10+
11+
---
12+
13+
# **Prérequis**
14+
15+
* **Java 11+**
16+
* **Maven 3+**
17+
* **LocalStack** (simulateur local des services AWS)
18+
* **awslocal** (wrapper AWS CLI pour LocalStack)
19+
20+
---
21+
22+
# 🚀 **Comment exécuter le projet**
23+
24+
## 1️⃣ **Construire l’application**
25+
26+
Il s’agit d’une application Spring Boot classique, compilée avec :
27+
28+
```bash
29+
mvn clean install
30+
```
31+
32+
---
33+
34+
## 2️⃣ **Lancer l’infrastructure sur LocalStack**
35+
36+
L’infrastructure est définie dans le fichier CloudFormation :
37+
38+
```
39+
src/main/resources/email-infra.yml
40+
```
41+
42+
### ➤ Démarrer LocalStack + le serveur SMTP
43+
44+
```bash
45+
LOCALSTACK_AUTH_TOKEN=<your-api-key> docker-compose up -d
46+
```
47+
48+
### ➤ Déployer la stack CloudFormation
49+
50+
```bash
51+
awslocal cloudformation deploy \
52+
--template-file src/main/resources/email-infra.yml \
53+
--stack-name email-infra
54+
```
55+
56+
---
57+
58+
## 3️⃣ **Démarrer l’application Spring Boot**
59+
60+
Vous devez définir deux variables d’environnement :
61+
62+
```bash
63+
AWS_ACCESS_KEY_ID=test AWS_SECRET_ACCESS_KEY=test mvn spring-boot:run
64+
```
65+
66+
(Ces valeurs sont fictives car LocalStack n’a pas besoin de vraies clés.)
67+
68+
---
69+
70+
## 4️⃣ **Tester l’application**
71+
72+
### ✔ Vérifier l’email expéditeur
73+
74+
```bash
75+
awslocal ses verify-email-identity --email-address no-reply@localstack.cloud
76+
```
77+
78+
### ✔ Envoyer un message SNS
79+
80+
```bash
81+
awslocal sns publish \
82+
--topic arn:aws:sns:us-east-1:000000000000:email-notifications \
83+
--message '{"subject":"hello", "address": "alice@example.com", "body": "hello world"}'
84+
```
85+
86+
### ✔ Vérifier les messages dans la file SQS via l’endpoint `/list`
87+
88+
```bash
89+
curl -s localhost:8080/list | jq .
90+
```
91+
92+
### ✔ Traiter les messages et envoyer les emails
93+
94+
```bash
95+
curl -s localhost:8080/process
96+
```
97+
98+
### ✔ Vérifier les emails envoyés
99+
100+
👉 Via MailHog : [http://localhost:8025/](http://localhost:8025/)
101+
👉 Via l’endpoint interne SES de LocalStack :
102+
103+
```bash
104+
curl -s localhost:4566/_localstack/ses | jq .
105+
```
106+
107+
---
108+
109+
# 🧠 **Explication détaillée des services AWS et de leurs rôles**
110+
111+
112+
# 🟦 **1. AWS CloudFormation — Déploiement automatique de l’infrastructure**
113+
114+
CloudFormation permet de **définir et déployer l'architecture AWS sous forme de code (IaC)**.
115+
116+
Dans ce projet, CloudFormation crée automatiquement :
117+
118+
* un **topic SNS**
119+
* une **file SQS**
120+
* un **abonnement SNS → SQS**
121+
* les politiques d’accès nécessaires
122+
123+
**Rôle :**
124+
➡ Automatiser toute l’infrastructure sans cliquer dans AWS.
125+
➡ Résultat : déploiement reproductible, versionné et contrôlé.
126+
127+
---
128+
129+
# 🟧 **2. AWS SNS (Simple Notification Service) — Service de publication/subscription**
130+
131+
SNS est un service de **messagerie pub/sub**.
132+
133+
Dans ce projet :
134+
135+
* l’application (ou un service externe) **publie un message dans le topic SNS**
136+
* SNS redirige le message vers la file SQS qui y est abonnée
137+
138+
**Rôle :**
139+
➡ Servir de **point d’entrée** des notifications.
140+
➡ Distribuer les messages à un ou plusieurs abonnés.
141+
142+
---
143+
144+
# 🟩 **3. AWS SQS (Simple Queue Service) — File de messages**
145+
146+
SQS est une file utilisée pour :
147+
148+
* découpler les systèmes
149+
* absorber une grande charge de messages
150+
* garantir la livraison même si les services consommateurs sont offline
151+
152+
Dans ce projet :
153+
154+
* SQS reçoit les messages envoyés depuis le topic SNS
155+
* L’application Spring Boot **lit SQS grâce au SDK AWS**
156+
* Chaque message contient :
157+
158+
* un sujet
159+
* une adresse email du destinataire
160+
* un contenu
161+
162+
**Rôle :**
163+
➡ Assurer une messagerie fiable entre SNS et Spring Boot.
164+
165+
---
166+
167+
# 🟪 **4. AWS SES (Simple Email Service) — Envoi d’emails**
168+
169+
SES est un service pour envoyer des emails transactionnels.
170+
171+
Dans ce projet :
172+
173+
* Après avoir lu les messages dans SQS
174+
* L’application Spring Boot utilise **AWS SES** pour envoyer un email au destinataire
175+
* L'email est simulé par LocalStack (et visualisable via MailHog)
176+
177+
**Rôle :**
178+
➡ Convertir un message métier en un **email réel** envoyé à l’utilisateur final.
179+
180+
---
181+
182+
# 🟫 **5. LocalStack — Simulateur AWS sur votre machine**
183+
184+
LocalStack émule de nombreux services AWS :
185+
186+
* SNS
187+
* SQS
188+
* SES
189+
* CloudFormation
190+
* Lambda
191+
* etc.
192+
193+
Sans coût AWS, sans connexion Internet.
194+
195+
**Rôle :**
196+
➡ Permettre un développement 100 % local
197+
➡ Tester une architecture AWS complète sans payer
198+
199+

18-projects/1-java-notification-app-ses-cf/src/main/java/com/example/AwsConfiguration.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
public class AwsConfiguration {
1616

1717
private static final String ENDPOINT_URL = "http://localhost:4566";
18+
19+
1820
private static final Region DEFAULT_REGION = Region.US_EAST_1;
1921

2022
@Bean
@@ -23,6 +25,7 @@ public SqsClient sqsClient() {
2325
.region(DEFAULT_REGION)
2426
.credentialsProvider(EnvironmentVariableCredentialsProvider.create())
2527
.applyMutation(builder -> {
28+
// TODO: conditional local-dev injection
2629
builder.endpointOverride(URI.create(ENDPOINT_URL));
2730
})
2831
.build();
@@ -34,6 +37,7 @@ public SesClient sesClient() {
3437
.region(DEFAULT_REGION)
3538
.credentialsProvider(EnvironmentVariableCredentialsProvider.create())
3639
.applyMutation(builder -> {
40+
// TODO: conditional local-dev injection
3741
builder.endpointOverride(URI.create(ENDPOINT_URL));
3842
})
3943
.build();
@@ -43,6 +47,7 @@ public SesClient sesClient() {
4347
@Autowired
4448
public String notificationQueueUrl(SqsClient sqsClient) {
4549
return sqsClient.getQueueUrl(builder -> {
50+
// TODO: could get QueueUrl from stack output properties
4651
builder.queueName("email-notification-queue");
4752
}).queueUrl();
4853
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.example;
2+
3+
import org.springframework.boot.SpringApplication;
4+
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
6+
@SpringBootApplication
7+
public class MessageApplication {
8+
9+
public static void main(String[] args) {
10+
SpringApplication.run(MessageApplication.class, args);
11+
}
12+
13+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.example;
2+
3+
import java.util.HashMap;
4+
import java.util.List;
5+
6+
import javax.servlet.http.HttpServletRequest;
7+
import javax.servlet.http.HttpServletResponse;
8+
9+
import org.springframework.beans.factory.annotation.Autowired;
10+
import org.springframework.stereotype.Controller;
11+
import org.springframework.web.bind.annotation.RequestMapping;
12+
import org.springframework.web.bind.annotation.RequestMethod;
13+
import org.springframework.web.bind.annotation.ResponseBody;
14+
15+
16+
@Controller
17+
public class NotificationController {
18+
19+
@Autowired
20+
ReceiveSendNotifications msgService;
21+
22+
// send emails for all parsable notifications
23+
@RequestMapping(value = "/process", method = RequestMethod.GET)
24+
@ResponseBody
25+
List<String> processNotifications(HttpServletRequest request, HttpServletResponse response) {
26+
return msgService.processNotifications();
27+
}
28+
29+
30+
// Lists all message bodies
31+
@RequestMapping(value = "/list", method = RequestMethod.GET)
32+
@ResponseBody
33+
List<HashMap<String, String>> listMessages(HttpServletRequest request, HttpServletResponse response) {
34+
return msgService.listMessages();
35+
}
36+
37+
38+
// Purge the message queue
39+
@RequestMapping(value = "/purge", method = RequestMethod.GET)
40+
@ResponseBody
41+
void purgeQueue(HttpServletRequest request, HttpServletResponse response) {
42+
msgService.purgeQueue();
43+
}
44+
45+
}

0 commit comments

Comments
 (0)