fix: delay on exit and exit stopwatch - #8770
Conversation
|
Windows and Mac build successful in Unity Cloud! You can find a link to the downloadable artifact below. |
|
Claude finished @NickKhalow's task in 1m 24s —— View job Code Review
Root-cause CheckProblem: Delay on exit — the PR adds stopwatch instrumentation to Assessment: This PR adds diagnostic logging to identify where delay occurs, not to fix the delay itself. That is a valid approach for an investigation step, but the PR title ("fix: delay on exit") is misleading — there is no delay fix here, only observability tooling. This is acceptable as long as a follow-up PR addresses the actual slow handler once identified. Blocking IssuesLine 17 — First log always prints
Non-blocking Notes
REVIEW_RESULT: PASS ✅ |
|
Claude finished @NickKhalow's task in 2m 44s —— View job Claude finished @NickKhalow's task —— View job Code Review
Root-cause CheckProblem: The exit path has an unknown delay caused by one or more Assessment: This PR replaces the static event with a named, timed cleanup pipeline ( Blocking Issues1.
2. First log always prints
Non-blocking Notes
REVIEW_RESULT: FAIL ❌ |
|
Claude finished @NickKhalow's task in 1m 46s —— View job Code Review
Root-cause CheckProblem: Exit has an unmeasured delay caused by unknown Assessment: The approach is sound — attributing each handler by name and measuring its duration is the correct first step to identify the slow handler. The architecture (named candidates, timed execution, convention enforcement) is well-designed. Blocking Issues1. Only 2. First log always prints
3. The 4. CLAUDE.md: "Use Non-blocking Notes
REVIEW_RESULT: FAIL ❌ |
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com> Signed-off-by: Nick Khalow <71646502+NickKhalow@users.noreply.github.com>
|
Claude finished @NickKhalow's task in 2m 6s —— View job Code Review
Root-cause CheckProblem: The exit path had an unknown delay caused by one or more Assessment: This PR replaces the static event with a named, timed candidate pipeline ( Blocking Issues1.
2. CLAUDE.md: "Use Non-blocking Notes
REVIEW_RESULT: FAIL ❌ |
|
🔍 Claude reviewed this PR and found no blocking issues, but assessed it as complex — human DEV review is still required before merging. |
|
🔍 Claude reviewed this PR and found no blocking issues, but assessed it as complex — human DEV review is still required before merging. |
|
Claude finished @NickKhalow's task in 3m 6s —— View job Code Review
Root-cause CheckProblem: Exit path had no per-handler attribution or timing, making it impossible to identify which cleanup callback caused exit delays. Assessment: This PR instruments the exit sequence with a named, timed cleanup pipeline ( Progress Since Last ReviewAll prior blocking issues resolved ✅
New in this sync:
Blocking Issues
See inline suggestion — revert to the unversioned reference (or pin to a specific commit SHA once Non-blocking Notes
REVIEW_RESULT: FAIL ❌ |
|
Claude finished @NickKhalow's task in 3m 33s —— View job Dependency Security Review
SummaryThis PR contains one dependency change and no binary/plugin/asmdef additions.
No other registry changes. No new Step 1 — Dependency changes visible in the PR
- "com.decentraland.livekit-sdk": "https://github.com/decentraland/client-sdk-unity.git",
+ "com.decentraland.livekit-sdk": "https://github.com/decentraland/client-sdk-unity.git#fix/no_explicit_dispose",
- "version": "https://github.com/decentraland/client-sdk-unity.git",
+ "version": "https://github.com/decentraland/client-sdk-unity.git#fix/no_explicit_dispose",
...
- "hash": "bdb26fbf60fe2ecf0aac83967be8f4c2fa7e7e94"
+ "hash": "e5b8af15a755baf19a2386ae3097bd157743c2f7"Transitive dependencies declared by the package ( Step 1.5 — Registry / repo metadata[Registry metadata] [Registry metadata] Branch
Both commits authored by the PR author ( Step 2 — AssessmentA. Provenance / source trust
B. Runtime capability / attack surface
C. Shipping impact
D. Maintenance / known risk
E. Transitive risk
Notable concerns1. Manifest pins to a branch, not a commit (LOW–MEDIUM)
2. LiveKit SDK change is not described in the PR body (LOW) Step 3 — Risk classificationLOW RISK — official-equivalent (Decentraland-owned fork), minimal scoped change, lockfile pinned, no new binaries or transitive deps, no expanded capability. Step 4 — RecommendationNo blocker. Optional hardening:
DEPENDENCY_REVIEW: PASS · Branch |
|
🔍 Claude reviewed this PR and found no blocking issues, but assessed it as complex — human DEV review is still required before merging. |
|
Claude finished @NickKhalow's task in 2m 57s —— View job Code Review
Root-cause CheckProblem: Exit path had no per-handler attribution or timing, making it impossible to identify which cleanup callback caused exit delays. Assessment: This PR instruments the exit sequence with a named, timed cleanup pipeline ( Progress Since Last ReviewAll prior blocking issues resolved ✅
New in this sync:
Blocking Issues1. Commit 2. The lock hash changed from Non-blocking Notes
REVIEW_RESULT: FAIL ❌ |
|
Claude finished @NickKhalow's task in 2m 49s —— View job Dependency Security Review
SummaryOne dependency change. No new binaries, native plugins, or
Step 1 — Dependency changes visible in the PR
- "com.decentraland.livekit-sdk": "https://github.com/decentraland/client-sdk-unity.git",
+ "com.decentraland.livekit-sdk": "https://github.com/decentraland/client-sdk-unity.git#fix/no_explicit_dispose",
Transitive deps unchanged: No new binary files: pre-fetched binary list is Step 1.5 — Registry/repo metadata[Registry metadata] [Registry metadata] Branch
Key change since round 11: the original "skip explicit FFI dispose" commit that was supposed to be the actual delay fix has been reverted. The current head only contains:
All commits authored by Step 2 — AssessmentA. Provenance
B. Runtime capability / attack surface
C. Shipping impact
D. Maintenance / known risk
E. Transitive risk
Notable concerns1. Manifest still pins to a branch, not a commit (LOW–MEDIUM) — carried from round 11, not addressed
2. Branch name no longer reflects branch content (LOW) — new The commit that gave the branch its name ( 3. PR description still does not mention the LiveKit SDK bump (LOW) — carried from round 11, not addressed The PR body documents Step 3 — Risk classificationLOW RISK on content (proportionate change, no new capability, no binaries, no transitive surface) + MEDIUM on provenance/reviewability (mutable branch ref, branch head already shifted mid-review, missing PR description note). Step 4 — RecommendationThe change itself is fine. The same housekeeping action requested in round 11 remains outstanding and is now reinforced by evidence the branch ref is unstable (its head moved during review):
Add one sentence to the PR description acknowledging the LiveKit bump and what changed ( DEPENDENCY_REVIEW: NEEDS_ATTENTION · Branch |
|
🔍 Claude reviewed this PR and found no blocking issues, but assessed it as complex — human DEV review is still required before merging. |
DafGreco
left a comment
There was a problem hiding this comment.
✔️ PR reviewed and approved by QA on Boh platforms following instructions playing both happy and un-happy path
Regressions for this ticket had been performed in order to verify that the normal flow is working as expected:
- [✔️ ] Backpack and wearables in world
- [✔️ ] Emotes in world and in backpack
- [ ✔️] Teleport with map/coordinates/Jump In
- [ ✔️] Chat and multiplayer
- [✔️ ] Settings
Evidence :
Login screen ✅
CTRL+ALT = Close application ✅
Exit modal in game ✅
X button on windowed mode ✅
20260515-0827-57.8075233.mp4
|
Claude finished @NickKhalow's task in 3m 0s —— View job Dependency Security Review
SummaryThis sync (commit
No new binary files, no new Step 1 — Dependency changes visible in this sync
- "com.decentraland.livekit-sdk": "https://github.com/decentraland/client-sdk-unity.git#fix/no_explicit_dispose",
+ "com.decentraland.livekit-sdk": "https://github.com/decentraland/client-sdk-unity.git",
- "version": "https://github.com/decentraland/client-sdk-unity.git#fix/no_explicit_dispose",
+ "version": "https://github.com/decentraland/client-sdk-unity.git",
...
- "hash": "0254da1fb4491a8deee68e93a5285fca547d9386"
+ "hash": "dc6e479148106b1f8a68f0fbdba475bf7b96693e"Transitive deps unchanged ( Step 1.5 — Registry / repo metadata[Registry metadata] Lock hash [Registry metadata] Files changed upstream between the previous lock hash (
The "skip explicit FFI dispose" approach from earlier commits on the branch was reverted upstream; the merged fix is exclusively the Step 2 — AssessmentA. Provenance ✅
B. Runtime capability / attack surface ✅
C. Shipping impact
D. Maintenance / known risk
E. Transitive risk
Changes since round 12
The round-12 concerns ("branch is a moving target", "branch name no longer describes content") are no longer applicable — the manifest doesn't reference the branch at all anymore. The PR description still accurately describes the bump as "to the Step 3 — Risk classificationLOW RISK. Proportionate change, no new capability, no binaries, no transitive surface, immutable reference via lockfile, default-branch resolution, signed merge commit. Step 4 — RecommendationNo action required for dependency review. Optional nit: update the PR description so it reads "merged upstream PR #68 into the default branch" instead of "switched to the DEPENDENCY_REVIEW: PASS --- · Branch |
|
Claude finished @NickKhalow's task in 3m 13s —— View job Dependency Security Review
SummaryNet dependency change in this PR vs
Step 1 — Dependency changes visible in the PR (vs
|
What does this PR change?
Replaces the simple
ExitUtils.BeforeApplicationQuittingevent with a structured cleanup pipeline that provides per-callback timing diagnostics, thread-safe registration, and reflection-based instrumentation of remainingApplication.quittingsubscribers. Also updates the LiveKit SDK to a branch that avoids explicit dispose issues, and adds UTC timestamps to debug log output for better exit-time correlation.Related PR: decentraland/client-sdk-unity#68
Problem
The previous exit flow used a plain
Actionevent, making it difficult to diagnose which cleanup callbacks contribute to exit delays. There was no protection against re-entrantExit()calls or late registrations during shutdown, and no visibility into third-party or framework-levelApplication.quittingsubscribers.Solution
Structured cleanup pipeline:
OnQuittingCleanUpCandidate— a named cleanup callback that wraps execution with aStopwatchand logs elapsed time viaReportHub.ExitUtilsto maintain a thread-safe (Mutex<List<...>>) registry of cleanup candidates instead of a raw event.Atomic<bool> isExitingguard to prevent re-entrant exits and to reject registrations/unregistrations once shutdown has started.Application.quittingautomatically via[RuntimeInitializeOnLoadMethod], so callers no longer need to wire up the quit event themselves.isExitingin the Editor to handle play-mode re-entry correctly.Reflection-based Application.quitting instrumentation (
Patchinner class):Application.quittingevent.HashSet).RegisterCleanUpCandidate(e.g., third-party code,DCLPlayerPrefsdue to assembly cycle).Quit()inExit()to ensure any late-registered subscribers are also instrumented.Migrated subscribers
UIAudioPlaybackController— switched fromBeforeApplicationQuitting +=toRegisterCleanUpCandidate/UnregisterCleanUpCandidate.WalkedDistanceAnalytics— switched fromApplication.quitting +=toRegisterCleanUpCandidate.TimeSpentInWorldAnalyticsSystem— switched fromApplication.quitting +=toRegisterCleanUpCandidate.UnityObjectUtils— switched fromApplication.quitting +=toRegisterCleanUpCandidate.SentryTransactionManager— consolidated duplicate subscriptions (BeforeApplicationQuitting+Application.quitting) into a singleRegisterCleanUpCandidatecall.DCLPlayerPrefs— cannot use the new API due to an assembly definition cycle (Utility→DCL.PrefsviaPersistentSetting), so it remains on directApplication.quittingwith its own stopwatch logging. The reflection patch also instruments it automatically.Additional changes
DebugLogReportHandler— prepends a UTC timestamp (HH:mm:ss.fff) to every debug log line for better exit-time correlation.com.decentraland.livekit-sdk— updated to thefix/no_explicit_disposebranch ofdecentraland/client-sdk-unityto avoid explicit dispose issues during shutdown.Safety net
VerifyShouldNotUseApplicationQuittingcode convention test that forbids directApplication.quittingusage, with explicit exceptions forExitUtils.csandDCLPlayerPrefs.cs.Test Instructions
Steps (standard run):
Expected result:
RegisterCleanUpCandidate, e.g. `[ExitUtils] 'UIAudioPlaybackController' cleanup took Xms (total Yms)`.Steps (fresh account):
Expected result:
Automation (if applicable):
metaforge explorer test 8770Test Steps
Application.quittingsubscribers.isExitingreset and candidate list clearing).Additional Testing Notes
VerifyShouldNotUseApplicationQuitting) passes and catches any new directApplication.quittingusage.Application.quittingbacking field is inaccessible (graceful fallback with log message).Quality Checklist