aindrajaya / aindrajaya/node-proxy-server

Perkuat Redis reconnect strategy agar service auto-recover saat Redis restart

Open
#1 0 comments 0 reactions 1 assignee Claimed by @aindrajaya View on GitHub
bug
Dominant language
TypeScript
Stars
0
Forks
0
PR merge metrics
No merged PRs in 30d

Description

## Ringkasan Masalah
Implementasi koneksi Redis saat ini belum cukup robust ketika Redis restart/intermiten. Akibatnya service berisiko gagal recover otomatis walaupun endpoint Redis valid.

## Konteks
- Redis berjalan di Docker dan dipublish ke host (`0.0.0.0:6379->6379/tcp`), sehingga `127.0.0.1:6379` valid.
- Masalah utama ada pada logic reconnect aplikasi, bukan pada alamat Redis.

## Temuan Audit
### 1) `src/db/redis.ts`
Konfigurasi saat ini hanya menggunakan:
- `lazyConnect: true`
- `enableReadyCheck: true`

Belum ada:
- `retryStrategy`
- `reconnectOnError`
- `maxRetriesPerRequest`
- event observability koneksi (`close`, `reconnecting`, `ready`, `end`)

### 2) `src/index.ts`
- `connectRedis()` dipanggil sekali saat startup.
- `connectRedis()` hanya memanggil `redisClient.connect()` jika `status === 'wait'`.
- Kondisi ini berpotensi tidak aman ketika status koneksi berubah ke state lain setelah Redis restart.

## Dampak
- Saat Redis sempat down/restart, proxy berpotensi error berkepanjangan atau tidak recover optimal.
- Risiko gangguan pada fitur yang bergantung pada Redis, seperti:
- token blocklist logout
- cache API key

## Usulan Perbaikan
1. Perkuat opsi koneksi ioredis di `src/db/redis.ts`:
- tambah `retryStrategy` (backoff dengan batas delay)
- tambah `reconnectOnError` (mis. tangani `READONLY`)
- set `maxRetriesPerRequest` sesuai kebutuhan service long-lived
2. Tambahkan event logging lifecycle Redis:
- `connect`, `ready`, `reconnecting`, `close`, `end`, `error`
3. Ubah `connectRedis()` agar tidak hanya memeriksa status `wait` (lebih defensif terhadap state non-ready lainnya).
4. (Opsional) Tambahkan health endpoint/check sederhana untuk observability dan restart PM2 hanya saat service benar-benar unhealthy (bukan restart setiap Redis restart).

## Kriteria Penerimaan
- [ ] Service otomatis mencoba reconnect saat Redis restart tanpa perlu restart PM2 manual.
- [ ] Setelah Redis kembali up, operasi Redis utama (blocklist token & cache API key) kembali normal.
- [ ] Log menunjukkan transisi state koneksi Redis secara jelas (`reconnecting`, `ready`, dll).
- [ ] Tidak ada loop crash aplikasi akibat error koneksi Redis sementara.

## Referensi Patch Awal (contoh)
```ts
import Redis from 'ioredis';
import { config } from '../config';

const MAX_RETRY_DELAY_MS = 5_000;

export const redisClient = new Redis(config.REDIS_URL, {
lazyConnect: true,
enableReadyCheck: true,
maxRetriesPerRequest: null,
retryStrategy(times) {
const delay = Math.min(times * 200, MAX_RETRY_DELAY_MS);
console.warn(`[Redis] Reconnecting attempt #${times}, delay=${delay}ms`);
return delay;
},
reconnectOnError(err) {
if (err.message.includes('READONLY')) return true;
return false;
},
});

redisClient.on('connect', () => console.log('[Redis] Connected'));
redisClient.on('ready', () => console.log('[Redis] Ready'));
redisClient.on('reconnecting', (ms) => console.warn(`[Redis] Reconnecting in ${ms}ms`));
redisClient.on('close', () => console.warn('[Redis] Connection closed'));
redisClient.on('end', () => console.error('[Redis] Connection ended'));
redisClient.on('error', (err) => console.error('[Redis] Error:', err));

export async function connectRedis(): Promise {
if (redisClient.status !== 'ready' && redisClient.status !== 'connect') {
await redisClient.connect();
}
}
```

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.