@@ -47,4 +47,12 @@ Pada tahap ini, kita menyelesaikan masalah *single-thread bottleneck* dengan men
2. Kita menggunakan struktur komunikasi **Channel** (`mpsc::channel`) di Rust. `ThreadPool` bertindak sebagai pengirim pesan (*Sender*), dan setiap `Worker` berbagi akses sebagai penerima pesan (*Receiver*) melalui `Arc<Mutex<Receiver>>` agar aman dari *race condition* antar *thread*.
3. Setiap kali ada koneksi masuk dari browser, fungsi `main` akan memanggil `pool.execute(...)` dan mengirimkan tugas (closure/pekerjaan yang harus dieksekusi) ke dalam *channel*.
4.*Worker* yang sedang menganggur akan menerima tugas tersebut dari *channel* dan langsung mengeksekusinya.
5. Dengan arsitektur ini, jika ada pengguna yang mengakses rute lambat seperti `/sleep`, hanya satu *Worker* yang akan tertidur. Tiga *Worker* lainnya tetap *standby* dan bisa langsung melayani koneksi baru yang masuk secara bersamaan (karena itu tes membuka 2 window secara bersamaan sekarang berhasil tanpa harus antre).
\ No newline at end of file
5. Dengan arsitektur ini, jika ada pengguna yang mengakses rute lambat seperti `/sleep`, hanya satu *Worker* yang akan tertidur. Tiga *Worker* lainnya tetap *standby* dan bisa langsung melayani koneksi baru yang masuk secara bersamaan (karena itu tes membuka 2 window secara bersamaan sekarang berhasil tanpa harus antre).
# Commit Bonus Reflection notes
Pada bagian bonus ini, saya mengganti fungsi `new` pada `ThreadPool` menjadi fungsi `build`. Berikut adalah perbandingan dan alasan perubahannya:
1.**Fungsi `new` (Sebelumnya):** Di Rust, fungsi `new` memiliki conventional yang tidak tertulis, bahwa ia harus **selalu berhasil** membuat dan mengembalikan *instance* dari sebuah struct. Pada kode sebelumnya, jika kita memasukkan parameter `size` bernilai `0`, program akan memanggil makro `assert!` dan seketika mengalami crash. Hal ini bukanlah *design pattern* yang baik untuk sebuah *library* atau public API, karena dapat mematikan program utama pengguna secara paksa.
2.**Fungsi `build` (Perbaikan):** Ketika proses pembuatan *instance* memiliki kemungkinan gagal (misalnya karena validasi *input* yang salah seperti `size == 0`), lebih *idiomatic* di Rust untuk menggunakan fungsi bernama `build` yang mengembalikan tipe data `Result`. Dengan cara ini, jika input bernilai `0`, kita mengembalikan `Err(PoolCreationError)` alih-alih melakukan *panic*.
3.**Dampak:** Penggunaan `build` memberikan fleksibilitas kepada pemanggil (dalam hal ini `main.rs`) untuk menangani *error* tersebut dengan elegan (misalnya dengan mencetak pesan *error* ke *stderr* dan keluar menggunakan `std::process::exit(1)`), membuat server menjadi jauh lebih *robust* dan aman dari *crash* mendadak.