Dokumentasi dan Test Cases: Alat Kuat untuk Menyelesaikan Masalah Pengembangan OpenResty
API7.ai
October 23, 2022
Setelah mempelajari prinsip-prinsip dan beberapa konsep penting dari OpenResty, akhirnya kita akan mulai mempelajari API.
Dari pengalaman pribadi saya, mempelajari API OpenResty relatif mudah, sehingga tidak memerlukan banyak artikel untuk memperkenalkannya. Anda mungkin bertanya-tanya: bukankah API adalah bagian yang paling umum dan esensial? Mengapa tidak menghabiskan banyak waktu untuk itu? Ada dua pertimbangan utama.
Pertama, OpenResty menyediakan dokumentasi yang sangat detail. Dibandingkan dengan banyak bahasa pemrograman atau platform lainnya, OpenResty tidak hanya menyediakan definisi parameter API dan nilai kembalian, tetapi juga contoh kode yang lengkap dan dapat dijalankan, yang dengan jelas menunjukkan bagaimana API menangani berbagai kondisi batas.
Mengikuti definisi API dengan contoh kode dan peringatan adalah gaya konsisten dari dokumentasi OpenResty. Oleh karena itu, setelah membaca deskripsi API, Anda dapat langsung menjalankan contoh kode di lingkungan Anda dan memodifikasi parameter serta dokumentasi untuk memverifikasinya dan memperdalam pemahaman Anda.
Kedua, OpenResty menyediakan kasus uji yang komprehensif. Seperti yang saya sebutkan, dokumentasi OpenResty menunjukkan contoh kode dari API. Namun, karena keterbatasan ruang, dokumen tersebut tidak menampilkan pelaporan kesalahan dan penanganan dalam berbagai situasi abnormal serta metode penggunaan beberapa API.
Tapi jangan khawatir. Anda dapat menemukan sebagian besar konten ini dalam kumpulan kasus uji.
Bagi pengembang OpenResty, bahan pembelajaran API terbaik adalah dokumentasi resmi dan kasus uji, yang profesional dan ramah pembaca.
Berikan seseorang ikan, dan Anda memberinya makan untuk sehari; ajari seseorang memancing dan Anda memberinya makan seumur hidup. Mari kita gunakan contoh nyata untuk merasakan bagaimana memanfaatkan kekuatan dokumentasi dan kumpulan kasus uji dalam pengembangan OpenResty.
Ambil contoh API get dari shdict
Berdasarkan area memori bersama NGINX, shared dict (kamus bersama) adalah objek kamus Lua, yang dapat mengakses data di beberapa worker dan menyimpan data seperti pembatasan laju, cache, dll. Ada lebih dari 20 API yang terkait dengan shared dict—API yang paling sering digunakan dan penting dalam OpenResty.
Mari kita ambil operasi get yang paling sederhana sebagai contoh; Anda dapat mengklik tautan dokumentasi untuk perbandingan. Contoh kode minimal berikut diadaptasi dari dokumentasi resmi.
http { lua_shared_dict dogs 10m; server { location /demo { content_by_lua_block { local dogs = ngx.shared.dogs dogs:set("Jim", 8) local v = dogs:get("Jim") ngx.say(v) } } } }
Sebagai catatan cepat, sebelum kita dapat menggunakan shared dict dalam kode Lua, kita perlu menambahkan blok memori di nginx.conf dengan direktif lua_shared_dict, yang dinamai "dogs" dan memiliki ukuran 10M. Setelah memodifikasi nginx.conf, Anda perlu memulai ulang proses dan mengaksesnya dengan browser atau perintah curl untuk melihat hasilnya.
Tidakkah ini terlihat sedikit membosankan? Mari kita modifikasi lebih sederhana. Seperti yang Anda lihat, menggunakan CLI resty dengan cara ini memiliki efek yang sama seperti menyematkan kode di nginx.conf.
$ resty --shdict 'dogs 10m' -e 'local dogs = ngx.shared.dogs dogs:set("Jim", 8) local v = dogs:get("Jim") ngx.say(v) '
Anda sekarang tahu bagaimana nginx.conf dan kode Lua bekerja sama, dan Anda telah berhasil menjalankan metode set dan get dari shared dict. Secara umum, sebagian besar pengembang berhenti di sana. Ada beberapa hal yang perlu diperhatikan di sini.
- Tahap mana yang tidak dapat menggunakan API terkait memori bersama?
- Kita melihat dalam contoh kode fungsi get hanya memiliki satu nilai kembalian. Lalu kapan akan ada lebih dari satu nilai kembalian?
- Apa jenis input ke fungsi get? Apakah ada batasan panjang?
Jangan meremehkan pertanyaan-pertanyaan ini; mereka dapat membantu kita memahami OpenResty dengan lebih baik, dan saya akan membawa Anda melalui mereka satu per satu.
Pertanyaan 1: Tahap mana yang tidak dapat menggunakan API terkait memori bersama?
Mari kita lihat pertanyaan pertama. Jawabannya cukup sederhana; dokumentasi memiliki bagian context (yaitu bagian konteks) yang mencantumkan lingkungan di mana API dapat digunakan.
context: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*
Seperti yang Anda lihat, fase init dan init_worker tidak termasuk, yang berarti bahwa API get yang terkait dengan memori bersama tidak dapat digunakan dalam dua fase ini. Harap dicatat bahwa setiap API memori bersama dapat digunakan dalam fase yang berbeda. Misalnya, API set dapat digunakan dalam fase init.
Selalu, baca dokumentasi saat menggunakannya. Tentu saja, dokumentasi OpenResty terkadang mengandung kesalahan dan kelalaian, jadi Anda perlu memverifikasinya dengan tes aktual.
Selanjutnya, mari kita modifikasi kumpulan tes untuk memastikan bahwa fase init dapat menjalankan API get dari shared dict.
Bagaimana kita dapat menemukan kumpulan kasus uji yang terkait dengan memori bersama? Kasus uji OpenResty semuanya ditempatkan di direktori /t dan dinamai secara teratur, yaitu self-incremented-number-function-name.t. Cari shdict, dan Anda akan menemukan 043-shdict.t, kumpulan kasus uji memori bersama, yang berisi hampir 100 kasus uji, termasuk tes untuk berbagai keadaan normal dan abnormal.
Mari kita coba memodifikasi kasus uji pertama.
Anda dapat mengganti fase content dengan fase init dan menghapus kode yang tidak perlu untuk melihat apakah antarmuka get berfungsi. Anda tidak perlu memahami bagaimana kasus uji ditulis, diorganisir, dan dijalankan pada tahap ini. Anda hanya perlu tahu bahwa itu sedang menguji antarmuka get.
=== TEST 1: string key, int value --- http_config lua_shared_dict dogs 1m; --- config location = /test { init_by_lua ' local dogs = ngx.shared.dogs local val = dogs:get("foo") ngx.say(val) '; } --- request GET /test --- response_body 32 --- no_error_log [error] --- ONLY
Anda seharusnya telah memperhatikan bahwa di akhir kasus uji, saya menambahkan tanda --ONLY, yang berarti mengabaikan semua kasus uji lainnya, dan hanya menjalankan yang ini, sehingga meningkatkan kecepatan berjalan. Nanti di bagian tes, saya akan menjelaskan secara khusus berbagai tag.
Setelah modifikasi, kita dapat menjalankan kasus uji dengan perintah prove.
prove t/043-shdict.t
Kemudian, Anda akan mendapatkan kesalahan yang mengkonfirmasi batasan fase yang dijelaskan dalam dokumentasi.
nginx: [emerg] "init_by_lua" directive is not allowed here
Pertanyaan 2: Kapan fungsi get memiliki banyak nilai kembalian?
Mari kita lihat pertanyaan kedua, yang dapat disimpulkan dari dokumentasi resmi. Dokumentasi dimulai dengan deskripsi syntax dari antarmuka ini.
value, flags = ngx.shared.DICT:get(key)
Dalam kondisi normal.
- Parameter pertama
valuemengembalikan nilai yang sesuai dengankeydalam kamus; namun, ketikakeytidak ada atau kedaluwarsa, nilaivalueadalahnil. - Parameter kedua,
flags, sedikit lebih rumit; jika antarmuka set menetapkan flags, itu akan mengembalikannya. Jika tidak, tidak.
Jika panggilan API gagal, value mengembalikan nil, dan flags mengembalikan pesan kesalahan tertentu.
Dari informasi yang disimpulkan dalam dokumentasi, kita dapat melihat bahwa local v = dogs:get("Jim") ditulis hanya dengan satu parameter penerima. Penulisan seperti ini tidak lengkap karena hanya mencakup skenario penggunaan tipikal tanpa menerima parameter kedua atau melakukan penanganan pengecualian. Kita dapat memodifikasinya menjadi berikut.
local data, err = dogs:get("Jim") if data == nil and err then ngx.say("get not ok: ", err) return end
Seperti pertanyaan pertama, kita dapat mencari kumpulan kasus uji untuk mengonfirmasi pemahaman kita tentang dokumentasi.
=== TEST 65: get nil key --- http_config lua_shared_dict dogs 1m; --- config location = /test { content_by_lua ' local dogs = ngx.shared.dogs local ok, err = dogs:get(nil) if not ok then ngx.say("not ok: ", err) return end ngx.say("ok") '; } --- request GET /test --- response_body not ok: nil key --- no_error_log [error]
Dalam kasus uji ini, antarmuka get memiliki input nil, dan pesan err yang dikembalikan adalah nil key. Ini memverifikasi bahwa analisis kita terhadap dokumentasi benar dan memberikan jawaban sebagian untuk pertanyaan ketiga. Setidaknya, input ke get tidak boleh nil.
Pertanyaan 3: Apa jenis input ke fungsi get?
Mengenai pertanyaan ketiga, jenis parameter input apa yang dapat diterima oleh get? Mari kita periksa dokumentasi terlebih dahulu, tetapi sayangnya, Anda akan menemukan bahwa dokumentasi tidak menentukan jenis key yang sah. Apa yang harus kita lakukan?
Jangan khawatir. Setidaknya kita tahu bahwa key dapat berupa tipe string dan tidak boleh nil. Apakah Anda ingat tipe data dalam Lua? Selain string dan nil, ada angka, array, tipe boolean, dan fungsi. Dua yang terakhir tidak perlu sebagai key, jadi kita hanya perlu memverifikasi dua yang pertama: angka dan array. Kita dapat mulai dengan mencari file tes untuk kasus di mana angka digunakan sebagai key.
=== TEST 4: number keys, string values
Dengan kasus uji ini, Anda dapat melihat bahwa angka juga dapat digunakan sebagai key, dan secara internal akan dikonversi ke string. Bagaimana dengan array? Sayangnya, kasus uji tidak mencakupnya, jadi kita perlu mencobanya sendiri.
$ resty --shdict 'dogs 10m' -e 'local dogs = ngx.shared.dogs dogs:get({}) '
Tidak mengejutkan, kesalahan berikut dilaporkan.
ERROR: (command line -e):2: bad argument #1 to 'get' (string expected, got table)
Secara ringkas, kita dapat menyimpulkan bahwa jenis key yang diterima oleh API get adalah string dan angka.
Jadi apakah ada batasan panjang dari key yang dimasukkan? Ada kasus uji yang sesuai di sini.
=== TEST 67: get a too-long key --- http_config lua_shared_dict dogs 1m; --- config location = /test { content_by_lua ' local dogs = ngx.shared.dogs local ok, err = dogs:get(string.rep("a", 65536)) if not ok then ngx.say("not ok: ", err) return end ngx.say("ok") '; } --- request GET /test --- response_body not ok: key too long --- no_error_log [error]
Ketika panjang string adalah 65536, Anda akan diberi tahu bahwa key terlalu panjang. Anda dapat mencoba mengubah panjangnya menjadi 65535, meskipun hanya 1 byte lebih sedikit, tetapi tidak ada lagi kesalahan. Ini berarti bahwa panjang maksimum key adalah tepat 65535.
Ringkasan
Akhirnya, saya ingin mengingatkan Anda bahwa dalam API OpenResty, setiap nilai kembalian dengan pesan kesalahan harus memiliki variabel untuk menerima dan melakukan penanganan kesalahan, jika tidak akan membuat kesalahan. Misalnya, jika koneksi yang salah dimasukkan ke dalam kumpulan koneksi, atau jika panggilan API gagal untuk melanjutkan logika di belakangnya, itu membuat orang mengeluh tanpa henti.
Jadi, jika Anda menemukan masalah saat menulis kode OpenResty, apa cara biasa Anda untuk menyelesaikannya? Apakah itu dokumentasi, milis, atau saluran lain?
Silakan bagikan artikel ini dengan kolega dan teman Anda sehingga kita dapat berkomunikasi dan meningkatkan.