Operasi database dari aplikasi dapat gagal di dua tempat, yaitu sebelum perintah sampai ke server dan di dalam server. Kegagalan pertama terjadi karena jaringan atau server yang tidak terjangkau, sedangkan kegagalan kedua terjadi karena aturan data yang dilanggar. Kedua kegagalan itu memerlukan penanganan yang berbeda, karena satu di antaranya tidak menyentuh data sama sekali, sedangkan yang lain mungkin sudah mengubah data pada saat error dilaporkan. Topik ini membahas error koneksi dan error tulisan dari aplikasi Node.js, batas waktu pemilihan server, retryable writes, dan write concern yang tidak terpenuhi. Contohnya menggunakan dua program kecil yang errornya dapat direproduksi dengan pasti pada lingkungan latihan ini.
Dua kategori error dari driver#
Driver Node.js melaporkan masalah melalui objek error dengan properti terstruktur, dan pembacaan properti itu lebih andal daripada pembacaan teks pesannya. Error koneksi berasal dari sisi jaringan, misalnya MongoServerSelectionError ketika tidak ada server yang dapat dipilih, atau MongoNetworkError ketika hubungan terputus di tengah operasi. Error server berasal dari penolakan perintah, misalnya MongoServerError yang membawa kode kesalahan server seperti 11000 untuk pelanggaran keunikan. Keduanya sampai ke kode aplikasi melalui mekanisme catch yang sama, sehingga pembedaannya dilakukan dengan membaca err.name dan err.code. Properti name berisi nama kelas error dan stabil antar versi driver, sedangkan message ditujukan bagi pembacaan manusia dan bentuknya dapat berubah.
PyMongo menamai kelas yang setara dengan konvensi Python. ServerSelectionTimeoutError dari pymongo.errors setara dengan MongoServerSelectionError, DuplicateKeyError adalah penurunan langsung dari error tulisan dengan kode 11000, dan WriteConcernError membawa kegagalan write concern. Pemetaan ini penting ketika pola penanganan dipindahkan antar kedua bahasa, karena nama kelasnya berbeda sedangkan kode kesalahan servernya tetap sama. Kode code berupa angka yang diterbitkan server, dan angka yang sama juga ditampilkan mongosh ketika perintah yang setara ditolak.
Error tulisan dengan kode yang pasti#
Error tulisan yang paling sering ditemui adalah pelanggaran keunikan, yaitu kode 11000 atau E11000. Server menolak dokumen kedua yang _id-nya sama dengan dokumen yang sudah ada, dan mongosh menampilkan error yang sama dengan yang diterima aplikasi. Blok berikut menyisipkan dokumen dengan _id tetap bernilai 101 dua kali, sehingga penyisipan kedua pasti ditolak.
use tugas
db.pekerjaan.insertOne({ _id: 101, judul: "Isi ulang tinta printer", selesai: false })
db.pekerjaan.insertOne({ _id: 101, judul: "Isi ulang tinta printer", selesai: true })switched to db tugas
{ acknowledged: true, insertedId: 101 }
Uncaught
MongoServerError: E11000 duplicate key error collection: tugas.pekerjaan index: _id_ dup key: { _id: 101 }Baris MongoServerError berasal dari server, bukan dari shell. Pesannya memuat nama koleksi, nama indeks, dan nilai yang bertabrakan, sedangkan kode 11000-nya adalah bagian yang sebaiknya dibaca program. Pesan lengkap seperti ini berguna untuk diagnosis manual, tetapi kode aplikasi sebaiknya membaca properti terstruktur yang stabil antar versi server.
Program error-tulis.js menangkap error yang sama dari kode aplikasi. Alih-alih mencetak seluruh pesan, program membaca err.name, err.code, dan err.keyValue, lalu melanjutkan eksekusi seperti biasa.
// Menangkap error tulisan E11000 dari aplikasi Node.js
const { MongoClient } = require("mongodb");
const client = new MongoClient("mongodb://127.0.0.1:27017");
async function main() {
await client.connect();
const koleksi = client.db("tugas").collection("pekerjaan");
// koleksi di-reset agar keluaran program selalu sama
await koleksi.deleteMany({});
await koleksi.insertOne({ _id: 101, judul: "Isi ulang tinta printer", selesai: false });
try {
await koleksi.insertOne({ _id: 101, judul: "Isi ulang tinta printer", selesai: false });
} catch (err) {
console.log("name:", err.name);
console.log("code:", err.code);
console.log("keyValue:", JSON.stringify(err.keyValue));
}
// program tetap berjalan setelah error tertangani
console.log("Dokumen tersimpan:", await koleksi.countDocuments());
await client.close();
}
main().catch((e) => { console.error(e); process.exitCode = 1; });name: MongoServerError
code: 11000
keyValue: {"_id":101}
Dokumen tersimpan: 1Angka Dokumen tersimpan: 1 menunjukkan program tetap berjalan setelah error tertangani, yaitu perilaku yang diharapkan dari penanganan error tulisan yang benar. Dokumen pertama tetap utuh, sedangkan dokumen yang ditolak tidak pernah tersimpan. Pencabangan berdasarkan err.code memungkinkan perlakuan khusus, misalnya E11000 pada kolom judul ditangani dengan memberi tanda penyimpanan ulang, sedangkan kode lain dilaporkan apa adanya.
Program dijalankan dari folder topik dengan penyiapan NODE_PATH yang sama dengan contoh Node.js lain pada modul ini.
# menetapkan lokasi package driver, lalu menjalankan program Node.js
export NODE_PATH=/home/kal/tools/node-driver/node_modules
node error-tulis.jsname: MongoServerError
code: 11000
keyValue: {"_id":101}
Dokumen tersimpan: 1Error koneksi dan server selection#
Error koneksi muncul ketika tidak ada server yang dapat dipilih untuk menjalankan perintah. Driver menunggu sampai batas serverSelectionTimeoutMS tercapai, dengan nilai bawaan 30 detik, sebelum mengangkat MongoServerSelectionError. Nilai bawaan yang panjang membuat aplikasi terasa berhenti ketika server mati. Program latihan berikut mempersingkatnya menjadi 2000 milidetik dan menyasar port 27099 yang tidak dipakai siapa pun. Prosesnya sama dengan server yang benar-benar berjalan, hanya alamatnya sengaja kosong.
// Menangkap error koneksi ketika server tidak terjangkau
const { MongoClient } = require("mongodb");
const client = new MongoClient("mongodb://127.0.0.1:27099", { serverSelectionTimeoutMS: 2000 });
async function main() {
try {
await client.connect();
const koleksi = client.db("tugas").collection("pekerjaan");
console.log("Dokumen tersimpan:", await koleksi.countDocuments());
} catch (err) {
console.log("name:", err.name);
console.log("message:", err.message);
} finally {
await client.close();
}
}
main().catch((e) => { console.error(e); process.exitCode = 1; });name: MongoServerSelectionError
message: connect ECONNREFUSED 127.0.0.1:27099Pesan connect ECONNREFUSED menyatakan sistem operasi menolak hubungan ke port itu, sedangkan properti name memberi pengenal kelas error yang stabil untuk pencabangan program. Pada aplikasi nyata, error ini ditangani di satu tempat, misalnya melaporkan gangguan ke sistem pemantauan lalu mengulang operasi setelahnya. Mencetak seluruh objek error ke pengguna akhir jarang berguna, karena teksnya panjang dan memuat rincian topology yang bukan ranah pengguna. Setiap percobaan hubungan ditolak sistem operasi dalam hitungan milidetik, tetapi driver tetap menunggu sampai batas waktunya habis sebelum melaporkan errornya.
Program dijalankan dari folder topik dengan cara yang sama, dan errornya muncul dalam hitungan detik karena batas waktunya sudah dipersingkat.
# menetapkan lokasi package driver, lalu menjalankan program Node.js
export NODE_PATH=/home/kal/tools/node-driver/node_modules
node error-koneksi.jsname: MongoServerSelectionError
message: connect ECONNREFUSED 127.0.0.1:27099Retryable writes dan write concern#
Server dapat memproses ulang satu operasi tulisan dokumen tunggal secara otomatis ketika hubungan jaringan terputus setelah perintah terkirim tetapi sebelum jawabannya diterima. Mekanisme ini bernama retryable writes dan aktif secara bawaan pada connection string yang menyasar replica set, termasuk melalui opsi retryWrites=true. Cakupannya adalah insertOne, updateOne, replaceOne, deleteOne, dan metode findOneAnd..., sedangkan operasi banyak dokumen seperti insertMany tidak diulang otomatis karena pengulangannya berisiko menggandakan hasil.
Kategori berikutnya adalah write concern yang tidak terpenuhi. Perintah tulisan dapat mengajukan syarat replikasi, misalnya w: 2 yang menunggu pengakuan dari dua anggota replica set. Pada replica set satu anggota seperti lingkungan latihan ini, syarat itu mustahil dipenuhi, sehingga server menjawab dengan MongoWriteConcernError kode 100. Blok berikut mengajukan syarat semacam itu dan menangkap errornya.
try {
db.pekerjaan.insertOne({ judul: "Cek write concern", selesai: false }, { writeConcern: { w: 2, wtimeout: 1000 } })
} catch (e) {
print("name:", e.name)
print("code:", e.code)
}
print("Dokumen tersimpan: " + db.pekerjaan.countDocuments())name: MongoWriteConcernError
code: 100
Dokumen tersimpan: 2Poin pentingnya ada pada angka Dokumen tersimpan: 2, yaitu dokumen dengan _id 101 dari blok sebelumnya ditambah dokumen yang dilaporkan gagal. MongoWriteConcernError tidak berarti tulisan gagal diterapkan, melainkan hanya menandakan syarat replikasinya yang tidak terpenuhi dalam batas waktu. Penanganan yang aman memeriksa isi error lalu memverifikasi keadaan data sebelum memutuskan mengulang operasi. Opsi wtimeout menetapkan berapa lama server menunggu syarat replikasi sebelum melaporkan kegagalan, sehingga tulisan tidak menggantung tanpa batas.
Kesalahan umum#
Kesalahan pertama adalah menelan error dengan blok catch yang kosong. Program tampak sehat, tetapi dokumen yang gagal disimpan hilang tanpa jejak, dan penyebabnya baru diketahui saat data dibaca pengguna. Setiap catch minimal mencatat err.name dan err.code ke log, lalu memutuskan apakah operasi diulang, dilaporkan, atau dibiarkan naik ke pemanggilnya.
Kesalahan kedua adalah mengulang insertMany secara membabi buta setelah error jaringan. Operasi banyak dokumen tidak termasuk retryable writes, sehingga sebagian batch mungkin sudah tersimpan ketika hubungan terputus, dan pengulangan menyisipkannya lagi. Rancang pengulangan agar idempoten, yaitu aman dijalankan ulang dengan hasil akhir yang sama, misalnya dengan _id yang ditetapkan sendiri sehingga penyisipan ulang hanya menghasilkan E11000 yang aman diabaikan.
Kesalahan ketiga adalah menyetel serverSelectionTimeoutMS tanpa pertimbangan. Nilai yang besar membuat aplikasi menunggu lama pada server yang mati, sedangkan nilai yang kecil melaporkan error pada server yang hanya lambat sesaat. Nilai 2000 milidetik pada contoh latihan dipilih agar program cepat berakhir, bukan sebagai rekomendasi untuk produksi. Batas yang sama berlaku untuk seluruh operasi klien karena ditetapkan pada connection string, sehingga perubahan nilainya cukup dilakukan di satu tempat.
Ringkasan#
- Error koneksi dan error server dibedakan lewat
err.namedanerr.code, bukan lewat teks pesannya. - E11000 adalah error tulisan yang pasti, yaitu penolakan server atas dokumen dengan
_idatau nilai unik yang sudah ada, dan penanganannya membaca properti terstruktur sepertikeyValue. serverSelectionTimeoutMSmembatasi lamanya driver menunggu server yang dapat dipilih, dengan nilai bawaan 30 detik.- Retryable writes mengulang otomatis operasi dokumen tunggal pada replica set, sedangkan
MongoWriteConcernErrormenandakan syarat replikasi yang tidak terpenuhi dan tidak menjamin tulisan gagal diterapkan.
Referensi#
- Retryable Writes — MongoDB Manual — Operasi tulisan yang diulang otomatis oleh driver pada replica set.
- Write Concern — MongoDB Manual
— Syarat replikasi tulisan beserta opsi
wtimeout. - Error Codes — MongoDB Manual — Daftar kode kesalahan server, termasuk 11000 untuk duplikasi kunci.
- Connect to MongoDB — MongoDB Node.js Driver
— Opsi koneksi seperti
serverSelectionTimeoutMSpada driver Node.js. - errors — PyMongo Documentation — Kelas error PyMongo untuk pelanggaran keunikan beserta kelas induknya.