Bab 1: Pengenalan tentang Penyelarasan (Retrying) di Go
1.1 Memahami Perlunya Mekanisme Penyelarasan
Pada berbagai skenario komputasi, terutama ketika berurusan dengan sistem terdistribusi atau komunikasi jaringan, operasi dapat gagal akibat kesalahan sementara. Kesalahan-kesalahan ini seringkali merupakan masalah sementara seperti ketidakstabilan jaringan, tidak tersedianya layanan dalam jangka waktu singkat, atau waktu habis. Alih-alih gagal dengan segera, sistem seharusnya dirancang untuk melakukan penyelarasan (retry) terhadap operasi yang mengalami kesalahan sementara. Pendekatan ini meningkatkan kehandalan dan ketahanan.
Mekanisme penyelarasan dapat sangat penting dalam aplikasi di mana konsistensi dan kelengkapan operasi sangat diperlukan. Mekanisme ini juga dapat mengurangi tingkat kesalahan yang dialami pengguna akhir. Namun, mengimplementasikan mekanisme penyelarasan tidaklah mudah, seperti menentukan seberapa sering dan seberapa lama melakukan penyelarasan sebelum menyerah. Di situlah strategi kembali (backoff strategies) memainkan peran yang signifikan.
1.2 Tinjauan tentang Pustaka go-retry
Pustaka go-retry
dalam Go memberikan cara fleksibel untuk menambahkan logika penyelarasan ke aplikasi Anda dengan berbagai strategi kembali. Fitur utamanya meliputi:
- Fleksibilitas: Sama seperti paket
http
dalam Go,go-retry
dirancang agar dapat diperluas dengan middleware. Anda bahkan dapat menulis fungsi penyelarasan Anda sendiri atau menggunakan filter-filter yang disediakan. - Independensi: Pustaka ini hanya mengandalkan pustaka standar Go dan menghindari ketergantungan eksternal, sehingga menjaga proyek Anda ringan.
- Konkurensi: Aman digunakan secara bersamaan dan dapat bekerja dengan goroutine tanpa kerumitan tambahan.
- Sadar konteks: Mendukung konteks asli Go untuk timeout dan pembatalan, dengan integrasi yang lancar dengan model konkurensi Go.
Bab 2: Mengimpor Pustaka-Pustaka
Sebelum Anda dapat menggunakan pustaka go-retry
, pustaka tersebut perlu diimpor ke dalam proyek Anda. Hal ini dapat dilakukan dengan menggunakan go get
, yang merupakan perintah Go untuk menambahkan dependensi ke modul Anda. Cukup buka terminal Anda dan eksekusi:
go get github.com/sethvargo/go-retry
Perintah ini akan mengambil pustaka go-retry
dan menambahkannya ke dependensi proyek Anda. Setelah itu, Anda dapat mengimpornya ke dalam kode Anda seperti halnya paket Go lainnya.
Bab 3: Mengimplementasikan Logika Penyelarasan Dasar
3.1 Penyelarasan Sederhana dengan Backoff Konstan
Bentuk paling sederhana dari logika penyelarasan melibatkan menunggu durasi waktu konstan antara setiap percobaan penyelarasan. Anda dapat menggunakan go-retry
untuk melakukan penyelarasan dengan backoff konstan.
Berikut contoh penggunaan backoff konstan dengan go-retry
:
package main
import (
"context"
"time"
"github.com/sethvargo/go-retry"
)
func main() {
ctx := context.Background()
// Membuat backoff konstan baru
backoff := retry.NewConstant(1 * time.Second)
// Bungkus logika penyelarasan dalam fungsi yang akan dilewatkan ke retry.Do
operation := func(ctx context.Context) error {
// Kode Anda di sini. Kembalikan retry.RetryableError(err) untuk melakukan penyelarasan, atau nil untuk berhenti.
// Contoh:
// err := someOperation()
// if err != nil {
// return retry.RetryableError(err)
// }
// return nil
return nil
}
// Gunakan retry.Do dengan konteks yang diinginkan, strategi backoff, dan operasi
if err := retry.Do(ctx, backoff, operation); err != nil {
// Tangani kesalahan
}
}
Pada contoh ini, fungsi retry.Do
akan terus mencoba menjalankan fungsi operation
setiap 1 detik sampai berhasil atau konteks berakhir atau dibatalkan.
3.2 Mengimplementasikan Backoff Eksponensial
Backoff eksponensial meningkatkan waktu penungguan antara penyelarasan secara eksponensial. Strategi ini membantu mengurangi beban pada sistem dan sangat berguna ketika berurusan dengan sistem skala besar atau layanan cloud.
Cara menggunakan backoff eksponensial dengan go-retry
adalah sebagai berikut:
package main
import (
"context"
"time"
"github.com/sethvargo/go-retry"
)
func main() {
ctx := context.Background()
// Membuat backoff eksponensial baru
backoff := retry.NewExponential(1 * time.Second)
// Sediakan operasi yang dapat diulang kembali
operation := func(ctx context.Context) error {
// Implementasikan operasi seperti yang ditunjukkan sebelumnya
return nil
}
// Gunakan retry.Do untuk menjalankan operasi dengan backoff eksponensial
if err := retry.Do(ctx, backoff, operation); err != nil {
// Tangani kesalahan
}
}
Dalam kasus backoff eksponensial, jika backoff awal diatur menjadi 1 detik, penyelarasan akan terjadi setelah 1 detik, 2 detik, 4 detik, dan seterusnya, meningkatkan waktu tunggu antara penyelarasan berikutnya secara eksponensial.
3.3 Strategi Pengunduran Fibonacci
Strategi pengunduran Fibonacci menggunakan deret Fibonacci untuk menentukan waktu tunggu antara percobaan ulang, yang dapat menjadi strategi yang baik untuk masalah terkait jaringan di mana peningkatan waktu tunggu secara bertahap bermanfaat.
Implementasi pengunduran Fibonacci dengan go-retry
ditunjukkan di bawah ini:
package main
import (
"context"
"time"
"github.com/sethvargo/go-retry"
)
func main() {
ctx := context.Background()
// Membuat pengunduran Fibonacci baru
backoff := retry.NewFibonacci(1 * time.Second)
// Mendefinisikan operasi untuk mencoba ulang
operation := func(ctx context.Context) error {
// Di sini akan berisi logika untuk melakukan tindakan yang mungkin gagal dan perlu dicoba ulang
return nil
}
// Melakukan operasi dengan pengunduran Fibonacci menggunakan retry.Do
if err := retry.Do(ctx, backoff, operation); err != nil {
// Menangani kesalahan
}
}
Dengan pengunduran Fibonacci dengan nilai awal 1 detik, percobaan ulang akan terjadi setelah 1 detik, 1 detik, 2 detik, 3 detik, 5 detik, dll., mengikuti deret Fibonacci.
Bab 4: Teknik Pengulangan Lanjutan dan Middleware
4.1 Memanfaatkan Jitter dalam Pengulangan
Ketika menerapkan logika percobaan ulang, penting untuk mempertimbangkan dampak percobaan ulang simultan pada sistem, yang dapat menyebabkan masalah hewan besar. Untuk mengurangi masalah ini, kita dapat menambahkan jitter acak ke interval pengunduran. Teknik ini membantu mempersempit upaya percobaan ulang, mengurangi kemungkinan beberapa klien memulai percobaan ulang secara serentak.
Contoh penambahan jitter:
b := retry.NewFibonacci(1 * time.Second)
// Mengembalikan nilai berikutnya, +/- 500ms
b = retry.WithJitter(500 * time.Millisecond, b)
// Mengembalikan nilai berikutnya, +/- 5% dari hasil
b = retry.WithJitterPercent(5, b)
4.2 Menetapkan Jumlah Percobaan Maksimum
Dalam beberapa skenario, diperlukan untuk membatasi jumlah percobaan ulang untuk mencegah percobaan ulang yang terus-menerus dan tidak efektif. Dengan menetapkan jumlah percobaan ulang maksimum, kita dapat mengontrol jumlah percobaan sebelum menyerah pada operasi.
Contoh menetapkan percobaan maksimum:
b := retry.NewFibonacci(1 * time.Second)
// Berhenti setelah 4 percobaan ulang, ketika percobaan ke-5 gagal
b = retry.WithMaxRetries(4, b)
4.3 Pembatasan Durasi Pengunduran Individu
Untuk memastikan bahwa durasi pengunduran individu tidak melebihi ambang tertentu, kita dapat menggunakan middleware CappedDuration
. Ini mencegah interval pengunduran yang terlalu lama dihitung, menambahkan ketepatan pada perilaku percobaan ulang.
Contoh pembatasan durasi pengunduran individu:
b := retry.NewFibonacci(1 * time.Second)
// Pastikan nilai maksimumnya adalah 2 detik
b = retry.WithCappedDuration(2 * time.Second, b)
4.4 Mengendalikan Total Durasi Percobaan Ulang
Dalam skenario di mana perlu ada batasan pada durasi total untuk seluruh proses percobaan ulang, middleware WithMaxDuration
dapat digunakan untuk menentukan waktu eksekusi total maksimum. Ini memastikan bahwa proses percobaan ulang tidak berlanjut secara tak terbatas, memberlakukan anggaran waktu untuk percobaan ulang.
Contoh mengendalikan total durasi percobaan ulang:
b := retry.NewFibonacci(1 * time.Second)
// Pastikan waktu total maksimum percobaan ulang adalah 5 detik
b = retry.WithMaxDuration(5 * time.Second, b)