node.js serverside - bekerja pada bug. Bagian 1

Selamat siang

Artikel ini ditujukan untuk pengembang yang akrab dengan node.js.

Baru-baru ini saya sedang menyiapkan materi tentang fakta-fakta yang berguna untuk diketahui oleh para pengembang di bawah node.js di kantor kami. Proyek yang kami kerjakan adalah layanan API yang menggunakan modul express node.js sebagai server web. Materi didasarkan pada kasus nyata di mana kode bekerja salah atau logika di dalamnya disembunyikan dengan hati-hati, atau memicu kesalahan selama ekspansi. Berdasarkan materi ini, lokakarya pengembangan staf diadakan.

Jadi, saya memutuskan untuk berbagi. Sejauh ini, hanya bagian pertama yang sekitar 30%. Jika tertarik, akan dilanjutkan!

Saya mencoba memberikan kesempatan untuk pengenalan cepat, jadi saya menyembunyikan contoh, alasan dan komentar di spoiler. Jika pernyataannya jelas, Anda dapat melewatkan "air". Meskipun "rake" kita di spoiler juga bisa menarik.

Seorang kolega selama seminar mengajukan pertanyaan kepada saya, mengapa membicarakannya, jika semuanya sudah ada dalam dokumentasi ini atau itu. Jawaban saya adalah sebagai berikut. Terlepas dari kenyataan bahwa pesan itu benar, semuanya benar-benar ada dalam dokumentasi, kami masih membuat kesalahan yang mengganggu terkait dengan kesalahpahaman atau ketidaktahuan tentang hal-hal dasar.

Ayo mulai!

Mesin virtual Node.js



Threading tunggal



Tidak seperti javavm, nodejs-vm adalah single-threaded ** .



Sumber

lebih detail
Pada saat yang sama, ada kumpulan thread tambahan yang digunakan oleh mesin virtual itu sendiri, misalnya, untuk mengatur I / O. Tetapi semua kode pengguna dijalankan hanya dalam satu utas, "utas".

Ini sangat menyederhanakan hidup, karena tidak ada persaingan. Eksekusi kode tidak dapat diganggu di tempat yang sewenang-wenang dan dilanjutkan di tempat lain. Kode hanya dieksekusi sampai ada kebutuhan untuk menunggu sesuatu, misalnya, kesiapan data saat membaca dari file. Saat menunggu, pawang lain dapat dieksekusi, baik sampai selesai, atau sampai juga mulai menunggu sesuatu.

Artinya, jika ada struktur data internal, maka Anda tidak perlu khawatir tentang sinkronisasi akses ke sana!

Apa yang harus dilakukan jika utas "utama" tidak punya waktu untuk memproses data?

Penskalaan dilakukan dengan memulai proses node.js lain atau, jika sumber daya server akan segera berakhir, dengan memulai server lain.

konsekuensi dan "rake" kami
Semuanya jelas di sini juga. Anda harus selalu siap untuk fakta bahwa mungkin ada (dan kemungkinan besar akan) ada lebih dari satu proses node.js. Dan terkadang ada juga beberapa server.

"Rake" yang disembunyikan ditemukan dalam kode kami


Garis-garis paralel berpotongan tak terhingga. Tidak mungkin untuk membuktikan, tetapi saya melihat.
Jean Effel, "Novel Adam dan Hawa."
Upaya dilakukan untuk memastikan keunikan instance entitas dalam database secara eksklusif oleh aplikasi. Secara umum, ini dan dalam isolasi dari konteksnya tidak terlihat buruk dengan baik, tetapi dalam situasi ini lebih dari itu. Tanpa melibatkan layanan pihak ketiga, tugas ini bagi saya tampaknya tidak memiliki solusi.

Kolega yang terlibat dalam hal ini, benar-benar ingin menerapkan ini tanpa melibatkan database yang sebenarnya. Pada akhirnya, setelah beberapa "pendekatan ke proyektil", itu direalisasikan ... dengan melibatkan SharePoint.


** Multithreading atau "jika Anda benar-benar ingin"



Dimulai dengan versi 10.5.0, node.js memiliki dukungan eksperimental untuk multithreading .


Sumber

Namun paradigma itu tetap sama
  • Setiap alur kerja baru membuat instance terisolasi sendiri dari lingkungan node mesin virtual.
  • Alur kerja tidak memiliki data yang dapat diubah yang umum. (Ada beberapa pemesanan, tetapi pada dasarnya pernyataan itu adil.)
  • Komunikasi dilakukan menggunakan pesan dan SharedArrayBuffer.

