☰
LSP 3.17 服务器发起的工作进度机制:window/workDoneProgress/create 请求深度解析
2026/10/6 2:23:17 网站建设 项目流程
  • 开发工具

【免费下载链接】language-server-protocol

Defines a common protocol for language servers.

项目地址:https://gitcode.com/gh_mirrors/la/language-server-protocol
点击查看免费下载

导读

window/workDoneProgress/create是 Language Server Protocol(LSP)中由**服务器主动向客户端发起工作进度(Work Done Progress)**的核心请求,解决了服务器在请求上下文之外执行耗时任务(如重新索引数据库、批量编译、依赖解析)时无法向用户呈现进度的问题。本文基于本仓库_specifications/lsp/3.17目录下的规范文档,结合 协议元模型 中对该请求的机器可读定义,完整讲解该请求的协议形态、token 生命周期、与$/progress通知的配合方式、取消机制及客户端能力协商,帮助你正确实现服务器端的进度上报。

一、背景:两种工作进度发起方式

在 LSP 3.15 及之后版本中,进度上报通过通用的$/progress通知完成,其值负载(value payload)有三种形态:WorkDoneProgressBegin、WorkDoneProgressReport和WorkDoneProgressEnd,对应进度的"开始—更新—结束"三个阶段(详见 类型定义)。

按发起方不同,Work Done Progress 分为两类:

发起方式触发途径典型场景
客户端发起(client initiated)客户端在请求参数中加入workDoneToken属性客户端发起的textDocument/reference等请求上附带进度 token
服务器发起(server initiated)服务器发送window/workDoneProgress/create请求服务器需要在某个请求之外自行上报进度,如后台重新索引数据库

本篇文章聚焦第二种方式——服务器发起的进度。

二、协议定义:方法、参数与响应

请求方向与方法名

window/workDoneProgress/create是一个从服务器发往客户端(server-to-client)的请求,用于请求客户端创建一个工作进度实例。这一方向性在协议元模型中有明确记录:在 metaModel.json 中,该请求的messageDirection字段为serverToClient,result类型为null,文档注释为:

Thewindow/workDoneProgress/createrequest is sent from the server to the client to initiate progress reporting from the server.

请求参数:WorkDoneProgressCreateParams

请求参数类型定义如下:

export interface WorkDoneProgressCreateParams { /** * The token to be used to report progress. */ token: ProgressToken; }

其中ProgressToken是integer | string的联合类型(见 specification.md 与 metaModel.json)。服务器在发起 create 请求时需自行生成一个唯一 token(实践中常用 UUID 字符串),该 token 将作为后续所有$/progress通知中标识此进度实例的键。

响应与错误处理

  • 成功响应:result为void(即无返回值,客户端确认已创建进度)。
  • 错误响应:若请求处理过程中发生异常,客户端返回error.code与error.message。

规范对错误情形有一个关键约束:如果 create 请求出错,服务器绝不能使用该 token 发送任何进度通知。这保证了错误发生后客户端不会收到与已失败进度关联的幽灵更新,是保证进度 UI 一致性的底线规则。

三、服务器发起进度的完整生命周期

根据 types/workDoneProgress.md 中的"Server Initiated Progress"一节,服务器发起的进度遵循以下完整流程:

1. 创建进度(create)

服务器在需要上报进度时(例如准备开始重索引),先向客户端发送:

{ "jsonrpc": "2.0", "id": 10, "method": "window/workDoneProgress/create", "params": { "token": "2f8a4c12-9d3b-4e76-9c1a-7b0f3a56e2d1" } }

2. 发送 begin 通知

创建成功后,服务器通过$/progress通知发送WorkDoneProgressBegin负载,title为必填项,用于简短说明正在执行的操作类型:

{ "jsonrpc": "2.0", "method": "$/progress", "params": { "token": "2f8a4c12-9d3b-4e76-9c1a-7b0f3a56e2d1", "value": { "kind": "begin", "title": "Indexing workspace", "cancellable": true, "message": "Scanning project/src", "percentage": 0 } } }

WorkDoneProgressBegin的字段语义(类型定义):

字段类型必填说明
kind'begin'是负载形态标记
titlestring是进度的标题,如"Indexing"或"Linking dependencies"
cancellableboolean否是否显示取消按钮;不支持取消的客户端可忽略
messagestring否更详细的进度消息,如"3/25 files";未设置时沿用上一次消息
percentageuinteger否进度百分比,100视为 100%;不提供则视为无限进度,取值范围[0, 100],应保持单调递增

3. 周期性发送 report 通知

任务执行过程中,服务器发送WorkDoneProgressReport更新进度:

{ "jsonrpc": "2.0", "method": "$/progress", "params": { "token": "2f8a4c12-9d3b-4e76-9c1a-7b0f3a56e2d1", "value": { "kind": "report", "message": "12/50 files", "percentage": 24 } } }

WorkDoneProgressReport支持cancellable、message、percentage三个可选字段;其中cancellable仅在 begin 中请求了取消按钮时有效。

