Lonjakan Application Not Responding (ANR) pasca-rilis adalah insiden kritis pada arsitektur React Native di Android. ANR terjadi ketika UI thread (Main Thread) terblokir lebih dari 5 detik saat menangani input pengguna, atau lebih dari 10 detik saat mengeksekusi BroadcastReceiver. Pada runtime React Native, isolasi thread antara JavaScript thread (Hermes) dan Android Main Thread sering kali menyamarkan penyebab utama freeze.
1. Observability: Native Watchdog Timer & Korelasi Stack Trace Hermes
Android crash reporter bawaan hanya menangkap native stack trace saat ANR terpicu via file /data/anr/traces.txt. Untuk mendeteksi thread freeze secara real-time sebelum OS menghentikan proses, aplikasi membutuhkan mekanisme watchdog di sisi native.
Implementasi Native Watchdog Timer
Pola paling efisien adalah mem-post task penanda (tick) ke Looper.getMainLooper() secara berkala dari dedicated background thread. Jika task tersebut tidak dieksekusi dalam batas waktu ambang (misalnya 4000 ms), Main Thread dipastikan mengalami stall.
package com.monitoring.anr
import android.os.Handler
import android.os.Looper
class ANRWatchdog(
private val timeoutMs: Long = 4000L,
private val onAnrDetected: (Thread, Array<StackTraceElement>) -> Unit
) : Thread("ANR-Watchdog-Worker") {
private val mainHandler = Handler(Looper.getMainLooper())
@Volatile private var tick = 0L
@Volatile private var isRunning = true
override fun run() {
while (isRunning) {
val startTick = tick
mainHandler.post { tick = startTick + 1 }
try {
sleep(timeoutMs)
} catch (e: InterruptedException) {
return
}
// Jika tick tidak berubah, UI thread terblokir selama >= timeoutMs
if (tick == startTick) {
val mainThread = Looper.getMainLooper().thread
onAnrDetected(mainThread, mainThread.stackTrace)
}
}
}
fun terminate() {
isRunning = false
interrupt()
}
}Korelasi Hermes JS Stack Trace di Sentry
Ketika Main Thread terblokir, root cause sebenarnya bisa berada di JavaScript Thread (mqt_js) yang membanjiri message queue atau memanggil method JSI/Bridge secara sinkron. Konfigurasi @sentry/react-native harus mengaktifkan tracking ANR native sekaligus Hermes sampling profiler:
import * as Sentry from "@sentry/react-native";
Sentry.init({
dsn: "https://[email protected]/0",
enableAppHangTracking: true, // Deteksi app hang di iOS
enableNativeFramesTracking: true,
// Integrasikan ANR detection native Android
anrDetection: {
enable: true,
timeoutInterval: 4000,
captureScreenshots: false,
},
_experiments: {
profilesSampleRate: 0.2, // Profiler Hermes untuk melacak execution stack JS
},
});Saat native ANR watchdog mentransmisikan exception ke Sentry, Sentry mengkorelasikan native thread dump dengan sampling profiler Hermes terakhir. Ini memperlihatkan fungsi JavaScript mana yang berjalan tepat sebelum event freeze terjadi.
2. Postmortem: Root Cause Tipikal ANR di React Native
Berdasarkan data runtime, ANR pada React Native umumnya terbagi menjadi dua skenario:
A. Sinkronisasi Data Berat pada Render Phase
Komponen React Native yang melakukan parsing payload JSON besar (misalnya cache lokal SQLite/MMKV) langsung di dalam siklus render() atau synchronous layout evaluation. Ketika ratusan node komponen ter-mount bersamaan, Hermes runtime membebani bridge untuk pengiriman instruksi layout ke Yoga engine di native thread, menghabiskan alokasi waktu Choreographer.
B. Blocking Bridge / TurboModule Sinkron
Penggunaan metode native module beranotasi @ReactMethod(isBlockingSynchronousMethod = true) atau fungsi C++ TurboModule via JSI yang memanggil I/O (disk/network) langsung di thread pemanggil tanpa memindahkannya ke thread pool terpisah (seperti Dispatchers.IO).
3. Prosedur Mitigasi Cepat dan Rollback
Saat terjadi lonjakan ANR mendadak pasca-rilis, investigasi kode membutuhkan waktu. Lakukan containment segera menggunakan dua jalur paralel:
Halt Staged Rollout via Google Play Developer API
Jika rilis dilakukan via staged rollout (misal 10%), hentikan rollout melalui API untuk mencegah paparan ke lebih banyak user tanpa menunggu pembukaan UI browser console:
PUT https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/edits/{editId}/tracks/production
Authorization: Bearer {access_token}
Content-Type: application/json
{
"releases": [
{
"name": "Release-2.1.0",
"versionCodes": ["20100"],
"status": "HALTED"
}
]
}Eksekusi Remote Kill-Switch
Jika fitur penyebab ANR terisolasi di JavaScript layer (misalnya flow checkout baru), jangan tunggu proses review binary Google Play yang membutuhkan waktu 12–48 jam. Nonaktifkan logic menggunakan Remote Feature Flag / Config service:
function ProductCheckoutFlow(props) {
const isNewEngineEnabled = useFeatureFlag("kill_switch_checkout_engine_v2");
if (!isNewEngineEnabled) {
return <LegacyCheckoutFallback {...props} />;
}
return <OptimizedCheckoutV2 {...props} />;
}4. Tindakan Pencegahan & Rekayasa Reliabilitas
Terapkan guardrail struktural agar regresi ANR terdeteksi sebelum aplikasi dipromosikan ke tahap rilis publik:
- Offload Komputasi ke Background Worklet: Operasi manipulasi array besar atau parsing data intensif harus dialihkan keluar dari JS event loop utama menggunakan pustaka seperti
react-native-worklets-coreatau offloading ke Native Worker threads. - Guardrail Android Vitals di CI/CD: Google Play Console menetapkan bad behavior threshold untuk ANR pada angka 0.47% (per-user basis). Integrasikan Play Developer Reporting API ke pipeline alert tim untuk mentrigger rollback otomatis bila metric melewati ambang 0.35%.
- Profiling Frame Drop di QA Stage: Validasi user journey kritis menggunakan Flashlight atau Android
dumpsys gfxinfodalam script integration test (e.g., Maestro) untuk mendeteksi jank dan Looper stalls sebelum masuk ke tahap deployment:
# Eksekusi profiling jank frame via ADB
adb shell dumpsys gfxinfo com.example.app reset
# Jalankan interaksi automated test...
adb shell dumpsys gfxinfo com.example.appEvaluasi metriks Janky Frames dan Number of Slow UI Thread frames pada output reporting. Frame execution time di atas 700ms pada Main Thread adalah indikator awal potensi ANR di perangkat low-end.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!