From 918489e4e5cc91473bace1e153d731aed914db83 Mon Sep 17 00:00:00 2001 From: hailin Date: Sat, 7 Mar 2026 10:42:53 -0800 Subject: [PATCH] fix(mobile/telemetry): buffer pre-init events instead of dropping them MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .../lib/core/telemetry/telemetry_service.dart | 45 ++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/frontend/genex-mobile/lib/core/telemetry/telemetry_service.dart b/frontend/genex-mobile/lib/core/telemetry/telemetry_service.dart index 7da60b0..6272bf9 100644 --- a/frontend/genex-mobile/lib/core/telemetry/telemetry_service.dart +++ b/frontend/genex-mobile/lib/core/telemetry/telemetry_service.dart @@ -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_view、session 启动事件等) + 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? 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? properties; + + const _PendingEvent({ + required this.eventName, + required this.type, + required this.level, + this.properties, + }); +}