VJSX 嵌入式执行器
本文引用的文件列表 - vhttpd.vjsx.example.toml - 08-vjsx-intro.md - VJSX_FACADE_REFERENCE.md - inproc_vjsx_types.v - registry.v - vjsx_host_loader.v - inproc_vjsx_lifecycle.v - inproc_vjsx_lane_pool.v - runtime_plan_cli_overlay.v - config.v
目录
简介
VJSX 是 vhttpd 内置的嵌入式 TypeScript/JavaScript 执行器,基于 QuickJS 引擎在进程内直接运行用户编写的 .mts/.ts/.mjs 等模块。它提供轻量、高性能的 HTTP/WebSocket 处理与宿主能力桥接,适合网关、中间件、协议粘合与快速原型场景。
项目结构
围绕 VJSX 的核心代码集中在 src/executor 下的 inproc_vjsx_* 系列模块,配合配置解析与运行时门面(Facade)文档,形成“配置→注册表→生命周期→Lane池→加载器→宿主API”的完整链路。
graph TB
A["配置文件<br/>config/vhttpd.vjsx.example.toml"] --> B["配置解析<br/>src/config/*.v"]
B --> C["执行器注册表<br/>src/executor/registry.v"]
C --> D["生命周期与状态<br/>src/executor/inproc_vjsx_lifecycle.v"]
D --> E["Lane 选择与池化<br/>src/executor/inproc_vjsx_lane_pool.v"]
D --> F["入口与模块加载器<br/>src/executor/vjsx_host_loader.v"]
D --> G["类型与配置结构<br/>src/executor/inproc_vjsx_types.v"]
H["门面参考文档<br/>docs/VJSX_FACADE_REFERENCE.md"] -.-> F
H -.-> D
图表来源 - vhttpd.vjsx.example.toml:1-36 - registry.v:197-261 - inproc_vjsx_lifecycle.v:16-87 - inproc_vjsx_lane_pool.v:5-30 - vjsx_host_loader.v:93-111 - inproc_vjsx_types.v:7-24 - VJSX_FACADE_REFERENCE.md:1-62
章节来源 - vhttpd.vjsx.example.toml:1-36 - registry.v:107-127 - inproc_vjsx_lifecycle.v:16-87 - inproc_vjsx_lane_pool.v:5-30 - vjsx_host_loader.v:93-111 - inproc_vjsx_types.v:7-24 - VJSX_FACADE_REFERENCE.md:1-62
核心组件
- 执行器注册表:负责将 kind=vjsx 映射为嵌入式工厂,并解析 CLI/配置到 VjsxRuntimeFacadeConfig。
- 生命周期与状态:创建 Lane 集合、启动 lane worker、维护签名与热更新状态。
- Lane 池与调度:按轮询选择空闲且健康的 Lane,支持超时等待与按 ID 精确选择。
- 入口与模块加载器:根据 app_entry 后缀判断模块模式,必要时安装 TS 运行时并构建临时产物,再导入默认导出或 handle 函数。
- 类型与配置结构:定义 VjsxRuntimeFacadeConfig、VjsxExecutionLane、InProcVjsxExecutor 等关键结构。
- 门面参考:对外暴露 ctx、ctx.runtime、WebSocket frame 等 API 约定。
章节来源 - registry.v:226-261 - inproc_vjsx_lifecycle.v:16-87 - inproc_vjsx_lane_pool.v:5-30 - vjsx_host_loader.v:17-29 - inproc_vjsx_types.v:7-24 - VJSX_FACADE_REFERENCE.md:8-25
架构总览
下图展示了从请求进入 vhttpd 到 VJSX 嵌入式执行器的关键路径,包括配置解析、执行器选择、Lane 分配、模块加载与调用。
sequenceDiagram
participant Client as "客户端"
participant VHTTPD as "vhttpd 内核"
participant Reg as "执行器注册表"
participant Life as "生命周期/状态"
participant Pool as "Lane 池"
participant Loader as "入口与模块加载器"
participant JS as "QuickJS 运行时"
Client->>VHTTPD : "HTTP/WebSocket 请求"
VHTTPD->>Reg : "resolve_vjsx_runtime_config()"
Reg-->>VHTTPD : "VjsxRuntimeFacadeConfig"
VHTTPD->>Life : "new_inproc_vjsx_executor(config)"
Life-->>VHTTPD : "InProcVjsxExecutor(含 lanes/workers)"
VHTTPD->>Pool : "select_next_lane()/acquire_next_lane()"
Pool-->>VHTTPD : "选定 Lane"
VHTTPD->>Loader : "load_entry(ctx, config, idx, sig, as_module)"
Loader->>JS : "TS转译/构建/运行入口"
JS-->>Loader : "默认导出/handle"
Loader-->>VHTTPD : "可调用句柄"
VHTTPD->>JS : "调用 handler(ctx)"
JS-->>VHTTPD : "响应/命令"
VHTTPD-->>Client : "返回结果"
图表来源 - registry.v:226-261 - inproc_vjsx_lifecycle.v:16-87 - inproc_vjsx_lane_pool.v:83-101 - vjsx_host_loader.v:93-111
详细组件分析
执行器注册与配置解析
- 当 executor.kind = "vjsx" 时,注册表将其识别为嵌入式执行器,并通过 resolve_embedded_host_runtime_config 将 TOML/Cli 参数合并为 EmbeddedHostRuntimeConfig,再转换为 VjsxRuntimeFacadeConfig。
- 关键映射:
- app_entry → app_entry
- module_root → module_root
- build_root → build_root
- runtime_profile → runtime_profile
- thread_count → lane_count → thread_count
- enable_fs/process/network 透传
- websocket_affinity/actor 透传
章节来源 - registry.v:197-261 - registry.v:107-127
生命周期与 Lane 管理
- new_inproc_vjsx_executor 依据 thread_count 初始化若干 VjsxExecutionLane,并为每个 Lane 准备 worker 通道(websocket/snapshot/warmup/pump/affinity)。
- 维护 source_probe/signature 缓存,用于增量热更新与预热。
- admin_details/lane_snapshot 暴露运行时元数据与 Lane 健康度。
章节来源 - inproc_vjsx_lifecycle.v:16-87 - inproc_vjsx_lifecycle.v:102-155
Lane 选择与并发控制
- select_next_lane 使用轮询 + 健康检查 + inflight 计数,避免将请求派发至忙碌或不健康 Lane。
- acquire_next_lane 支持带超时的重试等待;release_lane 在请求完成后减少 inflight 并尝试调度 WebSocket 邮箱任务。
章节来源 - inproc_vjsx_lane_pool.v:5-30 - inproc_vjsx_lane_pool.v:83-101 - inproc_vjsx_lane_pool.v:126-143
入口与模块加载器
- entry_runs_as_module 根据后缀判定是否作为模块运行(.mts/.ts/.mjs/.cjs 等),否则以脚本模式运行。
- load_entry 会:
- 若为 TS/运行时模块,安装 TS 运行时
- 构建产物到 lane 专属临时目录(含 pid/lane 信息)
- 生成 loader 包装,统一导出 default/handle/globalThis.__vhttpd_handle
- fs_roots 决定模块解析根目录(module_root/app_entry 所在目录与工作目录)。
章节来源 - vjsx_host_loader.v:17-29 - vjsx_host_loader.v:31-41 - vjsx_host_loader.v:74-91 - vjsx_host_loader.v:93-111
类型与配置结构
- VjsxRuntimeFacadeConfig 承载所有运行时开关与路径、线程数、网络/FS/进程权限等。
- VjsxExecutionLane 记录 id、served_requests、healthy/dirty、inflight、last_error 等。
- InProcVjsxExecutor 持有共享状态与对外接口。
章节来源 - inproc_vjsx_types.v:7-24 - inproc_vjsx_types.v:33-42 - inproc_vjsx_types.v:44-90
门面与 API 约定
- 入口解析顺序:export default → export const handle → globalThis.__vhttpd_handle。
- ctx.runtime 提供只读元信息与日志/事件/快照/IO/网络/桥接方法。
- WebSocket 帧与 upstream 帧字段、返回值形状均有明确约定。
章节来源 - VJSX_FACADE_REFERENCE.md:8-25 - VJSX_FACADE_REFERENCE.md:26-62 - VJSX_FACADE_REFERENCE.md:204-280
依赖关系分析
- 配置层:TOML/Cli 通过 runtime_plan_cli_overlay 与 embedded host 配置合并,最终落到 registry 的 resolve_vjsx_runtime_config。
- 执行层:生命周期创建 Lane 与 worker,Lane 池负责调度,加载器负责 TS 编译与模块装载。
- 外部依赖:QuickJS 运行时由 vjsx.* 模块驱动;TS 转译与运行时注入由 vjsx.runtimejs 完成。
graph LR
CFG["配置/TOML+CLI"] --> REG["registry.resolve_vjsx_runtime_config"]
REG --> LIF["inproc_vjsx_lifecycle.new_inproc_vjsx_executor"]
LIF --> POOL["inproc_vjsx_lane_pool.select/acquire/release"]
LIF --> LOAD["vjsx_host_loader.load_entry"]
LOAD --> QJS["QuickJS 运行时"]
图表来源 - registry.v:226-261 - inproc_vjsx_lifecycle.v:16-87 - inproc_vjsx_lane_pool.v:5-30 - vjsx_host_loader.v:93-111
章节来源 - registry.v:226-261 - inproc_vjsx_lifecycle.v:16-87 - inproc_vjsx_lane_pool.v:5-30 - vjsx_host_loader.v:93-111
性能与线程模型
- 线程/Lane 模型:thread_count 决定 Lane 数量,每个 Lane 对应一个独立的 QuickJS 上下文与 worker 协程,内部通过 channel 分发 WebSocket/快照/预热/泵任务。
- 调度策略:轮询 + 健康检查 + inflight 计数,避免热点过载;支持按 lane_id 精准路由(如粘性会话)。
- 内存与资源:
- 构建产物位于 lane 专属临时目录(含 pid/lane 索引),便于隔离与清理。
- 源码探针与签名缓存用于增量热更新,降低重启成本。
- 当前嵌入范围限定于 HTTP 与 WebSocket 事件分发,流式/MCP worker 模式不在此门面范围内。
章节来源 - inproc_vjsx_lifecycle.v:16-87 - inproc_vjsx_lane_pool.v:5-30 - vjsx_host_loader.v:74-91 - VJSX_FACADE_REFERENCE.md:196-202
配置详解:[vjsx] 选项
以下选项来自示例配置与注册表解析逻辑,说明其作用与典型用法。
- app_entry
- 作用:应用入口文件路径(支持相对/绝对路径)
- 解析:由 TOML 的 [vjsx].app_entry 或 CLI --vjsx-entry 覆盖
- 影响:模块加载器据此确定模块模式与构建产物位置
-
参考路径
-
module_root
- 作用:模块解析根目录,优先于工作目录
- 解析:TOML [vjsx].module_root 或 CLI --vjsx-module-root
- 影响:fs_roots() 会将 module_root 加入解析根
-
参考路径
-
build_root
- 作用:TS 转译与构建产物根目录;未设置时使用系统临时目录下的 vhttpd_vjsx
- 解析:TOML [vjsx].build_root 或 CLI --vjsx-build-root
- 影响:lane_temp_root 组合 entry_name/source_signature/pid/lane 生成唯一子目录
-
参考路径
-
runtime_profile
- 作用:运行时配置集(例如 node/script),影响全局环境与行为
- 解析:TOML [vjsx].runtime_profile 或 CLI --vjsx-runtime-profile
-
参考路径
-
thread_count
- 作用:执行线程/Lane 数量,建议接近 CPU 核心数
- 解析:TOML [vjsx].thread_count 或 CLI --vjsx-thread-count
- 影响:new_inproc_vjsx_executor 据此创建 lanes 与 workers
-
参考路径
-
其他相关开关(可选)
- enable_fs / enable_process / enable_network:控制宿主能力白名单
- max_requests:单 Lane 最大请求数(用于优雅重启/回收)
- websocket_affinity / websocket_actor:WebSocket 粘性与 Actor 策略
- 参考路径
章节来源 - vhttpd.vjsx.example.toml:21-25 - registry.v:201-214 - vjsx_host_loader.v:31-41 - vjsx_host_loader.v:74-91 - inproc_vjsx_lifecycle.v:17-24 - runtime_plan_cli_overlay.v:204-206 - inproc_vjsx_types.v:17-24 - registry.v:254-260
开发指南与最佳实践
- 入口约定
- 推荐导出 default 函数;其次支持 export const handle 或 globalThis.__vhttpd_handle
- Bot 风格也可导出 http/websocket/websocket_upstream/snapshot 等命名
-
参考路径
-
模块与依赖
- 使用 .mts/.ts 获得类型检查;.mjs/.cjs 可作为 ES 模块
- 模块解析根优先 module_root,其次 app_entry 所在目录,最后工作目录
-
参考路径
-
调试技巧
- 使用 ctx.runtime.log/warn/error 输出日志
- 使用 ctx.runtime.snapshot 获取运行时快照
- 查看 Admin Plane 的事件日志定位问题
-
参考路径
-
性能优化
- 合理设置 thread_count(接近 CPU 核心数)
- 利用 ctx.runtime.httpFetch 发起外部请求时做好超时与重试
- 使用本地 Map/Set 做轻量缓存,避免重复计算
- 参考路径
与 PHP Worker 模式对比
- 适用场景
- VJSX:薄逻辑层、网关/中间件、协议粘合、快速原型、低开销高并发
- PHP Worker:复杂业务、生态丰富、长期任务、数据库密集
- 差异点
- 执行模型:VJSX 嵌入式(进程内 QuickJS),PHP Worker 独立进程/CGI
- 依赖管理:VJSX 轻量、无 npm;PHP 生态成熟
- 生命周期:VJSX 基于 Lane 与签名热更;PHP Worker 有显式 worker 入口
- 参考路径
- 08-vjsx-intro.md:28-41
- registry.v:79-127
故障排查
- 常见错误
- 缺少 app_entry 或路径不存在:注册表会在解析阶段报错并给出明确提示
- 不支持的入口后缀:加载器会拒绝非 .js/.mjs/.cjs/.mts/.cts 等
- 无可用 Lane:Lane 池在全部忙或不健康时会返回错误
- 定位手段
- 使用 ctx.runtime.error 记录异常堆栈
- 使用 ctx.runtime.snapshot 观察各 Lane 健康与负载
- 检查 build_root 下 lane 专属目录是否存在构建产物
- 参考路径
- registry.v:230-243
- vjsx_host_loader.v:17-29
- inproc_vjsx_lane_pool.v:83-101
结论
VJSX 嵌入式执行器以“配置→注册表→生命周期→Lane 池→加载器→宿主 API”的清晰分层,提供了在 vhttpd 进程内高效运行 TypeScript/JavaScript 的能力。通过合理的 thread_count、module_root/build_root 与 runtime_profile 配置,结合 ctx/runtime 提供的丰富能力,开发者可在网关、中间件与协议适配场景中快速落地。对于复杂业务与长生命周期任务,仍建议采用 PHP Worker 模式,二者可按需组合使用。