# Solusi: URL Berbeda untuk Masing-Masing Transaksi

## Opsi 1: URL Berbeda Berdasarkan Type (SALES_INVOICE vs SALES_RECEIPT)

**Idea:** Pakai URL berbeda untuk SALES_INVOICE dan SALES_RECEIPT agar tidak saling blocking.

### Implementasi

**1. Update Config:**

```go
// config/config.go
type Config struct {
    // ... existing fields ...
    SharedHostingURLInvoice string  // URL untuk SALES_INVOICE
    SharedHostingURLReceipt string  // URL untuk SALES_RECEIPT
    SharedHostingURL        string  // Fallback/default URL
}
```

**2. Update Worker:**

```go
func (p *Pool) forwardToSharedHosting(payload interface{}, webhookType string) error {
    var url string
    
    // Pilih URL berdasarkan type
    switch webhookType {
    case "SALES_INVOICE":
        url = p.config.SharedHostingURLInvoice
    case "SALES_RECEIPT":
        url = p.config.SharedHostingURLReceipt
    default:
        url = p.config.SharedHostingURL
    }
    
    if url == "" {
        url = p.config.SharedHostingURL // Fallback
    }
    
    if url == "" {
        return fmt.Errorf("shared hosting URL empty")
    }
    
    // ... rest of forward logic ...
}
```

**3. Setup di Shared Hosting:**

- `receiver-invoice.php` → Handle SALES_INVOICE
- `receiver-receipt.php` → Handle SALES_RECEIPT

**Keuntungan:**
- ✅ Tidak saling blocking (SALES_INVOICE dan SALES_RECEIPT punya jalur sendiri)
- ✅ Bisa di-scale terpisah
- ✅ Mudah debug (log terpisah)

**Kekurangan:**
- ⚠️ Perlu maintain 2 file receiver.php
- ⚠️ Konfigurasi lebih kompleks

---

## Opsi 2: URL Berbeda Berdasarkan Database ID

**Idea:** Pakai URL berbeda berdasarkan `databaseId` untuk load balancing.

### Implementasi

```go
func (p *Pool) forwardToSharedHosting(payload interface{}, webhookType string, databaseID int64) error {
    // Pilih URL berdasarkan database ID (round-robin atau hash)
    urls := []string{
        p.config.SharedHostingURL,
        p.config.SharedHostingURL2, // Optional second URL
        p.config.SharedHostingURL3, // Optional third URL
    }
    
    // Hash database ID untuk konsistensi
    urlIndex := int(databaseID) % len(urls)
    url := urls[urlIndex]
    
    // ... rest of forward logic ...
}
```

**Keuntungan:**
- ✅ Load balancing otomatis
- ✅ Bisa scale horizontal

**Kekurangan:**
- ⚠️ Perlu setup multiple receiver.php di server berbeda
- ⚠️ Kompleksitas tinggi

---

## Opsi 3: Sequential Processing untuk Shared Hosting (Lebih Sederhana)

**Idea:** Jangan kirim concurrent requests ke shared hosting, tapi sequential (satu per satu).

### Implementasi

**Tambahkan mutex untuk serialize forward ke shared hosting:**

```go
type Pool struct {
    // ... existing fields ...
    forwardMutex sync.Mutex  // Mutex untuk serialize forward
}

func (p *Pool) forwardToSharedHosting(payload interface{}, webhookType string) error {
    // Lock mutex - hanya 1 forward dalam 1 waktu
    p.forwardMutex.Lock()
    defer p.forwardMutex.Unlock()
    
    // ... rest of forward logic ...
}
```

**Keuntungan:**
- ✅ Sederhana (tidak perlu URL berbeda)
- ✅ Tidak ada race condition di shared hosting
- ✅ Shared hosting tidak overload

**Kekurangan:**
- ⚠️ Lebih lambat (sequential, bukan parallel)
- ⚠️ Bisa jadi bottleneck jika banyak webhook

---

## Opsi 4: Rate Limiting (Paling Direkomendasikan)

**Idea:** Batasi jumlah concurrent requests ke shared hosting, tapi tetap parallel.

### Implementasi

**Tambahkan semaphore untuk limit concurrent forwards:**

```go
type Pool struct {
    // ... existing fields ...
    forwardSemaphore chan struct{}  // Semaphore untuk limit concurrent
}

func NewPool(cfg *config.Config, db *sql.DB) *Pool {
    return &Pool{
        // ... existing fields ...
        forwardSemaphore: make(chan struct{}, 3), // Max 3 concurrent forwards
    }
}

func (p *Pool) forwardToSharedHosting(payload interface{}, webhookType string) error {
    // Acquire semaphore (block jika sudah 3 concurrent)
    p.forwardSemaphore <- struct{}{}
    defer func() { <-p.forwardSemaphore }()
    
    // ... rest of forward logic ...
}
```

**Keuntungan:**
- ✅ Tetap parallel (tidak sequential)
- ✅ Tidak overload shared hosting
- ✅ Sederhana (tidak perlu URL berbeda)
- ✅ Bisa di-tune (ubah max concurrent)

**Kekurangan:**
- ⚠️ Bisa jadi bottleneck jika shared hosting lambat

---

## Rekomendasi

**Jika pesannya aman semua (tidak ada error):**

1. **Cek dulu apakah masalahnya di receiver.php:**
   - Apakah semua di-skip karena DFT?
   - Apakah ada error di receiver.php yang tidak di-log?
   - Apakah idempotency check skip semua?

2. **Jika memang perlu solusi teknis:**
   - **Opsi 4 (Rate Limiting)** → Paling sederhana dan efektif
   - **Opsi 1 (URL Berbeda per Type)** → Jika memang perlu isolasi

**Jika ada error di forward:**
- Fix masalah root cause dulu (network, timeout, dll)
- Baru pertimbangkan solusi di atas

---

## Implementasi Opsi 4 (Rate Limiting) - Recommended

Saya akan implementasikan Opsi 4 karena paling sederhana dan efektif. Mau saya implementasikan sekarang?
