
Qwen Code 多守护进程共享会话Relaxed Standalone Daemon Ownership 设计与实现解析【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code导读在 Qwen Code 的qwen serve架构中Conversations 运行时承载 Standalone 会话、Live Voice 与定时任务过去由用户级全局进程 owner把持导致 Web Shell 连到第二个守护进程时即使只是浏览会话目录也会收到503 conversation_runtime_in_use。本文基于设计文档 2026-09-02-relaxed-standalone-daemon-ownership.md系统讲解 Qwen Code 如何通过取消进程级 owner 强制会话级 writer lease 本地身份域限定回收 Live 精确发布者准入四层机制实现多个守护进程在同一用户、同一台机器上并发服务不同会话的会话分区并发契约session-partitioned concurrent-use contract。读完本文你将掌握该机制的完整行为契约、错误码语义、源码实现落点以及升级回滚注意事项。背景阅读该设计是 standalone-daemon-sessions.mdIssue #8908中跨守护进程拥有权要求的演进其落地与验证追踪见 2026-09-06-conversations-ownership-cutover.md。背景与动机为什么不能保留全局 owner在旧模型下qwen serve进程在处理 standalone 或 Live 请求前会先获取一个用户全局的进程 owner 记录conversations/runtime-owner.json内含version、pid、instanceNonce。这带来一个实际问题第一个碰过 standalone/Live 的守护进程会阻塞其他所有存活守护进程的 standalone 访问连接在第二个守护进程上的 Web Shell 即使只需要共享目录、新建聊天或操作另一个会话也会收到503 conversation_runtime_in_use。而普通 workspace 并没有这种进程级 runtime owner——多个守护进程可以同时指向同一个持久化 workspace。设计文档因此主张更简单、更一致的策略让每个守护进程独立服务各自的会话把真正共享写入的边界交给既有的跨进程会话 writer 协议。核心决策从进程级 owner 到会话级 lease本设计做出的核心决策是允许每个更新的qwen serve进程在 legacy 兼容检查通过后惰性地为共享 Conversations 根目录创建自己的 Conversations 运行时守护进程在服务 standalone API 前不再获取用户级进程 owner每个 standalone 会话在写入前必须获取既有的跨进程会话 writer lease。对齐效果是standalone 启动方式与普通 workspace 启动方式一致——多个守护进程可指向同一持久化 workspace但各自保留自己的 ACP bridge、子进程、live-session 索引、缓存与 runtime generation。需要特别强调的是这是会话分区并发使用契约而非无限制的多主支持更新的守护进程可以并发列出共享目录、创建会话、承载不同的会话 ID同一会话的竞争写入者与生命周期变更仍由该会话的 writer lease 串行化本变更不新增跨守护进程路由、共享 live-state 索引、原子多会话操作或分布式缓存失效。Live 激活仍然是一个机器全局例外只有 PID 与 instance nonce 精确匹配稳定 Live 发现记录的守护进程才能启动或替换 Live 通话其他更新的守护进程仍可服务 standalone 会话但其/live/start与/live/new请求继续返回可重试的503 conversation_runtime_in_useHost 发起的 toggle/new 动作也会在通话激活前被拒绝。行为契约详解设计文档给出了一条完整的可观察行为清单核心条款如下GET /standalone/session-options与所有/standalone/sessions路由可以在另一个更新守护进程存活时初始化本地 Conversations 运行时。更新后的守护进程不再仅因对方进程存活而产生conversation_runtime_in_use迁移期间若存在存活的 legacy runtime-owner 记录仍返回该错误直到旧守护进程退出。若守护进程 A 已加载会话 S守护进程 B 仍可列出共享目录、新建 standalone 会话并可创建/恢复/使用未被其他 writer 持有的另一个会话。不同会话 ID 可以同时在多个守护进程中处于活跃状态。客户端始终附着在它创建或恢复活跃会话的那个守护进程上prompt、cancel、permission、status、heartbeat、detach、SSE 事件路由不会转发到其他守护进程。创建或恢复 standalone 会话时无条件获取会话 writer lease与用户experimental.sessionWriterLease设置无关第二个守护进程尝试打开同一活跃会话时收到既有的409 session_writer_conflict。单会话重命名/修复使用同一顶层响应批量生命周期路由保持200结果外壳但在受影响条目的errors[]中保留 writer 错误类型。由 Conversations 运行时承载的所有其他会话包括 Live 与定时任务会话同样强制使用 lease防止后台 keepalive 或任务再水合静默恢复已活跃的 transcript。Live 发现与 Live 激活保持单发布者非发布者守护进程的/live/start、/live/new与 Host 发起动作全部失败。未密封的活跃锁仅当新守护进程能证明记录属于同一本地身份域同一 hostnameLinux 上还要求同一 boot 与 PID namespace且记录的进程已退出或 PID 被复用时才可回收存活进程包括停滞进程永远被 fenced。lease 持有者是 ACP writer 进程本身而非其守护进程父进程。若守护进程父进程死亡但子进程以匹配身份存活其他守护进程仍被 fenced直到该 writer 退出或被终止。持久化会话切换到另一守护进程的正常路径是协作式 writer 交接显式关闭会话或正常 idle reap 释放 lease优雅的受管守护进程关机会密封它使继任者走既有的 certified-takeover 协议。非协作退出是身份限定回收这一狭窄例外。两条路径都执行冷恢复cold restore而非热迁移。守护进程只有在解析到相同 Conversations 根与 runtime base 时才共享持久化 standalone 会话自定义 runtime base 保持与普通 workspace 相同的存储隔离。支持的拓扑一台机器上、同一 OS 用户下的多个守护进程。跨物理机器共享稳定状态基存放 Live locator、legacy owner 工件、删除日志或共享 runtime 基存放 transcript 与 writer 锁不在契约之内——这是承载性边界而非装饰性说明能被多台机器访问的稳定基会把 Live locator 从机器全局选举变成文件系统全局选举且 Darwin/Windows 的回收规则没有 boot/namespace 分量来区分共享同一 hostname 的两台主机。跨进程目录变更通过既有持久化会话缓存最终可见live state 只从接收方守护进程合并因此守护进程 B 可能把 A 中活跃的会话列为已持久化但未激活直到恢复尝试返回session_writer_conflict。源隔离不变standalone 的列出、恢复、生命周期路由只接受顶层 standalone 记录对 Live-owned 或其他外来记录保持 fail closed。并发后台清理同一删除日志条目时由该会话的生命周期 writer lease 串行化遇到session_writer_conflict的扫描把该条目视为由另一守护进程处理跳过该 UUID 继续不把争用转换为 compromised-record 结果。两个守护进程同时再水合同一定时任务绑定会话时强制 writer lease 只允许一个驻留会话失败的再水合通过既有再水合结果与错误上报路径记录恢复失败然后按既有 keepalive 退避且不会触发该会话的任务。同会话排他性覆盖完整的活跃会话生命周期而非仅重叠的 HTTP 请求只要会话仍加载在守护进程 A 中即便 A 在请求间隙空闲也不能通过守护进程 B 继续或变更它。保留的安全基线移除进程 owner 并不会把 Conversations 根目录降级为普通用户选择的 workspace。实现仍保留精确的 Conversations-root 校验与目录身份检查内部运行时隔离与禁止回退到主运行时primary-runtime fallback每守护进程 runtime generation、活动排空与终末隔离terminal quarantine各守护进程内的每会话生命周期协调持久的 standalone 删除日志与恢复检查生命周期变更既有 writer lease整个 Conversations 运行时的强制活跃会话 writer lease可证明同域陈旧活跃锁的身份限定回收迁移期 legacy runtime-owner 兼容检查Live discovery 的单发布者记录与校验只接受精确稳定 locator 发布者的 Live-start 准入。守护进程本地的创建准入、live owner 索引、生命周期协调器、回收 singleflight 与缓存失效都不是跨进程权威——它们可能让远端 live state 看似不活跃或延迟目录新鲜度但不决定写入所有权。工作目录身份 pin 仅在其匹配的本地 bridge 会话 generation 驻留期间、或在该生命周期操作获取会话 lease 后的一次变更内具有权威性没有匹配本地 generation 的 pin 会在再次检查目录前被丢弃且不会把另一守护进程安全重建的目录误判为working_directory_compromised。实现剖析设计文档用一张表明确了三个行为门gate及其替换方案ConsumerReplacementStandalone 访问共享运行时无进程级门会话 writer 与生命周期操作使用强制 writer lease定时任务激活绑定会话的强制 writer lease加上下述未绑定任务资格与绑定事务机器全局 Live 激活每次 Live 启动路径前的精确稳定 locator 发布者准入同时acquire 的状态目录引导bootstrap与稳定 Live 交接副作用被分别移到删除日志与 Live 发布路径没有任何 consumer 再隐式依赖被移除的 lifetime owner。1. 外层 owner 替换为 legacy 兼容检查ConversationRuntimeManager不再接受长期存活的ConversationRuntimeOwnership依赖也不再在ensure()中调用acquire()。在创建第一个本地 Conversations 运行时之前它只调用只读的 legacy runtime-owner 兼容检查运行时创建仍会在发布本地受管运行时前重新校验精确根目录。从源码看conversation-runtime-manager.ts 的ensureOnce()在未发布 runtime 时首先执行this.options.checkLegacyOwner()第 114 行之后才revalidateRoot()并发布而 conversation-runtime-ownership.ts 导出的checkLegacyConversationRuntimeOwner()复用了 owner 目录身份检查、目录锁.runtime-owner.lock、严格 version-1 记录解析、PID 存活规则、精确记录清理、持久化 sync 与交接宽限期。其语义为有效记录且 PID 仍存活 →conversation_runtime_in_use有效陈旧记录 → 在目录锁下移除并重新检查后继续畸形、不安全或不确定状态 → 保持既有的 compromised / unavailable 失败。该检查从不写入新的 owner 记录也不参与 Live discovery 交接它是该守护进程 generation 的一次性检查运行时发布后不再重复因此无法探测之后才创建的 legacy owner 记录——设计文档在排空并切换drain-and-cutover要求下接受该局限而不是引入 owner 轮询或运行时只读降级。createServeApp只构造兼容检查器不再向ServeAppLifecycleController挂接 Conversations owner——生命周期控制器在关停后不再有 Conversations 拥有权需要释放。2. 强制 Conversations 运行时的 writer lease强制点选在**运行时来源边界runtime-provenance boundary**而非会话源边界当守护进程构建验证来源为live-conversation的 workspace 运行时其 bridge 会向该运行时的 ACP 子进程环境添加一个私有、仅启用的 markerprimary、secondary、scratch 与其他普通 workspace bridge 不接收它。CLI 入口点在首次 await 或加载环境文件之前捕获并删除该私有 marker与既有私有父能力并列。它仅在 ACP 模式、能力存在且值精确匹配启用值时接受sandbox 重启动会随私有能力一起携带已接受的 marker普通重启动则不会。入口点把结果作为内部布尔值传给runAcpAgent而不是让 agent 读取可变进程环境。runAcpAgent把该布尔值并入既有的进程启动 writer 快照有效值为受信 runtime marker 被接受或用户启动设置启用 lease二者之一。每次请求的设置重载继续使用该冻结值因此一个 ACP 进程不会混用 leased 与 legacy writer。对于携带 Conversations marker 的受信受管子进程runAcpAgent设置reclaimPolicy: local并保留takeoverPolicy: certified其他受信受管 workspace 子进程保持reclaimPolicy: never。源码证据见 acpAgent.tsconversationsRuntimeProvenance布尔同时驱动强制 lease 与回收策略选择如第 14476-14480 行附近this.conversationsRuntimeProvenance ? local : never。守护进程的共享子进程环境覆盖默认移除marker然后live-conversationbridge 把未定义值替换为启用值同时把该键加入硬编码的项目环境排除列表防止 workspace.env或设置重载重新引入它。CLI 入口点在初始设置与环境加载后再次删除该键防止用户级.env值泄漏到工具或后续子进程。这使 standalone独立于用户配置不引入公开设置或命令行标志marker 限定在一个 bridge 上从而覆盖专用运行时承载的所有来源standalone、Live、定时任务 controller 与 run 会话因为基于 source 的覆盖会漏掉持久化 source 非standalone的后台会话。createAcpSessionBridge从两个条件合取推导出不可变的强制 lease 证明attestation冻结的子进程环境覆盖携带精确 Conversations marker且所选channelFactory携带转发能力由createSpawnChannelFactory经scrubChildEnv合并第二参数并打上包所有、不可变的转发能力标记。每次 spawn 前 bridge 将冻结覆盖与新鲜私有父能力合并进工厂参数映射。ConversationRuntimeManager在其 owned-runtime 校验中包含该证明缺失或错误的证明是静态运行时契约违例——新候选被拒绝并 dispose等价既有已注册运行时被终末隔离隔离的终末原因固定为不可重试的conversation_root_compromised后续每次ensure()或当前运行时断言都重新抛出同一错误而不降级为可重试的conversation_runtime_unavailable。源码证据见 conversation-runtime-manager.ts隔离原因为missing_mandatory_lease_attestation第 21 行该原因映射到conversationRootCompromisedError()第 88-93 行并在ensure()的终末分支与运行时校验第 222 行runtime.bridge.mandatoryLeaseAttested ! true中强制执行。ACP 会话必须在配置初始化期间、报告创建或恢复成功之前获取 lease并持有到会话关停复用既有的session_writer_conflict、session_writer_lost、session_transcript_changed、session_writer_unavailable映射。StandaloneSessionService的工作目录身份 pin 限定为一个本地驻留 bridge 会话 generation借助agentBound.eventEpoch只有当 bridge 仍报告同一 standalone 会话与 epoch 时才把 pin 复用作expected身份终末关闭留下的裸{ pinned }、idle reap 后缺失的会话或不同 epoch 均为孤儿 pin必须在恢复/修复/删除检查等维护路径检查目录前移除。若没有匹配的本地 generation 剩余open/repair 应用既有精确根、直接子、所有权、非符号链接与权限检查不带陈旧expected身份采纳当前安全目录身份ACP 子进程再获取 writer lease生命周期操作关闭本地会话时丢弃会话 pin、获取父侧生命周期 lease然后才为文件系统变更捕获新鲜的操作本地目录身份。既有受驻留 generation 或操作本地身份的变更仍是working_directory_compromised只有孤立的守护进程本地 pin 可被替换。StandaloneSessionService的父侧生命周期与维护获取含删除日志回收同样选择加固后的local策略普通 workspace 生命周期路由与其他受管运行时保持never。值得强调的是lease 保护一个 transcript 及其生命周期不协调会话列表读取、随机 ID 生成、守护进程本地受管目录状态、SSE 路由或 Live discovery且 fence 只覆盖更新后、协作的、由标记 Conversations 运行时承载的 writer——不获取协议 lease 的 legacy 守护进程或其他进程仍可绕过它。lease 是完整性协议不是操作系统访问控制边界。3. 只回收可证明陈旧的本地活跃 writer在把local回收策略用于受管 Conversations writer 之前Core 先加固它。源码证据见 session-writer-lease.tsLinux 上活跃 schema-version-2 记录在既有 hostname 与process_start_identity已含 boot ID 与进程启动 ticks之外新增可选pid_namespace_idwriter 在平台暴露时记录两个身份。读者把缺少任一身份的旧记录或新记录都视为存活绝不自动回收。复用 Core 的readPidNamespaceId()、readLocalBootId()与保守 PID 存活行为同时保留 writer lease 既有持久化process_start_identity格式。EPERM/EACCES仍视为存活只有PID 被证明不存在、经校验的僵尸或可读的启动身份不匹配能在身份域检查通过后支撑陈旧判定。判定逻辑见lockStateForRecord()第 499-530 行hostname 不匹配 → liveLinux 上 boot ID 或 PID namespace 缺失/不匹配 → livePID 不存在 → stale无启动身份 → live启动身份可读且不同 → stale否则 live。实现复用既有回收守卫、精确记录重读、原子陈旧记录移动与判定后的 transcript 校验从不依据锁年龄、获取时间、心跳缺失或守护进程响应性作决定。Darwin 与 Windows 保留各自的进程启动探测要求精确 hostname 与已记录启动身份PID 确定不存在 → stalePID 存活但当前启动身份可读且不同 → stale任一判定所需身份不可用或平台不支持身份探测 → 记录对回收而言保持存活。因此这两个平台依赖行为契约中的单机拓扑无 boot/namespace 分量时精确 hostname 就是整个身份域共享 hostname 与 runtime base 的两台主机可能把对方存活的 writer 判定为本地缺失 PIDLinux 额外用 boot ID 与 PID namespace 隔离。启动身份匹配存活的 PID 保持session_writer_conflict即使事件循环停滞外来 host/boot/namespace、无身份、畸形、非普通文件与不确定记录一律 fail closed。local策略只作用于未密封的活跃记录密封记录仍需 certified transcript takeover。任何过渡声称transition claim包括残余的都绝不基于进程存活被回收。正常每会话关闭会移除其精确活跃记录优雅受管关停持久化密封记录其他受管守护进程必须校验 transcript 证明后才能接管。首个切换版本保留该回收边界并在发布说明中记录Linux 重启或容器 PID namespace 变更可能让未密封活跃记录无限期 fenced且409 session_writer_conflict并不证明其 writer 仍存活。跨 boot 自动回收、新机器身份字段、基于过期的接管与公开 force-unlock API 都需要单独的设计决策。强制 lease 还使优雅受管关停对每个活跃 Conversations transcript 执行密封与哈希实现不静默延长既有子进程终止截止时间而是要求以代表性最大活跃会话/transcript 规模衡量并行密封是否落入该预算。4. 停止写入 owner 但不破坏迁移与状态目录安全行为变更不再构造、获取、释放长期存活的文件 owner但保留旧版本所需的最小检查并退役路径第一个补丁不删除剩余 owner 实现与聚焦测试迁移窗口关闭后再清理。具体做法把StandaloneDeletionJournal所需的一小部分路径创建与校验逻辑移入该类不新增替代 owner 服务或仅此一个消费者的 standalone 抽象日志从状态父目录直接派生保留私有目录创建、身份校验与持久化检查但没有owner 记录、进程存活检查、锁、宽限期、acquire 或 release。保留目录权限不对称POSIX 上conversations/叶子及其日志子树要求0700新建目录使用该模式稳定状态根与既有祖先必须是同属、非符号链接且规范身份稳定的目录但不要求历史模式为0700也不修改——尤其既有0755的~/.qwen依然有效。StandaloneDeletionJournal在每次读、恢复、清空、写路径上先校验父目录读取把缺失状态目录视为空首次写入安全创建不安全的或被替换的父目录使日志操作 fail closed。既有回收 singleflight 仍是守护进程本地的每个日志 UUID 在读取或变更 transcript 前进入其会话生命周期 lease后台扫描若输掉获取则跳过该 UUID 继续触发操作不把普通 lease 争用归类为日志损坏同一会话的直接生命周期请求保持正常结构化冲突响应。新守护进程永不创建或替换conversations/runtime-owner.json只在既有conversations/.runtime-owner.lock下检查存活的旧版 owner 保持conversation_runtime_in_use精确重校验的陈旧记录被持久化移除。该锁只是此兼容操作的瞬态守卫不跨运行时生命周期持有。服务器保留conversation_runtime_in_use仅用于旧版迁移与 Live-start 非发布者准入更新后的守护进程不会仅因另一更新守护进程挂载了 Conversations 就发出它。conversation_runtime_unavailable、conversation_root_compromised与守护进程本地运行时不变式失败保持不变。5. Live discovery 保持独立激活改为发布者准入discovery.ts 中的 owner 协议保持不变owner 记录选出一个可发现的 Live 宿主并保护该端点发布。但发布本身目前并不门控/live/start、/live/new或 Host 快捷键动作的激活——旧实现由被移除的 Conversations acquire 间接提供该激活门因此替代实现必须同时覆盖发布与每条启动路径发布路径在每次writeLiveDiscoveryFile()之前对所有目标基含稳定基调用handoffLiveDiscoveryOwner()。源码中该函数第 478 行起以commitOwner回调与宽限语义工作发布路径为所有目标传入 no-opcommitOwner不再有 Conversations owner 记录可提交保留默认waitForHandoffGrace。在陈旧 owner 回收时handoffLiveDiscoveryOwner()持 Live 锁移除已校验死 locator、释放锁、再执行既有交接宽限随后发布调用writeLiveDiscoveryFile()重取 Live 锁并拒绝竞争中的活跃发布者。no-op 刻意移除旧的跨记录排序依赖同时保留锁后 Live 宽限。只读 Live-start 准入使用与稳定基相同的目录身份检查、锁、安全记录解析与精确 owner 比较。发布等待完成后、通话激活前重新读取稳定 locator要求当前协议版本且{ pid, instanceNonce }与本地守护进程匹配绝不创建、替换、移除或回收记录。有效但不同的发布者 → 既有可重试conversation_runtime_in_use缺失或瞬态不可读 locator →conversation_runtime_unavailable畸形或不安全状态 → 不可重试conversation_runtime_ownership_compromised。这些失败是 Live 局部的不会隔离 Conversations 运行时或禁用 standalone 路由。路由发起的/live/start、/live/new与 Host 发起的toggle/new动作必须在LiveHostCoordinator.start()之前进入同一异步准入接缝被拒绝的 Host 动作发布既有非机密 Live unavailable/error 状态且不得启动 Live 会话协调器、麦克风采集或 Appshot 采集。由于接缝是异步的准入在 start 进入接缝时捕获协调器动作 generation此后任何 Hoststop/toggle/new与任何/live/start、/live/new、/live/stop请求都推进该 generation接缝在start()前重查 generation被取代的 start 直接丢弃——pending 准入期间到达的 stop 绝不能在准入解析后跟随着启动通话。协调器既有的 action epoch 只在通话创建时推进无法表达该预启动窗口排序因此 generation 与 epoch 并存。最终状态Live discovery 与激活保持单发布者而 Conversations writer lease 是会话粒度的——当选发布者上的 Live 会话可以与另一守护进程上的不同 standalone 会话同时运行另一守护进程触及同一 transcript 时由 writer lease 拒绝standalone 路由无论 lease 可用与否都继续拒绝 Live-owned 记录。6. 定时任务激活加固不加第二个 lease定时任务的持久化、keepalive 与 boot 再水合保持不变。Controller 与 run 会话在恢复成功前从 Conversations 运行时继承强制 writer lease丢失 lease 的守护进程无法让绑定会话驻留boot 再水合记录失败keepalive 使用既有重试退避。多个守护进程可读取同一任务文件并同时尝试恢复同一绑定会话lease 获取发生在该会话调度器激活之前因此恰好一个恢复可驻留并触发绑定任务失败的恢复不得执行或预订任务其冲突保留在既有再水合结果与onError路径而非追加为一次任务运行。既有跨进程任务文件变更锁与持久化lastFiredAt状态不变。这防止仅由并发恢复引起的重复但并不把调度器升级为 exactly-onceprompt 已派发但 fired 状态尚未持久化的既有 at-least-once 窗口保持不变。未绑定持久任务需要单独的准入规则两个 keepalive worker 最初可能铸造不同的 controller 会话 ID此时会话 writer lease 无法在它们之间选举。因此在标记的 Conversations ACP 运行时中持久加载前安装调度器资格谓词拒绝触发任何未绑定持久任务守护进程 keepalive 仍是唯一绑定此类任务的组件其既有updateCronTasks事务在跨进程任务文件锁下重查未绑定状态、提交一个 controller 会话 ID 并拆除失败的孤儿。默认runQwenServe路径启用守护进程受管绑定 worker选择 Conversations marker 但未启用该 worker 的嵌入宿主会让未绑定 Conversations 任务休眠且不得回退到 legacy lock-owner 执行。产品边界不变持久 cron 任务在 standalone 会话中仍不受支持通用定时任务路由不能在 Conversations workspace 创建新会话。7. 同一版本内交付最小 Web Shell 降级不新增activeElsewhere列表字段或新的客户端 owner 发现协议。后端与 Web Shell 可分别合入 PR但发布必须等客户端本地呈现结果状态standalone 列表失败与过渡期conversation_runtime_in_use在 Recents 区域渲染一次而不是每次导航触发 refetch 都走全局错误 toast打开会话时的session_writer_conflict与session_writer_unavailable渲染在受影响行/区域并带重试动作。activeElsewhere提示仍被推迟因为列表没有权威的跨守护进程 live-state 索引——客户端改为响应既有 attach 时错误契约。8. 不加路由与协调变更不引入守护进程间代理、重定向、共享 owner 索引、心跳、全局生命周期锁或分布式缓存失效既有会话路由继续只在接收守护进程内部的运行时中解析 owner。不引入新设置或命令行标志——同时支持排他与宽松两种模式会保留整个旧子系统并制造混合模式兼容问题。错误契约速查条件结果另一更新守护进程加载了不同会话列出、新建与对另一会话的操作继续另一更新守护进程为 open/rename/repair 加载了该会话该会话返回409 session_writer_conflict批量 archive/delete 包含另一守护进程加载的会话既有200批处理外壳该项errors[].code为session_writer_conflict同本地身份域内可证明已死的良好活跃 owner回收 → 权威 transcript 重载 → 继续活跃 owner 存活/停滞/外来/缺失回收身份该会话409 session_writer_conflictwriter 记录畸形/非普通文件或残留 transition claim该会话503 session_writer_unavailable有效密封记录 匹配 transcript 证明Certified takeover → 权威重载 → 继续密封记录 transcript 证明不再匹配该会话409 session_transcript_changedConversations bridge 缺少强制 lease 证明新候选拒绝并 dispose或既有运行时终末隔离一切请求保持不可重试503 conversation_root_compromised安全工作目录身份变更且无匹配本地 generation 残留丢弃孤儿 pin采纳当前身份走正常 writer/lifecycle lease 继续工作目录身份在本地 generation 驻留期间或 leased 生命周期操作捕获后变更既有working_directory_compromised存活的 legacy runtime-owner 记录迁移期 standalone 表面503 conversation_runtime_in_uselegacy 拥有权状态畸形/不安全/不确定既有conversation_runtime_ownership_compromised或conversation_runtime_unavailable非稳定 Live locator 发布者的守护进程尝试启动 Live/live/start或/live/new返回503 conversation_runtime_in_usestandalone 仍可用Live-start 时稳定 locator 缺失/不可读/畸形/不安全Live 启动 fail closedunavailable 或 ownership-compromisedstandalone 仍可用对每个 writer 状态行批量生命周期路由在既有200每项结果中保留相同错误类型而不是改变批处理的传输状态。兼容性与发布REST 与 SDK 对象形状不变。守护进程批量序列化器必须停止把 session-writer 错误折叠进standalone_session_operation_failed并在受影响项字符串code中保留既有 writer 错误类型standalone_sessions_v1与standalone_session_options_v1继续描述 API 支持且不为并发保证新增能力。发布是排空并切换drain-and-cutover不是滚动混版升级先停止所有能在无强制 lease 下承载 standalone 会话的守护进程版本确认其会话已关闭再启动带本变更的守护进程。若在旧→新方向违反该顺序新守护进程会尊重存活的 legacy runtime-owner 记录并返回503 conversation_runtime_in_use旧守护进程退出后下一次运行时初始化移除陈旧精确记录并无须重启继续。兼容守卫降低失败模式但不支持滚动混版部署——一次性兼容检查在运行时发布后不重复无法探测反向更新守护进程挂载后旧守护进程才启动它找不到 owner 记录、写一条、可能在 leased writer 旁运行未 lease 的 ACP writer。因此共享同一 Conversations 根的守护进程必须一起升级owner 记录格式不扩展 lease-aware marker因为旧严格读者会把新形状判为 compromised。writer-lock schema-version-2 owner 记录接受可选pid_namespace_id更新后的 Linux writer 在可用时填充更新后的回收器要求它与既有启动身份共同存在。缺完整身份的既有或新活跃记录对冲突检测兼容但不能自动回收——升级预检必须排空这些 writer或在权威外部 writer fence 后显式清理残余记录。回滚必须在旧的非参与守护进程启动前关闭/排空所有更新后的 Conversations writer并确认无活跃、密封、claim 或身份扩展记录残留仅优雅进程退出可能有意留下密封交接记录。发布说明要点包括多个守护进程可为同一用户暴露 standalone 会话活跃会话是守护进程本地的支持拓扑是一台机器、同一 OS 用户下若干守护进程跨物理机共享稳定基或 runtime base 不受支持Darwin/Windows 的陈旧 writer 回收依赖该边界不同会话 ID 可跨更新守护进程并发活跃而同一会话的第二 writer 或生命周期变更被 fencedstandalone 会话始终使用 writer lease即使实验设置缺失或为 falseLive 与定时任务 writer 同样如此只有精确稳定 Live locator 发布者能激活 Live同时刻的定时任务再水合只接纳一个驻留 owner且不提供超出调度器既有持久化语义的 exactly-once未绑定任务在跨进程任务文件事务提交其 controller 绑定前不能从 Conversations 会话触发可证明同域死亡活跃 writer 被自动回收Linux 要求相同 hostname、boot 与 PID namespace存活或不可验证的 writer 保持 fencedlease 提供同会话冲突 fence而非多主支持。验证策略单元测试覆盖无长期 legacy owner 的服务器启动存活/陈旧 legacy-owner 兼容检查严格畸形 owner 失败无 lifetime ownership 的运行时初始化无 owner release 的关停保留的 root/generation/quarantine 失败删除日志状态父目录创建与 compromise 检测历史非0700状态根接受 非私有conversations/叶子拒绝无 owner 获取的日志启动日志读/恢复/写路径父目录重校验后台回收中争用即跳过运行时来源 writer-lease 选择。writer 矩阵覆盖Conversations 运行时用户设置关闭、普通运行时关闭、所有运行时开启——Conversations 选local而普通受管子进程保持never无私有父能力时 marker 拒绝环境文件加载前捕获用户级与项目级环境擦洗sandbox 传播primary/secondary/Conversations bridge 子进程环境隔离。工厂覆盖验证默认工厂与createSpawnChannelFactory返回的每个配置工厂都携带转发能力并经scrubChildEnv合并 bridge 第二参数。Bridge 证明覆盖精确 marker 该工厂或故意证明的测试 fake 被接受忽略第二参数的未证明工厂 marker 被拒绝能力工厂但 marker 缺失或错误被拒绝。运行时发布覆盖合格 Conversations bridge 被接受不合格新live-conversation候选被拒绝并 dispose等价既有注册运行时被拒绝并隔离且后续每次访问保持不可重试conversation_root_compromised。调度器覆盖验证捕获的 marker 安装未绑定持久任务跳过、绑定后允许触发、普通 workspace lock-owner 行为不变。Core lease 覆盖记录并校验 Linux PID namespace、缺回收身份视为存活、仅同 hostname/boot/namespace 回收死亡与 PID 复用 owner、拒绝匹配存活/停滞/外来 host/boot/namespace/legacy 无身份/畸形/密封/残留 claim。Darwin/Windows 覆盖对应 hostname 与进程启动规则。受管关停与双进程集成受管关停覆盖用代表性高活跃会话数与大 transcript 衡量并行密封是否满足既有终止截止时间并验证强制超时在 writer 进程仍存活时保留精确活跃锁、绝不留下残余 claim 或不确定过渡且该精确进程退出后只有同身份域竞争者可恢复良好活跃记录。双进程守护进程集成测试同一 home、runtime base 与 Conversations 根验证 15 项核心场景守护进程 A 与 B 的GET /standalone/session-options与GET /standalone/sessions都返回200任一守护进程的 standalone 路由不因另一进程存活而返回conversation_runtime_in_use存活 legacy runtime-owner 记录返回503 conversation_runtime_in_use其进程退出后下一次请求无须重启即退役陈旧记录并返回200A 保持会话 S 活跃时B 仍可列目录、新建聊天 T、恢复并使用不同持久化会话A 保持 S 活跃时B 恢复/重命名/修复 S 收到409 session_writer_conflictarchive/delete 保持200批处理外壳并报告 S 的session_writer_conflict显式关闭释放 A 的 lease 后B 通过普通获取恢复 S独立地A 优雅关停密封另一会话后B 通过 certified takeover 恢复A 关闭或 idle reap S 后B 可安全重建其工作目录新身份并释放 S之后 A 可 open/repair/delete S 而不把 A 的孤儿 pin 视为 compromiseA 匹配 generation 驻留期间替换目录仍 fail closedA 的锁持有 ACP writer 在稳定活跃态被杀后同本地身份域中的 B 回收锁、权威重载 transcript 并继续无须手工清理只杀 A 的父进程而 writer 仍存活时仍返回冲突匹配存活或停滞的 A以及外来 host/boot/PID namespace 记录保持409 session_writer_conflict无身份与残余 claim 状态 fail closed关停任一守护进程不移除或失效另一方的本地运行时两个空闲守护进程同时再水合同一定时任务绑定会话时经 writer lease 选出一个驻留会话输家记录恢复失败并退避只有赢家触发该槽位的绑定任务两个 keepalive worker 观察到同一未绑定任务可能铸造竞争 controller 会话但 Conversations 会话在未绑定时绝不触发它任务文件事务提交恰好一个绑定、清理输家孤儿只有绑定 controller 具备触发资格两个守护进程回收同一 prepared 删除时选出一个 lease 持有者竞争者跳过该 UUID 而不使无关触发操作失败或报告日志损坏两个守护进程都启用 Live 时只有精确稳定 locator 发布者能激活通话另一守护进程的/live/start、/live/new、Host toggle 与 Host new 在 Live 会话协调器或采集设备启动前失败该守护进程仍服务不同 standalone 会话standalone 路由继续拒绝 Live 记录root compromise 与不可用 generation 仍 fail closed不回退到主 workspace。聚焦StandaloneSessionService覆盖终末关闭不留可复用 generation pindetach 保留同 generation 的 pinidle-reaped 或被替换的 event epoch 在复用前被惰性丢弃删除回收从不提供孤儿 pin驻留 generation 期间的替换与 leased 生命周期操作捕获后的身份变更保持working_directory_compromised外来摘要或不确定 bridge 探测绝不授权重新 pin。Live 回归覆盖discovery 仍至多一个发布者发布路径对稳定基与自定义基都执行既有校验交接陈旧稳定基记录可在前任 owner 退出后被回收no-opcommitOwner交接宽限在交接锁释放后、发布前运行该间隙的竞争发布者被发布锁拒绝。启动准入只接受当前协议版本与精确稳定 locator PID/instance nonce拒绝有效不同发布者可重试错误对缺失/畸形/不安全/不可读 locator 状态 fail closed 而不隔离 standalone两条 HTTP 启动路由与两条 Host 启动动作共用同一准入拒绝时不执行任何会话或采集工作准入线性化证明pending 准入期间被后续 stop/toggle/new 意图取代的 start在解析后不执行任何会话或采集工作只有最新意图可激活通话。standalone 可用性独立于 discovery 发布失败与发布记录者。Web Shell 回归覆盖切换会话不因 standalone 列表失败弹 toast过渡期conversation_runtime_in_use在 Recents 区域出现一次打开时的session_writer_conflict/session_writer_unavailable附着于受影响会话/区域并带重试动作不需要activeElsewhere列表字段。测试必须证明边界的两个侧面不同会话 ID 可跨更新守护进程并发使用而同一会话在其完整加载生命周期内保持排他不得暗示全局新鲜 live state、跨守护进程事件路由或原子多会话操作。被否决的替代方案守护进程间代理proxying保留单一运行时 owner但需要对所有 standalone 与 owner-routed 会话 API含 SSE 与权限做认证转发。客户端重定向到 owner引入发现、token、origin 与重连行为并保留本变更要移除的全局 owner。每守护进程独立 standalone 存储简单但使守护进程看不到同一持久化会话目录。依赖用户设置启用 writer lease允许关闭设置的守护进程绕过 fence无法保护共享 standalone 持久化。只对sourceTypestandalone启用 lease漏掉同 Conversations 运行时承载的 Live 与定时任务来源包括无 standalone API 请求的后台再水合。把单发布者 discovery 当作激活 fence发布与激活是两条独立路径无每条启动路径前的显式准入直连非发布者守护进程的客户端仍可启动第二个 Live host。现在就给列表加activeElsewhere需要权威共享 live-state 索引或 owner 发现协议最小 Web Shell 行为可用既有 attach 时错误契约实现。共享路由或全局事务平面跨守护进程事件路由、全局新鲜 live state 与跨会话原子操作是不同可靠性契约对由既有会话 writer lease 分区的并发使用并非必需。无资格限定的陈旧 writer 回收仅 PID/hostname/年龄/不活跃无法证明共享存储上的受管 writer 已死自动恢复限定于匹配本地身份域与稳定进程身份一切不确定状态保持 fenced。保留受管never 手工解锁普通非协作 writer 死亡会让每个已加载会话不可用直到操作员发现并移除内部锁文件身份限定本地回收自动处理常见安全情形手工恢复仅保留给外部 writer fence 后的不确定过渡或存储状态。小结Relaxed Standalone Daemon Ownership 将 Qwen Code 的 Conversations 会话共享模型从一进程全局独占演进为会话粒度排他 身份限定恢复更新后的守护进程并发服务不同会话同一会话始终由跨进程 writer lease 串行化Live 激活保持机器全局单发布者而一切不安全、无法证明或跨身份域的状态严格 fail closed。这一设计既解决了多守护进程场景下503 conversation_runtime_in_use的可用性痛点又没有引入跨守护进程路由、全局锁或分布式协调等更重的可靠性契约是一个以既有 writer 协议为支点的会话分区并发契约。部署时请务必遵循排空并切换的升级顺序并在多守护进程拓扑下按本文错误契约核对客户端呈现。【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考