Repository navigation
[0.2.2-rc.1][Windows] In-app update still deadlocks at the pendingRequests drain — installDesktopUpdateTaskControl is byte-identical to 0.2.1-rc.5 #12361
meihuaanying
started this conversation in
General
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
TL;DR
In-app update 0.2.1-rc.5 → 0.2.2-rc.1 on Windows x64 still fails with the same dialog:
The download itself is fine. Two byte-level findings from diffing the two shipped
app.asarfiles:installDesktopUpdateTaskControlis byte-identical between 0.2.1-rc.5 and 0.2.2-rc.1 (1284 chars,old === new). Theawait Promise.all(pendingRequests)drain — with no exemption for long-lived responses — is unchanged.lib/main.js,updateTasks()changed only by an added 4th argument (a log label). The budget is still1e4(10000 ms).Consequence: the
process.exit()teardown fix that 0.2.2-rc.1 ships (discussed in #12237) cannot help here. This failure happens beforebackend.stop()is ever reached — it is thrown byupdateTasks("lock"), atlib/main.js:20561, whilebackend.stop()only runs at:20570.Environment
@deepseek-ai/dsh-desktop0.2.1-rc.5 → 0.2.2-rc.1nightly,provider: generic,https://download.deepseek.com/dsh-desk/feeds/win-x64/isAdminRightsRequired: false),D:\program\DSH, no admin rights%LOCALAPPDATA%\@deepseek-aidsh-desktop-updater\pending\deepseek-harness-0.2.2-rc.1-win-x64.exe, 293,425,336 BswcK0J6ofGkaAWLRpOes2ca7CWO8vuM5Vp0FRnQ/DG3q+Z+OhvsgLz3hIiSYpRUETY+fEz+Ww86fNa0jiVIifw=== feednightly.ymlexactly; AuthenticodeValid, signerCN=Hangzhou DeepSeek Artificial Intelligence Co., Ltd.resources/runtime/versions.json)So: not a network problem, not a hash problem, not a disk problem, not a signature problem. The payload was already complete on disk before the retry; I re-verified SHA-512 against the feed by hand.
Where it fails (0.2.2-rc.1 line numbers)
resources/app.asar→lib/main.js:resources/app.asar→dsh/node_modules/@deepseek-ai/dsh-desktop-host/lib/index.js:Every request accepted by the connection waterfall is registered in
pendingRequestsand only settles in thefinally. Any accepted response that stays open for the lifetime of the GUI keepsPromise.all(pendingRequests)pending forever, and the shell gives up at 10 s.Note that in 0.2.1-rc.5 the same function lives at
:108, with the drain at:143— and the extracted function bodies compare equal, so no part of this control was touched by the 0.2.2-rc.1 release.Same function, both versions, 0.2.2-rc.1 on the left:
updateTasks()diff, 0.2.1-rc.5 vs 0.2.2-rc.1:async updateTasks(action) { const response = await this.control({ type: "update-tasks", action - }, 1e4, "desktop update: task inspection timed out"); + }, 1e4, "desktop update: task inspection timed out", "desktop update");What I could and could not confirm
new WebSocket(...)(dsh-api-gateway/lib/client.browser.js:342,dsh-client-connection/lib/client.browser.js:1348), so the main/apievent channel is an HTTP upgrade and does not pass throughconnection/request. Plain/apiRPC calls arePOSTwithrequestBodyMode: "buffered"and therefore do settle.dsh-host-webserver(MCP SSE endpoints, tunnel/proxy plugins, streaming "operation report" channels) or the shell's own long-poll route. This is precisely the part that is undiagnosable after the fact: a timeout writes no log, andinspectandlockshare both the deadline and the message, sotask inspection timed outcannot be told apart fromdrain stuck.dsh-host-webserver/lib/index.js:204-206already detectstext/event-stream— but only inside the gzip filter. That predicate is not reused by the drain, so an SSE response that is perfectly well known to the webserver still counts as a request that must settle.Reproduce
hasDesktopActiveTasksmust be false, otherwise the confirmation dialog asks to stop tasks first — that is a different, successful path).安装更新失败,请稍后重试。with technical detaildesktop update: task inspection timed out. The installer never starts;resources/app.asarstill reports 0.2.1-rc.5; the Host is restarted and the app stays usable.Repeating the click fails identically, because the condition is a property of a live GUI, not a transient state.
Workaround (verified on this machine)
Quit the app completely, then run the already-downloaded, already-verified installer with exactly the arguments
NsisUpdater.doInstall()uses:Result on this machine: installer ran 66 s, exit code 0,
--force-runrelaunched the app itself,app.asarpackage.json →0.2.2-rc.1, registryDisplayName/DisplayVersion→0.2.2-rc.1, no profile or session loss.The catch is that this works only because the process tree is gone; it is not something a user can do from inside the app, and the failure dialog offers no pointer to it.
Suggested fixes
In rough order of value per line changed:
text/event-streampredicate, or let a route declare itself ambient so it is never added topendingRequests. Without this, the guarantee "no request in flight when the installer starts" is unachievable for any GUI whose whole purpose is a live stream.Promise.racethe drain against e.g. 2 s; on expiry return{ active: true, reason: "drain-timeout" }plus the pending count, so the shell renders a true diagnosis rather thaninspection timed out.inspect(must be fast) andlock(drain) currently share1e4and one string; that is why reports like this one and [Bug] Desktop auto-updater fails with "desktop update: task inspection timed out" due to live renderer connection deadlock in installDesktopUpdateTaskControl #10003/[BUG][Desktop 0.2.1-rc.3] 安装更新反复失败:desktop update: task inspection timed out —— 任务排空 10 秒死线过短 #11991/[Bug] macOS 桌面内更新失败:"desktop update: task inspection timed out"(10s 硬超时 / 无日志 / inspect 与 lock 不可区分) #11828 all end up with the same sentence and no way to separate "Host busy" from "drain stuck".update-tasksoutcome to disk by default: action, elapsed ms, admitted count, pending count, settle results. There is currently no update journal unless an env var was set at launch, so every field report has to be reconstructed from static analysis.Relation to existing reports
Duplicate-checked before posting; this is intended as a delta, not a re-report:
await Promise.all(pendingRequests)deadlock (macOS 0.2.1-rc.1→rc.2), plus a Windows confirmation in the comment. I am reusing their analysis; what is new here is that 0.2.2-rc.1 still contains it verbatim.Host did not complete graceful task teardown), a different failing step. Its conclusion "install 0.2.2-rc.1 manually and this path stops reproducing" holds for that path; it does not cover this one, because the lock step fails first and 0.2.2-rc.1 did not change it. Worth stating explicitly so nobody reads "0.2.2-rc.1 fixes the updater" and skips this.ERROR_SHARING_VIOLATION); the workaround happens to coincide.New information contributed by this report:
installDesktopUpdateTaskControlbetween the two shipped asar files, not by observation.process.exit()teardown fix is irrelevant to this path, becauselockfails beforebackend.stop()is called.--force-runself-relaunch, three version sources agreeing afterwards).No usernames, machine names, session contents or tokens are included. If a maintainer wants the extracted
app.asarfragments or the exact byte offsets used for the comparison, I can attach them.All reactions