feat: ordered startup + Services autoload extraction#2159
Draft
kuruk-mm wants to merge 6 commits into
Draft
Conversation
Addresses Sentry GODOT-EXPLORER-3B (iOS WatchdogTermination, #1532, #1980) by (1) introducing a BootInstrumentation autoload that records every named boot step as a Sentry breadcrumb + last_boot_step tag, (2) extracting all service-like dependencies out of Global into a new Services autoload whose bootstrap() runs under main.tscn's visible splash, and (3) collapsing six autoload entries into children of Services. - BootInstrumentation (new): boot clock, Sentry breadcrumb chain, and on non-prod a CanvasLayer overlay with ephemeral step lines plus a circular RAM-usage indicator pinned outside the safe area (triple-finger / F8 toggle). - Services (new): single registry for every long-lived dependency. Owns 12 GDScript service objects (realm, scene_fetcher, modal_manager, etc.), the 5 previously-autoloaded scripts (ui_sounds, notifications_manager, connection_quality_monitor, impostor_capturer, avatar_lod_coordinator), and forwarding getters (typed where possible) for 19 Rust-inherited singletons on DclGlobal. bootstrap() is awaited from main.gd; heavy work yields process_frame between steps so the iOS watchdog stays responsive. Rust singletons attach under /root/Services rather than /root. - Global: shrunk by ~250 lines. Retains signals, config constants, runtime state (camera mode, height tracking, session_id), CLI / orientation / Sentry-tag setup, and the async_route_to_target_scene branching that used to live in main.gd. - project.godot autoload block: 8 entries -> 3 (BootInstrumentation, Services, Global). - Callsite migration: ~1000 sites swept across 120+ files. UiSounds.* / NotificationsManager.* / ConnectionQualityMonitor.* / ImpostorCapturer.* / AvatarLODCoordinator.* -> Services.<name>.*; Global.realm / Global.player_identity / Global.metrics / Global.config / etc. -> Services.<name>; Global.get_config() -> Services.config. class_name UISounds removed from ui_sounds.gd and from .godot/global_script_class_cache.cfg. - lib/src/scene_runner/global_get_node_helper.rs: get_realm_node now reads /root/Services/realm (was /root/realm) to match the new tree. Validates clean: gdformat, gdlint, check-gdscript (303 scripts, 0 errors). Pending live smoke tests: cargo run -- run, --emulate-ios (portrait + landscape), --itest, --stest, on-device iOS watchdog repro.
…instrumentation # Conflicts: # godot/src/decentraland_components/avatar_attach.gd # godot/src/global.gd # godot/src/logic/scene_fetcher.gd # godot/src/mobile/joystick/virtual_joystick.gd # godot/src/ui/explorer.gd # godot/src/ui/pages/auth/lobby.gd # godot/src/ui/pages/loading_screen/loading_screen.gd # godot/src/ui/pages/loading_screen/loading_screen_progress_logic.gd
Contributor
📦 Build Report🤖 Android
Build Status: ✅ Success 🍏 iOS
🔗 Workflow Run: View logs 🔄 Updated: 2026-06-24 22:06:34 UTC |
…instrumentation # Conflicts: # godot/project.godot
Contributor
🍏 iOS Build Complete✅ Status: Success 🔗 iOS Workflow: View build 📦 Artifacts: godot-mobile-deploy-pipeline 📍 Branch: 🔄 Completed: 2026-06-01 19:11:39 UTC |
…instrumentation # Conflicts: # godot/project.godot # godot/src/connection_quality_monitor.gd # godot/src/decentraland_components/avatar/avatar.gd # godot/src/decentraland_components/avatar/impostor/impostor_capturer.gd # godot/src/global.gd # godot/src/logic/player/player_gamepad_input.gd # godot/src/test/avatar/spawn_and_move.gd # godot/src/ui/components/organisms/profile_settings/profile_settings.gd # godot/src/ui/explorer.gd # godot/src/ui/pages/auth/lobby.gd # godot/src/ui/pages/backpack/backpack.gd # godot/src/ui/pages/discover/discover.gd # godot/src/ui/pages/settings/settings.gd
…tion Main's iOS StoreKit env-report (iap_manager.gd) timed boot-relative telemetry via Global._startup_time, which this branch removed in favor of the BootInstrumentation boot clock. Add BootInstrumentation.boot_elapsed_ms() and use it, fixing the merge fallout (undefined Global._startup_time -> parse error in iap_manager.gd).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Diagnoses + reshapes the boot path for the iOS WatchdogTermination Sentry issue
GODOT-EXPLORER-3B(392 events / 97 users in prod, every release since 0.44; same crash as #1532 / tracked in #1980). Three changes land together:BootInstrumentationautoload — boot clock + Sentry breadcrumb chain +last_boot_steptag on every event. On non-prod, renders an on-screen overlay with ephemeral step lines + a circular RAM-usage indicator pinned outside the safe area (triple-finger / F8 toggle). When a watchdog kill happens, the Sentry event now arrives tagged with the last step that fired.Servicesautoload — single registry for every long-lived dependency. Owns 12 GDScript service objects (realm,scene_fetcher,modal_manager,music_player, …), the 5 previously-autoloaded scripts (ui_sounds,notifications_manager,connection_quality_monitor,impostor_capturer,avatar_lod_coordinator), and forwarding getters (typed where possible) for 19 Rust-inherited singletons onDclGlobal.Services.bootstrap()is awaited frommain.gdunder the visible splash; it yieldsprocess_framebetween heavy blocks so iOS sees a responsive main loop. Rust singletons attach as children of/root/Servicesinstead of/root.Globalshrunk — keeps signals, config constants, runtime state (camera mode, height tracking,session_id), CLI / orientation / Sentry-tag setup, and theasync_route_to_target_scenebranching that used to live inmain.gd. Six autoload entries removed fromproject.godot(down from 8 to 3:BootInstrumentation,Services,Global).Scope
UiSounds.*→Services.ui_sounds.*,Global.realm→Services.realm,Global.get_config()→Services.config, etc.).lib/src/scene_runner/global_get_node_helper.rs—get_realm_nodenow resolves/root/Services/realm(was/root/realm). No other absolute path lookups exist in Rust per audit.class_name UISoundsstripped fromui_sounds.gd; entry removed from.godot/global_script_class_cache.cfg.Why this fixes the watchdog
The previous boot ran
_async_clear_cache_if_needed()plus ~20add_child.call_deferredRust singleton attaches insideGlobal._ready, under the engine's opaque splash — iOS sees the main loop go silent and kills the process. Now those run insideServices.bootstrap()awaited frommain.tscn's visible splash, withawait get_tree().process_frameyields between heavy blocks. The instrumentation also tells us exactly which step is the last one before a kill, so if a watchdog still fires we can target the culprit.Test plan
cargo run -- run— desktop smoke; should reach lobby; step prints monotonic.cargo run -- run -- --emulate-iosand… --emulate-ios --landscape— visual smoke + BootInstrumentation overlay sanity (RAM indicator in the notch channel in both orientations).cargo run -- run --target ios— original repro from [Bug]: iOS sometimes loading too long (shaders?) #1532: open app, wait on splash, lock the phone 30s, unlock. App should survive.cargo run -- run --itest— alternate-mode boot (cli.test_runner) routes throughServices.bootstrap()thenasync_route_to_target_scene().cargo run -- run --stest— same for scene tests.last_boot_steptag values on GODOT-EXPLORER-3B (filtered toenvironment:production). Either the event count drops sharply, or remaining events cluster on one step we can target next.Validated
gdformat godot/— cleangdlint godot/— no problemscargo run -- check-gdscript— 303 scripts, 0 errorsRisk
/root/Services/<Name>. Phase-1 audit confirmed onlyglobal_get_node_helper.rsuses/root/realm; no other absolute-path lookups exist. Patched in this PR.check-gdscriptclean after each batch). No silent class-name shadowing risk (UISoundswas the onlyclass_nameon the demoted scripts; stripped).Related: #1532 (user repro), #1980 (tracking),
GODOT-EXPLORER-3B(Sentry).