Lewati ke konten

Reload Policy Dinamis & Tiering

Rate limiter tradisional membutuhkan restart aplikasi atau lock global mutex untuk memperbarui aturan rate limit. distlimit menghadirkan Engine Dynamic Policy Lock-Free yang didukung oleh atomic.Pointer[Policy] Go untuk pembaruan aturan zero-downtime dan resolusi tier multi-tenant.


Panggil limiter.UpdatePolicy(newLimit, newWindow) di mana saja dalam kode Anda untuk memperbarui limit global secara instan:

package main
import (
"net/http"
"time"
"github.com/balramadan/distlimit"
"github.com/balramadan/distlimit/driver/memory"
)
func main() {
memDriver := memory.New(5 * time.Minute)
// Inisialisasi Limiter dengan aturan default: 100 request per menit
limiter, _ := distlimit.New(
memDriver,
distlimit.WithLimit(100),
distlimit.WithWindow(1*time.Minute),
)
// Endpoint API Admin untuk memperbarui limit secara dinamis
http.HandleFunc("/admin/update-limits", func(w http.ResponseWriter, r *http.Request) {
// Langsung perbarui limit menjadi 500 req/menit saat runtime tanpa jeda lock
limiter.UpdatePolicy(500, 1*time.Minute)
w.Write([]byte("Kebijakan rate limit berhasil diperbarui!"))
})
}
sequenceDiagram
    autonumber
    actor Admin
    participant Limiter as Limiter (atomic.Pointer)
    actor Goroutine as HTTP Worker Goroutines

    Admin->>Limiter: UpdatePolicy(500, 1m)
    Limiter->>Limiter: Alokasi struct Policy baru
    Limiter->>Limiter: atomic.Pointer.Store(&newPolicy)
    Goroutine->>Limiter: AllowKey(ctx, key)
    Limiter->>Goroutine: atomic.Pointer.Load() -> Evaluasi 500 req/m

Karena penggantian pointer dieksekusi via operasi atomik CPU, goroutine worker aktif yang membaca kebijakan mengalami zero lock contention (latensi nanodetik $O(1)$).


👑 Resolusi Tier Multi-Tenant (PolicyResolver)

Section titled “👑 Resolusi Tier Multi-Tenant (PolicyResolver)”

Dalam platform SaaS multi-tenant, tier pengguna yang berbeda (misal Free, Pro, Enterprise) membutuhkan aturan rate limit kustom tanpa perlu membuat instance limiter yang terpisah.

Interface PolicyResolver memungkinkan Anda menyelesaikan aturan Policy dinamis per key secara realtime:

type PolicyResolver interface {
ResolvePolicy(ctx context.Context, key string) (Policy, bool)
}
package main
import (
"context"
"strings"
"time"
"github.com/balramadan/distlimit"
"github.com/balramadan/distlimit/driver/memory"
)
// Implementasi Custom Tier Resolver
type CustomTierResolver struct{}
func (r *CustomTierResolver) ResolvePolicy(ctx context.Context, key string) (distlimit.Policy, bool) {
// Key VIP Enterprise mendapatkan 10.000 request per menit
if strings.HasPrefix(key, "vip:") {
return distlimit.Policy{
Limit: 10000,
Window: 1 * time.Minute,
}, true
}
// Pengguna Pro mendapatkan 1.000 request per menit
if strings.HasPrefix(key, "pro:") {
return distlimit.Policy{
Limit: 1000,
Window: 1 * time.Minute,
}, true
}
// Fallback: kembalikan false untuk menggunakan kebijakan default Limiter
return distlimit.Policy{}, false
}
func main() {
memDriver := memory.New(5 * time.Minute)
// Pasangkan PolicyResolver ke Limiter
limiter, _ := distlimit.New(
memDriver,
distlimit.WithLimit(100), // Kebijakan default untuk pengguna Free / Anonim
distlimit.WithWindow(1*time.Minute),
distlimit.WithPolicyResolver(&CustomTierResolver{}),
)
// Contoh evaluasi:
limiter.AllowKey(context.Background(), "user:123") // Menggunakan limit default (100 req/m)
limiter.AllowKey(context.Background(), "pro:456") // Diselesaikan ke limit Pro (1.000 req/m)
limiter.AllowKey(context.Background(), "vip:789") // Diselesaikan ke limit VIP (10.000 req/m)
}