Skip to content

Six uloop Editor paths still depend on EditorApplication.delayCall, which some sessions never flush #3168

Closed

Description

@hatayama

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.delayCall held 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.update handler 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 first update tick for exactly this kind of session, but its last step still goes through delayCall. 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. The SignalTick() 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 delayCall in 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 use delayCall. Whether a cold start depends on the delayCall path has not been checked.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions