fix(mobile/telemetry): buffer pre-init events instead of dropping them

Root cause: TelemetryService.initialize() is async (device info collection,
SharedPreferences I/O, remote config sync), taking several hundred ms to
complete. RouteObserver page_view events and auth events fire synchronously
during the initial navigation before initialization finishes, causing the
"TelemetryService not initialized, event ignored" drops seen in logs.

Fix: add _preInitBuffer (max 50 events). logEvent() now enqueues events
instead of dropping when _isInitialized=false. After initialization
completes, all buffered events are replayed in order via logEvent(),
ensuring no startup events are lost.

The network errors ("Failed host lookup: api.gogenex.com") are unrelated —
they are expected in offline test environments and handled gracefully.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-03-07 10:42:53 -08:00
parent 9bcb1f864d
commit 918489e4e5
1 changed files with 44 additions and 1 deletions

View File

@ -45,6 +45,16 @@ class TelemetryService {
bool _isInitialized = false;
bool get isInitialized => _isInitialized;
///
///
/// initialize()
/// RouteObserver/auth
/// replay
///
/// 50
final List<_PendingEvent> _preInitBuffer = [];
static const int _maxPreInitBuffer = 50;
///
late SessionManager _sessionManager;
@ -135,6 +145,16 @@ class TelemetryService {
debugPrint('📊 TelemetryService initialized');
debugPrint(' InstallId: $_installId');
debugPrint(' UserId: $_userId');
// Replay page_viewsession
if (_preInitBuffer.isNotEmpty) {
debugPrint('📊 [Telemetry] Replaying ${_preInitBuffer.length} buffered pre-init events');
final buffered = List<_PendingEvent>.from(_preInitBuffer);
_preInitBuffer.clear();
for (final e in buffered) {
logEvent(e.eventName, type: e.type, level: e.level, properties: e.properties);
}
}
}
/// installId
@ -167,7 +187,15 @@ class TelemetryService {
Map<String, dynamic>? properties,
}) {
if (!_isInitialized) {
debugPrint('⚠️ TelemetryService not initialized, event ignored');
// replay
if (_preInitBuffer.length < _maxPreInitBuffer) {
_preInitBuffer.add(_PendingEvent(
eventName: eventName,
type: type,
level: level,
properties: properties,
));
}
return;
}
@ -394,3 +422,18 @@ class TelemetryService {
_instance = null;
}
}
/// 使
class _PendingEvent {
final String eventName;
final EventType type;
final EventLevel level;
final Map<String, dynamic>? properties;
const _PendingEvent({
required this.eventName,
required this.type,
required this.level,
this.properties,
});
}