Dari 3 Menit ke 500ms: Bug Signup yang Tidak Masuk Akal
Saya memburu delay signup 3 menit yang ternyata adalah user Schrödinger — ada dan tidak ada secara bersamaan karena lag replikasi database antara write dan read.
Kamu tahu perasaan ketika pengguna melaporkan bug yang sama sekali tidak masuk akal? "Aplikasinya butuh 3 menit untuk loading setelah saya signup." Tiga menit? Itu bukan waktu loading, itu istirahat ngopi. Ini cerita tentang bagaimana saya melacak salah satu bug paling aneh dalam sejarah DIALØGUE.
Misteri Dimulai
Semuanya dimulai dengan polos. Pengguna baru mendaftar menggunakan Google SSO, bersemangat mencoba DIALØGUE. Lalu... tidak ada. Yah, tidak sepenuhnya tidak ada — mereka mendapat loading skeleton yang kami desain dengan cantik. Selama tiga menit penuh.
Bagian anehnya? Ini hanya terjadi pada pengguna baru. Pengguna yang sudah ada bisa login seketika. Dan tidak konsisten — kadang 1 menit, kadang 3, sesekali langsung bekerja.
Pikiran pertama saya: "Pasti masalah cold start." (Narator: Bukan masalah cold start.)
Investigasi
Ronde 1: Salahkan Frontend
```typescript
// Tersangka pertama: Hook loading profil
useEffect(() => {
if (user) {
fetchUserProfile(); // Ini yang lama banget
}
}, [user]);
```
Ditambahkan timer di mana-mana. API call memang butuh 3 menit. Tapi kenapa? Backend seharusnya mengembalikan data atau error, bukan hanya... menunggu.
Ronde 2: Salahkan Backend
Menyelam ke Supabase Edge Functions kami:
```typescript
// Edge Function untuk mendapatkan profil user
const { data: profile } = await supabase
.from('users')
.select('*')
.eq('id', userId)
.single();
if (!profile) {
// User baru - buat profil
await createUserProfile(userId);
}
```
Ini terlihat benar. Harusnya cepat, kan? Waktunya tambah logging lagi.
Ronde 3: Plot Semakin Tebal
Setelah menambah log di mana-mana (dan saya maksud di mana-mana), saya menemukan sesuatu yang aneh:
[00:00] User sign in dengan Google
[00:01] Auth trigger aktif - buat user record
[00:01] Frontend minta profil
[00:01] Edge Function query user... TIDAK ADA HASIL
[00:02] Edge Function coba buat user...
[00:02] Database constraint error: User sudah ada
[00:03] Function retry...
[03:00] Function akhirnya timeout
Tunggu, apa? User tidak ada, tapi juga sudah ada? User Schrödinger? T.T
Pengungkapan
Setelah menatap log database sampai mata perih, akhirnya saya melihatnya. Database kami punya proses yang saling berkompetisi:
- Supabase Auth Trigger: Membuat user record saat signup
- Edge Function: Mencoba membuat user kalau tidak ditemukan
- Database Replication Lag: INSERT dari trigger belum tereplikasi ke read replica
Ini yang terjadi:
-- Auth trigger (di primary database)
INSERT INTO users (id, email) VALUES ($1, $2);
-- Edge Function (baca dari replica)
SELECT * FROM users WHERE id = $1; -- Tidak menemukan apa-apa!
-- Edge Function (mencoba membantu)
INSERT INTO users (id, email) VALUES ($1, $2); -- KONFLIK!
Function akan retry dengan exponential backoff, setiap percobaan kena race condition yang sama sampai:
- Replikasi akhirnya terkejar (1-3 menit)
- Function timeout (3 menit)
Update: Penyebab Sebenarnya dan Solusi Akhir yang Robust
Setelah postingan awal, kami terus debugging, dan meskipun perubahan backend kami adalah perbaikan, akar misterinya tetap sulit ditemukan. Terobosan datang ketika kami mengalihkan fokus dari backend ke flow hidrasi dan autentikasi sisi klien.
Penyebab Sebenarnya: Race Condition Sisi Klien
Masalahnya bukan database trigger yang lambat atau Edge Function yang cold start. Masalah sebenarnya adalah race condition klasik sisi klien:
- OAuth Redirect: Pengguna baru sign in dengan Google dan diredirect kembali ke aplikasi kami.
- Async Session: Library klien Supabase (
supabase-js) mulai memproses token dari URL untuk membuat session. Ini proses asinkron. - Premature Render: Tapi aplikasi React kami langsung render. Dia meminta session pengguna sebelum proses asinkron dari langkah 2 selesai.
- Kegagalan: Aplikasi mendapat session
null, menyimpulkan pengguna tidak login, dan merender state kosong atau error. Beberapa saat kemudian, session tersedia, tapi sudah terlambat — UI sudah membuat keputusannya.
Workaround awal kami, seperti menambah retry sisi klien, hanyalah gejala dari melawan race condition fundamental ini.
Solusinya: Satu Sumber Kebenaran untuk Autentikasi
Solusi yang benar dan final adalah merancang ulang manajemen state autentikasi frontend kami agar benar-benar event-driven dan robust.
1. Logic Terpusat di SupabaseProvider:
Kami merefaktor SupabaseProvider kami menjadi satu-satunya sumber kebenaran yang otoritatif untuk autentikasi. Kami menghapus semua listener dan check lain dari hook lain.
2. Menggunakan onAuthStateChange dengan Benar:
Inti dari perbaikan ini adalah mengandalkan secara eksklusif listener onAuthStateChange dari Supabase.
// Logic yang disederhanakan di SupabaseProvider.tsx
export function SupabaseProvider({ children }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true); // Mulai dalam state loading
useEffect(() => {
const { data: { subscription } } = supabase.auth.onAuthStateChange(
(event, session) => {
setUser(session?.user ?? null);
// Kita baru menganggap autentikasi "selesai" setelah listener ini aktif.
setLoading(false);
}
);
return () => subscription.unsubscribe();
}, []);
// ...
}
Pattern ini memastikan seluruh aplikasi tetap dalam state loading sampai Supabase mengonfirmasi session pengguna valid atau null. Tidak ada lagi race condition.
Happy Ending
DIALØGUE sekarang onboarding pengguna baru dalam waktu kurang dari satu detik. Tidak ada lagi istirahat ngopi saat signup. Tidak ada lagi pengguna bingung yang bertanya-tanya apakah mereka merusak sesuatu.
Perbaikan ini sudah di production selama 3 minggu. Nol masalah timeout. Nol race condition. Hanya signup yang mulus dan cepat seperti seharusnya sejak awal.
Apakah worth menghabiskan seminggu debugging ini? Ketika saya melihat pengguna baru dengan lancar membuat podcast pertama mereka dalam hitungan menit setelah mendaftar — tentu saja. :D
Pernahkah kamu melacak bug di mana sesuatu secara bersamaan ada dan tidak ada? Saya merasa setiap developer punya setidaknya satu cerita bug Schrödinger. Saya ingin dengar ceritamu!
Salam,
Chandler
Ingin mencoba signup yang sekarang cepat? Buat podcast AI-mu di DIALØGUE. Saya janji tidak akan butuh 3 menit lagi :)





