Repository navigation
Six uloop Editor paths still depend on EditorApplication.delayCall, which some sessions never flush #3168
Description
Summary
Some Editor sessions stop flushing EditorApplication.delayCall while EditorApplication.update keeps running. Four startup paths were already moved off delayCall for that reason, but six other places still schedule their work with it. In such a session that work never runs.
Observed
Found while verifying #3163, in one Editor session on macOS with the Editor in the background:
EditorApplication.delayCallheld 22 pending callbacks: Unity's own startup callbacks (shortcuts, Input System, toolbars, EditorWindow) and uloop's — the server controller's startup recovery,RecoverSettingsFileIfNeeded, and the setup wizard flow.- Two callbacks added later did not run during at least 23 seconds of observation.
- Over the same period a temporary
EditorApplication.updatehandler ran 103 times in 10.1 s. - The uloop server answered commands normally throughout.
What put this session into that state is not known. The trigger recorded in the code is the native "Scripts have compiler errors" dialog at cold start; whether a dialog appeared when this Editor started could not be checked afterwards.
Places that still depend on delayCall
At Editor startup:
UnityCliLoopServerController—ScheduleStartupRecovery(action => EditorApplication.delayCall += () => action(), RestoreServerStateIfNeeded).UnityCliLoopEditorSettingsRecoveryScheduler.ScheduleForEditorStartup—RecoverSettingsFileIfNeeded.SetupWizardStartupFlow.EvaluateVersionChange—_showWindowOnVersionChange(). The check that leads here already runs on the firstupdatetick for exactly this kind of session, but its last step still goes throughdelayCall. In the observed session this callback was pending, so the window was due and never shown.
Later in the session:
UnityCliLoopServerController.OnServerLoopUnexpectedlyExited— recovery after the server loop exits unexpectedly. TheSignalTick()that follows would not have helped in the observed session: every uloop command signals a tick when it queues main-thread work, and the pending callbacks still did not run.CompileLifecycleRecoveryCoordinator—AbortCompileAfterWatchdogFault.UnityCliLoopSettingsWindow.HandleToolToggled—ApplyToolToggleSideEffects(skill synchronization after a tool toggle).
Expected
None of these depends on delayCall being flushed. Each rides on EditorApplication.update with a callback that unsubscribes itself first — the pattern SetupWizardWindow, HotReloadEditorStartup, PausePointEditorStartup, and WatchEditorStartup already use — or goes through the main-thread dispatcher, which runs on both update and tick.
Open questions
- What stops
delayCallin a session without the compile-error dialog, if that is what happened here (for example an Editor that has never been in the foreground). - What a user sees when each skipped callback does not run. In the observed session the server was reachable: after a domain reload it is restored from
afterAssemblyReload, which does not usedelayCall. Whether a cold start depends on thedelayCallpath has not been checked.
Activity