4. 发送 end 通知收尾

任务完成或失败时发送WorkDoneProgressEnd:

{ "jsonrpc": "2.0", "method": "$/progress", "params": { "token": "2f8a4c12-9d3b-4e76-9c1a-7b0f3a56e2d1", "value": { "kind": "end", "message": "Indexing finished" } } }

WorkDoneProgressEnd仅含可选的message字段,可用于说明操作结果。

token 的使用约束

规范明确要求:create 请求中提供的 token 只能使用一次——即对该 token 应恰好发送一个begin、任意多个report和一个end通知。这与客户端发起的进度形成对比:客户端通过请求参数中的workDoneToken传入的 token,其有效期只持续到该请求返回响应为止。

四、取消机制:window/workDoneProgress/cancel

服务器发起的进度同样支持取消。客户端通过window/workDoneProgress/cancel通知(client-to-server 方向)取消进度,参数类型为:

export interface WorkDoneProgressCancelParams { /** * The token to be used to report progress. */ token: ProgressToken; }

协议要点(见 workDoneProgressCancel.md):

  • 取消的进度无需在 begin 中标记为cancellable——也就是说,即使服务器未提供取消按钮,客户端仍然可以主动取消进度;
  • 客户端可能因多种原因取消进度:发生错误、重载工作区等;
  • 服务器收到该通知后,应终止对应任务并发送end通知收尾(或依据自身实现决定处理方式)。

此外,对于客户端发起的进度,取消则直接通过取消对应请求(如$/cancelRequest)完成,无需单独的 cancel 通知。

五、客户端能力协商与向后兼容

为保持协议向后兼容,服务器只有在客户端通过能力声明明确支持时,才能使用window/workDoneProgress/create请求。客户端在 initialize 握手阶段返回的ClientCapabilities中声明:

window?: { /** * Whether client supports server initiated progress using the * `window/workDoneProgress/create` request. */ workDoneProgress?: boolean; };

对应客户端能力属性为window.workDoneProgress,类型为boolean,可选。服务器在发起 create 请求前必须检查该能力位;若客户端未声明支持,服务器应退回到客户端发起的方式,或在请求参数中附带的workDoneToken上上报进度,甚至放弃进度展示。

与之相对,客户端发起方式有一个特别之处:不存在专门的客户端能力位来声明"是否会在每个请求上发送进度 token"。因为这在很多客户端中并非静态属性,甚至同一请求类型的不同请求实例都可能不同,所以客户端能力通过每个请求参数中是否出现workDoneToken属性来按实例动态表达(见 types/workDoneProgress.md 中 "Client Initiated Progress" 一节)。

同时,为避免客户端在发送请求前建立进度 UI 而服务器实际不报进度,服务器需要在对应功能的 server capability 中声明workDoneProgress支持,例如:

{ "referencesProvider": { "workDoneProgress": true } }

六、从元模型看协议定义的一致性

本仓库在 metaModel 目录 中提供了 LSP 3.17 的机器可读元模型(metaModel.json、metaModel.schema.json与对应的 TypeScript 模型metaModel.ts),可用于校验与代码生成。其中与本文主题相关的定义包括:

  • window/workDoneProgress/create 请求定义:messageDirection: "serverToClient"、result: null、params: WorkDoneProgressCreateParams;
  • WorkDoneProgressCreateParams 结构:仅含token: ProgressToken一个属性;
  • WorkDoneProgressCancelParams 结构:同样仅含token: ProgressToken;
  • ProgressToken 类型:integer | string。

元模型中的这些定义与各 Markdown 规范文档完全一致,说明该请求在协议中作为一等公民被完整建模。如果你在实现语言服务器 SDK 时使用元模型驱动代码生成,window/workDoneProgress/create会自然生成对应的请求类型、参数类型与文档注释。

七、实现建议小结

  1. 能力先行:发送 create 请求前,务必检查客户端能力window.workDoneProgress是否为true。
  2. token 唯一且单次使用:每个进度实例使用独立的ProgressToken,遵守"一个 begin、多个 report、一个 end"的规则。
  3. 正确处理 create 失败:create 请求报错后,该 token 立即作废,不得再发送任何$/progress通知。
  4. 响应取消:监听window/workDoneProgress/cancel通知,收到后尽快终止任务并发送end负载。
  5. 善用元模型:以 metaModel.json 为单一事实来源生成类型定义,避免手写结构与规范漂移。

通过以上机制,语言服务器可以在索引、编译、依赖分析等请求外的长耗时操作中,向用户提供可取消、可感知的进度反馈,显著改善编辑器的交互体验——这正是 LSP 3.15 引入工作进度机制、并让服务器侧发起进度的设计初衷。

  • 开发工具

【免费下载链接】language-server-protocol

Defines a common protocol for language servers.

项目地址:https://gitcode.com/gh_mirrors/la/language-server-protocol
点击查看免费下载
上一篇:Klipper实战:如何让3D打印机实现智能参数自适应调校
下一篇:Tkinter表格组件终极指南:用tksheet构建专业级数据界面

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询