AWS Lambda adalah layanan FaaS milik Amazon: kamu menyerahkan satu function, dan AWS yang menyalakan server, menjalankan function itu saat ada event, lalu menambah salinannya saat ramai. Kamu bayar per request dan per milidetik selama function jalan, jadi jam sepi gak ada biaya idle. Ingat juru masak panggilan dari pelajaran Cloud Computing Basics. Saat pertama datang, dia harus menata meja, mengasah pisau, dan menyalakan kompor dulu (cold start). Setelah itu tiap pesanan langsung dimasak (handler). Kalau dia masih di dapur saat pesanan berikutnya datang, persiapannya gak diulang (warm start). Pesanan datang bersamaan? Agensi mengirim juru masak tambahan, tapi cuma sampai batas kontrak (concurrency). Tiap juru masak memegang stopwatch (timeout), dan meja yang lebih besar lebih mahal per menit tapi masaknya lebih cepat (memory).
🧪 Tebakan cepat: batas konkurensi
catatan-ekspordiset 2. Lima request ekspor PDF datang di detik yang sama. Berapa yang dikerjakan, dan apa yang terjadi pada sisanya? Tebak dulu, jawabannya ada di bagian "Konkurensi dan throttle".
Handler: event masuk, response keluar
Pelajaran Serverless Functions sudah memperkenalkan bentuknya. Sekarang kita pakai sungguhan: fitur ekspor PDF catatan-api makan banyak CPU dan ramainya cuma di jam kerja, jadi route POST /catatan/{id}/ekspor dipindah dari web-1 ke Lambda bernama catatan-ekspor (Node.js 22, region ap-southeast-3 Jakarta, sama dengan bucket catatan-lampiran dari pelajaran Object Storage).
// index.mjs (handler: index.handler)
import pg from "pg";
import { buatPdf } from "./pdf.mjs";
// INIT: jalan sekali per execution environment
const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL, max: 1 });
export const handler = async (event, context) => {
const id = Number(event.pathParameters?.id);
if (!Number.isInteger(id)) {
return { statusCode: 400, body: JSON.stringify({ error: "id harus angka" }) };
}
const { rows } = await pool.query("SELECT judul, isi FROM catatan WHERE id = $1", [id]);
if (rows.length === 0) {
return { statusCode: 404, body: JSON.stringify({ error: "catatan tidak ditemukan" }) };
}
console.log(`ekspor ${id}, sisa waktu ${context.getRemainingTimeInMillis()} ms`);
const pdf = await buatPdf(rows[0]); // kerja CPU paling berat
return {
statusCode: 200,
headers: { "Content-Type": "application/pdf" },
isBase64Encoded: true,
body: pdf.toString("base64"),
};
};
handler(event, context): AWS memanggil function ini sekali per request.eventberisi data request,contextberisi info tentang eksekusi ini.context.getRemainingTimeInMillis()memberi tahu sisa waktu sebelum timeout.context.awsRequestIdadalah id request yang sama dengan yang muncul di log.- Yang di-return adalah object
{ statusCode, headers, body }. Body selalu string, jadi file biner seperti PDF dikirim sebagai base64 denganisBase64Encoded: true. - Baris di luar handler (
import,new pg.Pool) adalah init code. Bedanya dibahas dua bagian lagi.
Event dari API Gateway
API Gateway adalah layanan AWS yang menerima request HTTP dari internet lalu meneruskannya ke Lambda sebagai event JSON. Untuk HTTP API (format payload 2.0), event POST /catatan/42/ekspor kira-kira begini (dipangkas):
{
"version": "2.0",
"routeKey": "POST /catatan/{id}/ekspor",
"rawPath": "/catatan/42/ekspor",
"headers": { "content-type": "application/json", "authorization": "Bearer eyJhbGciOi..." },
"pathParameters": { "id": "42" },
"requestContext": {
"http": { "method": "POST", "path": "/catatan/42/ekspor", "sourceIp": "198.51.100.7" },
"requestId": "Ab3xQjYzSQ0EJXw="
},
"body": "{\"ukuran\":\"A4\"}",
"isBase64Encoded": false
}
Method ada di event.requestContext.http.method, dan {id} dari route masuk ke event.pathParameters.id sebagai string. body juga string, jadi perlu JSON.parse(event.body). REST API yang lebih tua memakai format 1.0, dengan event.httpMethod dan event.path. Cek dulu format mana yang dipakai sebelum membaca field-nya.
Init sekali, handler berkali-kali
Lambda menjalankan function-mu di dalam execution environment (yang di pelajaran Serverless Functions disebut instance): sebuah sandbox kecil dengan runtime Node.js, kode-mu, dan memory-nya sendiri. Satu environment mengerjakan satu request pada satu waktu.
| Kejadian | Yang jalan | Contoh di Lab (512 MB) |
|---|---|---|
| Cold start: belum ada environment yang nganggur | init (start runtime, import, new pg.Pool) lalu handler |
Init Duration 412,08 ms, lalu Duration 926,36 ms |
| Warm start: ada environment yang nganggur | handler saja | Duration 862,71 ms |
Request pertama di environment baru juga membuka koneksi ke Postgres (64 ms). Karena pool dibuat di luar handler, request berikutnya di environment yang sama memakai koneksi itu lagi. Kalau new pg.Pool() dipindah ke dalam handler, tiap request membuka koneksi baru, dan koneksi lama tetap menggantung selama environment-nya hidup. Environment yang lama nganggur dibuang AWS (berapa lama, AWS gak janji; di Lab, 15 menit). Mengubah kode atau konfigurasi seperti memory juga membuat environment baru, jadi request sesudahnya cold start.
Untuk endpoint yang gak boleh kena cold start, Provisioned Concurrency menyiapkan sejumlah environment yang sudah di-init sebelum request datang. Biayanya tambahan, dibayar per jam walau gak ada request. Penyebab cold start dan cara menekannya dibahas di Serverless Patterns & Cold Start.
Konkurensi dan throttle
Concurrency adalah jumlah environment yang sedang mengerjakan request di saat yang sama. Hitungan kasarnya: request per detik × durasi rata-rata dalam detik. 20 request per detik × 0,5 detik = sekitar 10 environment bersamaan.
Kuota bawaan konkurensi biasanya 1.000 per region untuk semua function di akunmu (akun baru bisa lebih kecil). Reserved concurrency memberi satu function batas sendiri. Di atas batas itu Lambda menolak request dengan error TooManyRequestsException (status 429, Rate Exceeded.). Itulah throttle. Jadi dengan batas 2 dan lima request bersamaan, dua dikerjakan (dua cold start) dan tiga ditolak 429. Itu jawaban tebakannya. Request yang ditolak gak pernah menjalankan kode-mu, jadi gak ada log-nya. Pemanggil sinkron seperti API Gateway menerima error, sedangkan event async (S3, EventBridge) disimpan dan dicoba lagi oleh Lambda sampai 6 jam.
Kenapa justru sengaja dibatasi? Tiap environment memegang koneksi Postgres sendiri. 1.000 environment berarti 1.000 koneksi, padahal max_connections bawaan Postgres cuma 100. Batas konkurensi plus max: 1 di pool menjaga database tetap hidup. Dasarnya ada di pelajaran Connection Pooling, dan untuk trafik besar AWS punya RDS Proxy yang menjadi pool di antara Lambda dan database.
Memory, CPU, dan timeout
Memory bisa diset dari 128 MB sampai 10.240 MB, dan CPU ikut naik sebanding dengan memory (sekitar 1.769 MB = 1 vCPU penuh). Timeout bawaannya 3 detik, paling lama 900 detik (15 menit). Lewat dari itu, request dihentikan dengan pesan Task timed out after 3.00 seconds. Angka contoh dari Lab untuk warm start catatan-ekspor:
| Memory | Waktu yang dibutuhkan | Hasil dengan timeout 3 detik | Biaya per 1 juta request |
|---|---|---|---|
| 128 MB | 3.412,71 ms | dihentikan di 3.000 ms | (gagal) |
| 512 MB | 862,71 ms | 200 | $7,39 |
| 1.024 MB | 437,71 ms | 200 | $7,50 |
Menaikkan memory dari 512 MB ke 1.024 MB membuat PDF dua kali lebih cepat, tapi biayanya hampir sama, karena harga dihitung dari GB × detik: memory dua kali, durasi setengahnya. Di 128 MB, menaikkan timeout ke 10 detik memang menghilangkan error, tapi user menunggu 3,4 detik. Yang benar di sini menambah memory.
Membaca baris REPORT di CloudWatch
Semua console.log dan log dari Lambda masuk ke CloudWatch Logs, di log group /aws/lambda/catatan-ekspor. Tiap request diapit tiga baris dari Lambda sendiri. Ini cold start di 512 MB (angka contoh):
INIT_START Runtime Version: nodejs:22.v51 Runtime Version ARN: arn:aws:lambda:ap-southeast-3::runtime:7c1e4b0d9a3f52e8c6b1d0a9f8e7d6c5b4a39281706f5e4d3c2b1a0f9e8d7c6b
START RequestId: 8f5a1c2e-4b7d-4e19-9c3a-000000000001 Version: $LATEST
2026-10-09T02:00:00.488Z 8f5a1c2e-4b7d-4e19-9c3a-000000000001 INFO ekspor 42, sisa waktu 2924 ms
END RequestId: 8f5a1c2e-4b7d-4e19-9c3a-000000000001
REPORT RequestId: 8f5a1c2e-4b7d-4e19-9c3a-000000000001 Duration: 926.36 ms Billed Duration: 1339 ms Memory Size: 512 MB Max Memory Used: 97 MB Init Duration: 412.08 ms
- Duration: lama handler jalan untuk request ini.
- Billed Duration: yang ditagih, dibulatkan ke atas per milidetik. Sejak 1 Agustus 2025 AWS juga menagih fase init, jadi di cold start angkanya Duration + Init Duration: 926,36 + 412,08 = 1.338,44, dibulatkan jadi 1.339 ms.
- Memory Size: memory yang kamu set. Max Memory Used: puncak pemakaian sungguhan. Kalau angkanya jauh di bawah, boleh turunkan memory, asal durasinya gak melonjak.
- Init Duration: cuma muncul di cold start. Kalau baris REPORT gak punya field ini, request itu warm.
Biaya = jumlah request × $0,20 per juta + GB × detik × $0,0000166667 (harga contoh x86, cek halaman harga region-mu). Warm start 512 MB: 0,5 GB × 0,863 detik × $0,0000166667 ≈ $0,0000072 per request, plus $0,0000002. Sejuta request jadi sekitar $7,39.
Trigger selain HTTP
API Gateway hanya satu dari banyak trigger, yaitu sumber event yang memanggil Lambda:
- S3 Event: objek baru masuk ke bucket. Contoh: foto profil di-upload, Lambda membuat thumbnail-nya.
- SQS: pesan di antrean. Lambda mengambilnya per batch, cocok untuk kerja yang boleh antre.
- EventBridge (dulu bernama CloudWatch Events): jadwal cron, misalnya backup tiap jam 2 pagi.
- DynamoDB Streams: data di tabel berubah, misalnya untuk memperbarui index pencarian.
Ukuran kode juga dibatasi: 50 MB untuk zip yang di-upload langsung, 250 MB setelah diekstrak (termasuk layer), atau sampai 10 GB kalau dikemas sebagai container image.
⚠️ Jebakan yang sering ketemu
- Membuat koneksi database di dalam handler. Tiap request membayar koneksi baru, dan koneksi lama menggantung. Buat client di luar handler, dengan pool kecil.
- Konkurensi tanpa batas di depan Postgres. Lonjakan trafik jadi ratusan environment dan ratusan koneksi. Pasang reserved concurrency,
max: 1, atau RDS Proxy. - Menaikkan timeout untuk menambal function yang lambat. Kalau kerjanya CPU, naikkan memory: lebih cepat dan biayanya sering hampir sama.
- Salah format event. Membaca
event.httpMethoddari HTTP API (format 2.0) hasilnyaundefined. Method-nya ada dievent.requestContext.http.method.
TL;DR: Lambda memanggil handler(event, context) sekali per request dan menagih per request plus GB × detik, tanpa biaya idle. Kode di luar handler (init) jalan sekali per execution environment saat cold start, lalu dipakai ulang di warm start, jadi buat koneksi database di sana dengan pool kecil. Satu environment = satu request pada satu waktu, concurrency ≈ request per detik × durasi, kuota bawaannya biasanya 1.000 per region, dan di atas batas Lambda menolak dengan 429 TooManyRequestsException (throttle). Memory 128 MB sampai 10.240 MB menentukan CPU, timeout bawaan 3 detik dan paling lama 15 menit. Baris REPORT di CloudWatch berisi Duration, Billed Duration, Memory Size, Max Memory Used, dan Init Duration yang cuma muncul di cold start. Trigger selain API Gateway: S3 Event, SQS, EventBridge, DynamoDB Streams. Provisioned Concurrency menjaga environment tetap warm dengan biaya tambahan.