Oleh karena itu, kode lama akan terus berfungsi saat menggunakan alur kerja.
Baca lebih lanjut di sini.


Siklus hidup aplikasi



Inti dari nodejs-vm adalah loop acara. Ketika eksekusi kode harus ditangguhkan atau kode, tampaknya, telah berakhir, kontrol beralih ke sana.

Teks tersembunyi
Perulangan acara memeriksa apakah (oh) peristiwa yang telah kami daftarkan telah terjadi. Jika sesuatu terjadi, maka pawang akan dipanggil. Dan jika tidak, itu akan diperiksa jika ada "generator" dari acara yang telah kami daftarkan penangannya. Koneksi tcp terbuka atau penghitung waktu bisa menjadi generator seperti itu. Jika mereka tidak dapat ditemukan, maka program keluar. Kalau tidak, salah satu dari acara ini diharapkan, penangan dipanggil, dan semuanya berulang.

Konsekuensi dari perilaku ini adalah kenyataan bahwa ketika kode tampaknya berakhir, keluar dari nodejs-vm tidak terjadi, misalnya, karena kami mendaftarkan pengatur waktu, yang harus dipanggil setelah beberapa waktu.

Ini ditunjukkan dalam contoh berikut.

console.log('registering timer callbacks'); setTimeout( function() { console.log('Timer Event 1'); }, 1000); console.log('Is it the end?'); 


hasil:
 registering timer callbacks Is it the end? Timer Event 1 


Baca lebih lanjut di sini.

"Rake" lain dalam kode kita



Semua orang dapat mengelola negara!
Tanda apakah pengguna adalah administrator disimpan dalam variabel global. Variabel ini diinisialisasi ke false pada awal program. Kemudian, ketika administrator mendaftar, variabel ini disetel ke true.

Akibatnya, jika administrator mengunjungi sistem, setiap pengguna yang mengakses instance layanan ini dianggap sebagai administrator.

Saya harus berusaha menunjukkan kepada rekan saya bahwa ada kesalahan dalam logika. Seorang kolega yakin bahwa untuk setiap permintaan http, lingkungan yang sama sekali baru dibuat.


package.json - bidang yang layak diisi



package.json adalah file deskripsi untuk paket kami. Dalam konteks ini, ini tentang aplikasi kita , dan bukan tentang dependensi. Kolom dan penjelasan yang tercantum di bawah adalah alasan mengapa semuanya harus sama.

Teks tersembunyi

nama


Sampai kami mempublikasikan paket di repositori, isian juga dapat dinilai. Pertanyaannya adalah bahwa bidang ini nyaman digunakan untuk menamai file instalasi atau, misalnya, untuk menampilkan nama produk pada halaman web-nya. Secara umum, "apa yang Anda sebut yacht, .."

versi


Gagasan utamanya adalah jangan lupa untuk menambah nomor versi sambil memperluas fungsionalitas, memperbaiki bug, ... Sayangnya, di kantor kami Anda masih dapat menemukan produk dengan versi yang tidak berubah 0.0.0. Lalu coba tebak fungsionalitas apa yang berfungsi untuk klien ...

utama


Bidang ini memberi tahu file mana yang akan diluncurkan saat aplikasi kita mulai (`npm start`). Jika paket digunakan sebagai dependensi, maka file mana yang akan diimpor saat menggunakan modul kami oleh aplikasi lain. Direktori saat ini adalah direktori di mana file `package.json` berada.

Dan juga, jika kita, misalnya, menggunakan vscode , maka file yang ditentukan dalam bidang ini akan diluncurkan ketika debugger dipanggil atau ketika perintah "eksekusi" dijalankan.

Ekstensi ".js" dapat dihilangkan. Ini lebih merupakan konsekuensi dari semua kasus penggunaan yang mungkin, sehingga tidak secara langsung dijabarkan dalam dokumentasi.

mesin


Bidang ini berisi tuple: {"node": version , "npm": version , ...}.

Saya tahu bidang "simpul" dan "npm". Mereka menentukan versi node.js dan npm yang diperlukan agar aplikasi kita berfungsi. Versi diperiksa dengan menjalankan perintah install npm.

Sintaks standar untuk menentukan versi paket dependensi didukung: tanpa awalan (versi tunggal), awalan "~" (dua angka pertama dari versi harus cocok) dan awalan "^" (hanya nomor pertama dari versi harus cocok). Jika ada awalan, versi harus lebih besar dari atau sama dengan yang ditentukan dalam bidang ini. Hanya daftar versi; indikasi eksplisit lebih banyak, lebih sedikit, ... dll. juga berfungsi.

