Studi Kasus: Microservice Notifikasi Email
Notifikasi email adalah fitur krusial di banyak aplikasi modern, baik itu untuk verifikasi akun, notifikasi aktivitas, atau pengingat penting kepada pengguna. Seiring kompleksitas sistem bertambah, pola monolitik mulai kewalahan, terutama pada integrasi sistem eksternal atau kebutuhan skalabilitas tinggi. Di sinilah gaya arsitektur microservice menawarkan solusi modular, fleksibel, dan scalable.
Pada artikel ini, kita akan membahas studi kasus membangun microservice untuk notifikasi email. Saya akan membimbing Anda melalui desain arsitektur, pembuatan kode layanan inti, integrasi message queue, serta simulasi real-world. Mari kita mulai dari big picture.
Mengapa Microservice untuk Notifikasi Email?
Ada beberapa alasan arsitektur microservice layak digunakan untuk fitur ini:
- Decoupling: Pengiriman email berjalan terpisah dari proses utama (misal user registration, order). Kegagalan satu proses tidak mempengaruhi sistem utama.
- Resilience: Dukungan queueing memastikan email tetap dikirim jika terjadi gangguan pada mail server atau service spikes.
- Scalability: Traffic tinggi hanya pada service notifikasi email bisa diatasi dengan skala horizontal pada mikroservis tersebut, tanpa mengubah service lain.
- Maintanability: Logika email, template, dan audit mudah dikembangkan terpisah dari domain utama.
Gambaran Arsitektur
Bagaimana hubungan antara service lain, message broker, dan notifikasi email? Simak diagram berikut.
flowchart LR
A(App Lain: User, Order, dsb) --|Kirim Event Notifikasi| B(Message Queue)
B --|Dequeued| C(Microservice Notifikasi Email)
C --|Kirim email| D[SMTP Server]
C --|Update log status| E(DB Notifikasi)
Penjelasan:
- A: Service lain (misal,
UserService) mengirim event ke message broker (RabbitMQ, Kafka, Redis, dsb). - B: Message broker menampung event-email sebagai buffer.
- C: Microservice notifikasi email mengambil event, mengirimkan email, dan menulis log ke database.
- D/E: SMTP/Vendor email eksternal, serta DB untuk tracking status.
Desain Skema Notifikasi Email
Tabel berikut bisa digunakan untuk tracking setiap email:
| id | email_to | subject | body | status | error_message | created_at | sent_at |
|---|---|---|---|---|---|---|---|
| 1 | user@site.com | Aktivasi Akun | … | Sukses | NULL | 2024-06-20 19:12:21 | 2024-06-20 19:12:23 |
| 2 | user2@site.com | Reset Password | … | Failure | SMTP timeout | 2024-06-20 19:14:10 | NULL |
Kolom status bisa bernilai Pending, Sukses, atau Failure.
Implementasi Microservice Email dengan Node.js & Express
Struktur Direktori
microservice-email/
├── src/
│ ├── index.js
│ ├── emailService.js
│ ├── queueConsumer.js
│ └── models/
│ └── notification.js
├── package.json
└── README.md
Dependensi
{
"dependencies": {
"express": "^4.18.2",
"amqplib": "^0.10.3", // Untuk RabbitMQ
"nodemailer": "^6.9.4", // Untuk Email SMTP
"sequelize": "^6.30.0", // ORM
"mysql2": "^3.5.2"
}
}
1. Membuat Email Service (emailService.js)
const nodemailer = require('nodemailer');
const transporter = nodemailer.createTransport({
host: 'smtp.mailprovider.com',
port: 587,
secure: false,
auth: {
user: 'your_email@provider.com',
pass: 'password'
}
});
async function sendEmail(to, subject, body) {
const mailOptions = {
from: '"YourApp Notif" <your_email@provider.com>',
to,
subject,
html: body
};
return transporter.sendMail(mailOptions);
}
module.exports = { sendEmail };
2. Mendefinisikan Model Notifikasi (models/notification.js)
// with Sequelize
const { Model, DataTypes } = require('sequelize');
const sequelize = require('../db');
class Notification extends Model {}
Notification.init({
email_to: DataTypes.STRING,
subject: DataTypes.STRING,
body: DataTypes.TEXT,
status: DataTypes.STRING,
error_message: DataTypes.STRING,
sent_at: DataTypes.DATE,
}, { sequelize, modelName: 'notification' });
module.exports = Notification;
3. Konsumer Queue (queueConsumer.js)
const amqp = require('amqplib');
const { sendEmail } = require('./emailService');
const Notification = require('./models/notification');
async function startConsumer() {
const connection = await amqp.connect('amqp://localhost');
const channel = await connection.createChannel();
const queue = 'email_notification';
await channel.assertQueue(queue);
channel.consume(queue, async (msg) => {
if(msg !== null) {
const { to, subject, body } = JSON.parse(msg.content.toString());
const notif = await Notification.create({
email_to: to, subject, body, status: 'PENDING', created_at: new Date()
});
try {
await sendEmail(to, subject, body);
notif.status = 'SUCCESS';
notif.sent_at = new Date();
} catch (err) {
notif.status = 'FAILURE';
notif.error_message = err.message;
}
await notif.save();
channel.ack(msg);
}
});
}
module.exports = { startConsumer };
4. Menjalankan Microservice (index.js)
const express = require('express');
const { startConsumer } = require('./queueConsumer');
const app = express();
app.get('/healthz', (_, res) => res.send('OK'));
app.listen(8001, () => console.log('Email Service running at 8001'));
startConsumer();
Simulasi Pengiriman Email
Anggap ada service user registration yang ingin mengirim email ke user dengan payload:
const amqp = require('amqplib');
async function publishEmail(to, subject, body) {
// Mirip logic pada service pengirim
const conn = await amqp.connect('amqp://localhost');
const ch = await conn.createChannel();
await ch.assertQueue('email_notification');
ch.sendToQueue('email_notification', Buffer.from(JSON.stringify({to, subject, body})));
setTimeout(() => conn.close(), 500);
}
// Kirim Email Aktivasi
publishEmail('user@site.com', 'Aktivasi Akun', '<b>Selamat datang!</b>');
Hasilnya, microservice akan menarik pesan queue, mengirim email, lalu memperbarui status pada database.
Infrastruktur: Skenario Failure & Scalability
Bagaimana jika SMTP down, atau traffic mendadak melonjak?
- Retry: Dengan queue, pesan tetap tertampung dan akan dicoba ulang otomatis begitu service recover.
- Horizontal Scaling: Tambah instance consumer (proses worker) untuk mengambil workload lebih banyak dari queue (misal, dengan Docker/Kubernetes).
Ringkasan dan Best Practice
- Isolasi microservice notifikasi memberikan decoupling dan reliability tinggi.
- Gunakan message broker (seperti RabbitMQ, Kafka) untuk asynchronous delivery dan failover.
- Logging dan monitoring email sangat vital, baik untuk debugging maupun SLA pengiriman.
- Hindari hardcoding SMTP credential—selalu gunakan environment variable.
Kesimpulan
Studi kasus ini mendemonstrasikan betapa powerful dan maintainable-nya sistem microservice notifikasi email jika dibangun secara modular dan asynchronous. Dengan sedikit modifikasi, service ini pun bisa diperluas ke SMS, Push Notification, atau channel lain.
Arsitektur microservice bukan silver bullet, tapi untuk usecase seperti di atas, keunggulannya sangat terasa—khususnya di sistem skala menengah sampai besar.
Mulai mendistribusikan notifikasi, delegasikan workload, dan nikmati pengelolaan sistem yang makin scalable — satu microservice pada satu waktu!
Referensi:
Apa pengalamanmu mengimplementasikan notifikasi terdistribusi? Share di komentar!