
Untuk seseorang yang sedang mencari program sederhana dan cepat yang menerima file csv, memanggil API validasi penerima, dan mengeluarkan file CSV, program ini untuk Anda.
Saat membangun aplikasi email, pengembang sering kali perlu mengintegrasikan beberapa layanan dan API. Memahami fundamental API email dalam infrastruktur cloud memberikan dasar untuk membangun alat yang kuat seperti sistem validasi massal yang akan kita buat dalam panduan ini.
Salah satu pertanyaan yang kadang-kadang kami terima adalah, bagaimana saya dapat memvalidasi daftar email secara massal dengan validasi penerima? Ada dua opsi di sini, yang pertama adalah mengunggah file melalui UI SparkPost untuk validasi, dan yang lainnya adalah membuat panggilan individual per email ke API (karena API adalah validasi email tunggal).
Opsi pertama bekerja dengan baik tetapi memiliki batasan 20Mb (sekitar 500.000 alamat). Bagaimana jika seseorang memiliki daftar email yang berisi jutaan alamat? Itu bisa berarti membaginya menjadi 1.000-an unggahan file CSV.
Karena mengunggah ribuan file CSV tampaknya agak aneh, saya mengambil kasus penggunaan itu dan mulai bertanya-tanya seberapa cepat saya bisa membuat API berjalan. Dalam posting blog ini, saya akan menjelaskan apa yang saya coba dan bagaimana saya akhirnya mencapai program yang dapat menjalankan sekitar 100.000 validasi dalam 55 detik (Sedangkan dalam UI saya mendapatkan sekitar 100.000 validasi dalam 1 menit 10 detik). Dan sementara ini masih akan memakan waktu sekitar 100 jam untuk selesai dengan sekitar 654 juta validasi, skrip ini dapat berjalan di latar belakang menghemat waktu yang signifikan.
Versi akhir dari program ini dapat ditemukan di sini.
Kesalahan pertama saya: menggunakan Python
Python adalah salah satu bahasa pemrograman favorit saya. Bahasa ini unggul di banyak bidang dan sangat mudah dipahami. Namun, salah satu area di mana ia tidak unggul adalah pada proses konkuren. Meskipun python memiliki kemampuan untuk menjalankan fungsi asinkron, ia memiliki apa yang dikenal sebagai The Python Global Interpreter Lock atau GIL.
"The Python Global Interpreter Lock atau GIL, dalam kata-kata sederhana, adalah sebuah mutex (atau kunci) yang memungkinkan hanya satu thread untuk memegang kendali interpreter Python.
Ini berarti bahwa hanya satu thread yang dapat berada dalam keadaan eksekusi pada suatu waktu. Dampak dari GIL tidak terlihat oleh pengembang yang mengeksekusi program yang hanya menggunakan single-thread, tetapi dapat menjadi hambatan kinerja dalam kode yang bergantung pada CPU dan multi-threaded.
Karena Global Interpreter Lock (GIL) hanya memungkinkan satu thread untuk dieksekusi pada satu waktu, bahkan pada sistem multi-core, ia telah mendapatkan reputasi sebagai fitur "terkenal" dari Python (lihat artikel Real Python tentang GIL).
Pada awalnya, saya tidak menyadari GIL, jadi saya mulai pemrograman di python. Pada akhirnya, meskipun program saya bersifat asinkron, ia terkunci, dan tidak peduli berapa banyak thread yang saya tambahkan, saya tetap hanya mendapatkan sekitar 12-15 iterasi per detik.
Bagian utama dari fungsi asinkron di Python dapat dilihat di bawah ini:
Jadi saya menghentikan penggunaan Python dan kembali ke papan gambar…
Saya memutuskan untuk menggunakan NodeJS karena kemampuannya dalam melakukan operasi i/o non-blokir dengan sangat baik. Pilihan lain yang sangat baik untuk menangani pemrosesan API asinkron adalah membangun konsumen webhook serverless dengan Azure Functions, yang dapat menangani beban kerja variabel secara efisien. Saya juga cukup akrab dengan pemrograman di NodeJS.
Memanfaatkan aspek asinkron dari Node.js, pendekatan ini bekerja dengan baik. Untuk detail lebih lanjut tentang pemrograman asinkron di Node.js, lihat panduan RisingStack tentang pemrograman asinkron di Node.js.
Kesalahan kedua saya: mencoba membaca file ke dalam memori
Memecah kode terakhir
Setelah membaca dan memvalidasi argumen terminal, saya menjalankan kode berikut. Pertama, saya membaca file CSV dari email dan menghitung setiap baris. Ada dua tujuan dari fungsi ini, 1) memungkinkan saya untuk melaporkan kemajuan file secara akurat [seperti yang akan kita lihat nanti], dan 2) memungkinkan saya untuk menghentikan timer ketika jumlah email dalam file sama dengan validasi yang diselesaikan. Saya menambahkan timer agar saya bisa menjalankan tolok ukur dan memastikan saya mendapatkan hasil yang baik.
Kemudian saya memanggil fungsi validateRecipients. Perhatikan bahwa fungsi ini bersifat asinkron. Setelah memvalidasi bahwa infile dan outfile adalah CSV, saya menulis baris header, dan memulai timer program menggunakan pustaka JSDOM.
Script berikut ini benar-benar merupakan inti dari program jadi saya akan memecahnya dan menjelaskan apa yang sedang terjadi. Untuk setiap baris dari infile:
Sambil bekerja secara asinkron, ambil baris tersebut dan panggil recipient validation API.
Kemudian, pada respons
Tambahkan email ke JSON (agar dapat mencetak email dalam CSV)
Validasi jika reason adalah null, dan jika demikian, isikan nilai kosong (ini agar format CSV tetap konsisten, karena dalam beberapa kasus reason diberikan dalam respons)
Setel options dan keys untuk modul json2csv.
Konversi JSON ke CSV dan keluarkan (menggunakan json2csv)
Tulis kemajuan di terminal
Akhirnya, jika jumlah email dalam file = validasi yang diselesaikan, hentikan timer dan cetak hasilnya
Satu masalah terakhir yang saya temukan adalah meskipun ini bekerja dengan baik di Mac, saya menghadapi kesalahan berikut ketika menggunakan Windows setelah sekitar 10.000 validasi:
Error: connect ENOBUFS XX.XX.XXX.XXX:443 – Local (undefined:undefined) dengan email XXXXXXX@XXXXXXXXXX.XXX
Setelah melakukan penelitian lebih lanjut, ini tampaknya menjadi masalah dengan pool koneksi klien HTTP NodeJS yang tidak menggunakan kembali koneksi. Saya menemukan artikel Stackoverflow tentang masalah ini, dan setelah menggali lebih dalam, menemukan konfigurasi default yang baik untuk pustaka axios yang menyelesaikan masalah ini. Saya masih tidak yakin mengapa masalah ini hanya terjadi di Windows dan tidak di Mac.
Langkah Selanjutnya
Untuk seseorang yang mencari program cepat dan sederhana yang menerima csv, memanggil API validasi penerima, dan mengeluarkan CSV, program ini untuk Anda.
Beberapa penambahan pada program ini diantaranya:
Membangun antarmuka depan atau UI yang lebih mudah digunakan
Penanganan kesalahan dan percobaan ulang yang lebih baik karena jika karena alasan tertentu API mengeluarkan kesalahan, program saat ini tidak mencoba ulang panggilan
Pertimbangkan untuk mengimplementasikan sebagai serverless Azure Function untuk penskalaan otomatis dan pengurangan manajemen infrastruktur
Saya juga ingin tahu apakah hasil yang lebih cepat dapat dicapai dengan bahasa lain seperti Golang atau Erlang/Elixir. Di luar pemilihan bahasa, batasan infrastruktur juga dapat memengaruhi kinerja - kami belajar ini secara langsung ketika kami menemui batas DNS yang tidak terdokumentasi di AWS yang memengaruhi sistem pemrosesan email volume tinggi kami.
Untuk pengembang yang tertarik menggabungkan pemrosesan API dengan alat alur kerja visual, lihat cara mengintegrasikan Flow Builder dengan Google Cloud Functions untuk alur kerja otomasi tanpa kode.
Silakan berikan saya umpan balik atau saran untuk mengembangkan proyek ini.