Penafian "Npm install" memeriksa versi yang ditentukan dalam "engine" hanya jika mode "engine-strict" diaktifkan. Kami menyertakannya untuk setiap proyek, menambahkan file .npmrc dengan baris: "engine-strict = true". Sekali waktu, "npm install" melakukan pemeriksaan ini secara default.

Beberapa wadah, setidaknya dalam dokumentasi, menulis bahwa versi yang sesuai akan digunakan secara default. Dalam hal ini, kita berbicara tentang Azure.

Contoh:
 "engines": { "node": "~8.11", // require node version 8.11.* starting from 8.11.0 "npm": "^6.0.1" // require npm version 6.* starting from 6.0.1 }, 


"rake" reguler



Dan raja telanjang!

Berulang kali disepakati dengan klien bahwa versi `node.js` yang diperlukan harus paling tidak 8. Ketika versi awal aplikasi dikirimkan, semuanya berfungsi. "Suatu hari" setelah pengiriman versi baru di klien, aplikasi berhenti berjalan. Semuanya bekerja dalam pengujian kami.

Masalahnya adalah bahwa dalam versi ini kami mulai menggunakan fungsionalitas yang didukung hanya dari versi 8 node.js. Bidang "mesin" tidak diisi, jadi tidak ada yang memperhatikan sebelumnya bahwa klien memiliki versi kuno dari node.js. (Layanan web Azure default).

skrip


Kolom berisi tuple dari formulir: {"script1": script1 , "script2": script2 , ...}.

Ada skrip standar yang berjalan dalam situasi tertentu. Sebagai contoh, skrip "install" akan dijalankan setelah menjalankan "npm install". Sangat mudah, misalnya, untuk memeriksa ketersediaan program yang diperlukan agar aplikasi dapat berfungsi. Atau, katakanlah, untuk mengompres semua file statis yang tersedia melalui layanan web kami sehingga mereka tidak harus dikompres dengan cepat.

Dalam hal ini, Anda tidak dapat dibatasi hanya untuk nama standar. Untuk menjalankan skrip arbitrer, Anda harus menjalankan "npm run script-name ".

Lebih mudah mengumpulkan semua skrip yang digunakan di satu tempat.

Contoh:
  "scripts": { "install": "node scripts/install-extras", "start": "node src/well/hidden/main/server extra_param_1 extra_param_2", "another-script": "node scripts/another-script" } 


PS Ekstensi ".js" dapat dihilangkan dalam banyak kasus.


package-lock.json - membantu menginstal versi dependensi tertentu, bukan yang "terbaru"



Teks tersembunyi
Untuk git atau tidak git? ..


File ini muncul dalam npm relatif baru. Tujuannya adalah untuk mengatur pengulangan perakitan.

dan satu lagi "rake"


Tapi saya tidak mengubah apa pun di program saya! Kemarin dia bekerja!


Pada mesin peer, aplikasi bekerja dengan baik. Di komputer lain di lingkungan yang identik, dalam aplikasi yang ditempatkan dari git ke direktori baru, setelah mengeksekusi 'npm install', 'npm start' sampai sekarang muncul kesalahan yang belum pernah terjadi sebelumnya.

Masalahnya disebabkan oleh fakta bahwa file 'package-lock.json' hilang dari repositori git. Oleh karena itu, selama instalasi paket, semua dependensi level kedua atau lebih (tentu saja, tidak ditulis dalam package.json) dipasang sesegar mungkin. Di komputer seorang kolega, semuanya baik-baik saja. Set versi yang tidak kompatibel dipilih pada komputer yang diuji.

package-lock.json - untuk git!



Kembali dari penyimpangan. File 'package-lock.json' berisi daftar semua modul yang diinstal secara lokal untuk aplikasi kita. Kehadiran file ini memungkinkan Anda untuk membuat ulang satu set modul versi satu-ke-satu.

Rangkuman: jangan lupa untuk memasukkan git dan memasukkannya ke dalam file pengiriman (instalasi) aplikasi!

Berguna: jika file 'package-lock.json' hilang, tetapi ada direktori 'node_modules' dengan semua modul yang diperlukan, file 'package-lock.json' dapat dibuat kembali:
 npm shrinkwrap rename npm-shrinkwrap.json package-lock.json 



Anda dapat mengakhiri ini sekarang. Informasi yang tidak termasuk adalah teknik penyederhanaan kode yang digunakan oleh tim kami.

Jika kesalahan terdeteksi, saya akan mencoba memperbaikinya dengan cepat!

Source: https://habr.com/ru/post/id430972/


All Articles