尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Overleaf Script Runner:Web 服务一次性脚本的日志、状态与进度追踪框架

发布时间:2026/9/13 22:14:31

资讯中心
01
ARTICLE

Overleaf Script Runner:Web 服务一次性脚本的日志、状态与进度追踪框架

Overleaf Script Runner:Web 服务一次性脚本的日志、状态与进度追踪框架
Overleaf Script RunnerWeb 服务一次性脚本的日志、状态与进度追踪框架【免费下载链接】overleafA web-based collaborative LaTeX editor项目地址: https://gitcode.com/GitHub_Trending/ov/overleafOverleaf 的services/web服务维护着大量用于数据修复、迁移和运维操作的一次性脚本services/web/scripts/下有上百个.mjs脚本。这些脚本通常由运维人员在服务器上手动触发默认情况下执行结果只存在于标准输出里。Script Runnerservices/web/scripts/lib/ScriptRunner.mjs就是为此设计的统一包装器它自动为脚本记录开始/结束、持久化最终状态success或error并向脚本暴露trackProgress函数以记录自定义进度步骤执行状态可以在管理后台的 Script Logs 页面查看。读完本文你将掌握如何在 Overleaf 中编写一个符合规范的运维脚本并理解其底层的状态持久化与执行监控机制。核心特性README 将 Script Runner 的能力概括为四点这四点都能在 ScriptRunner.mjs 源码中找到对应实现自动记录脚本的开始与结束脚本执行前后各写一次数据库见下文beforeScriptExecution/afterScriptExecution记录最终状态status字段只会是success或error由main函数是否正常返回决定提供trackProgress进度上报函数脚本的main函数接收该参数每完成一个子任务调用一次即可把进度消息连同时间戳追加到日志文档中捕获脚本参数与环境信息调用scriptRunner(main, vars)时传入的vars对象会被整体存入日志文档同时还会记录OL_POD_NAME、OL_USERNAME、OL_IMAGE_VERSION等环境变量便于事后定位“哪个镜像、哪台 Pod、谁执行的”。使用方法按照 README 的约定编写一个新脚本只需四步导入scriptRunner将脚本主逻辑写成一个async函数形参接收trackProgress不需要进度追踪时可以忽略该参数调用scriptRunner(main, scriptVariables)第二个参数是脚本需要的任意变量通过控制台输出中打印的 URL 访问 Script Logs 页面查看执行状态。仓库自带了一个可直接运行的示例脚本 services/web/scripts/example/track_progress.mjs它就是 README 中示例的实体文件完整内容如下// Import the script runner utility (adjust the path as needed) import { scriptRunner } from ../lib/ScriptRunner.mjs const subJobs 30 /** * Your scripts main work goes here. * It must be an async function and accept trackProgress. * param {(message: string) Promisevoid} trackProgress - Call this to log progress. */ async function main(trackProgress) { for (let i 0; i subJobs; i) { await new Promise(resolve setTimeout(() resolve(), 1000)) await trackProgress(Job in progress ${i 1}/${subJobs}) } await trackProgress(Job finished) } // Define any variables your script needs (optional) const scriptVariables { subJobs, } // --- Execute the script using the runner with async/await --- try { await scriptRunner(main, scriptVariables) process.exit() } catch (error) { console.error(error) process.exit(1) }几个使用要点main必须是async函数。因为scriptRunner内部await main(trackProgress)只有异步主函数才能把进度写入和状态上报串在正确的时序上scriptVariables是可选参数默认值为{}它会被原样存入脚本日志的vars字段用来回答“这次执行传了什么参数”scriptRunner的签名还支持另外两个可选参数canonicalName脚本的规范名称默认取进程入参文件名去掉扩展名与scriptPath脚本路径默认取process.argv[1]。绝大多数脚本用默认值即可注意trackProgress返回的是Promisevoid示例中每步都await它保证进度按序写入。执行流程源码剖析scriptRunner的执行流程可以拆成三段全部位于 ScriptRunner.mjs1. 前置判断与初始化beforeScriptExecutionconst isSaaS Boolean(Settings.overleaf) if (!isSaaS) { await main(async message { console.warn(message) }) return }一个容易忽略的细节只有 SaaS 部署Settings.overleaf配置存在时才会写入数据库。在社区版/自建环境中scriptRunner退化为直接调用main且trackProgress只做console.warn——脚本行为不变但不产生数据库日志。这解释了为什么进度功能在开源版上“可用但不持久化”。SaaS 环境下beforeScriptExecution会创建一条 ScriptLog 文档写入canonicalName、filePathAtVersion、podName、username、imageVersion和vars。若脚本由带OL_USERNAME环境变量的用户触发还会在控制台打印一段横幅其中包含直达链接✨ Your script is running! Track progress at: {Settings.adminUrl}/admin/script-log/{log._id}这正是 README 第 4 步所说的“使用控制台输出的 URL 查看脚本状态”的来源——链接是每次执行动态生成的直接定位到本次执行的日志文档。2. 执行期间trackProgress的进度追加async function trackProgress(message) { try { console.warn(message) await ScriptLog.findByIdAndUpdate(logId, { $push: { progressLogs: { timestamp: new Date(), message, }, }, }) } catch (error) { console.error(Error tracking progress:, error) } }每次进度上报通过 MongoDB 的$push往progressLogs数组追加{timestamp, message}同时把消息打到stderrconsole.warn方便看容器日志。注意trackProgress内部做了 try/catch进度写入失败只打印错误不会中断脚本本身——进度追踪是“锦上添花”而非关键路径。3. 收尾状态落库afterScriptExecutiontry { await main(trackProgress) } catch (error) { await afterScriptExecution(logId, error) throw error } await afterScriptExecution(logId, success)main抛错时先写入status: error再把错误向上抛保持脚本进程的退出码语义不变正常返回则写入status: success。afterScriptExecution通过findByIdAndUpdate同时更新status与endTime。ScriptLog 数据模型脚本日志的持久化模型定义在 services/web/app/src/models/ScriptLog.mjs存储于 MongoDB 的scriptLogs集合字段类型说明canonicalNameString脚本规范名默认取自文件名不含扩展名filePathAtVersionString脚本文件路径process.argv[1]imageVersionString来自OL_IMAGE_VERSION未设置时记为unknownpodNameString来自OL_POD_NAME未设置时记为unknownusernameString来自OL_USERNAME未设置时记为unknownstartTimeDate默认Date.now即日志文档创建时间endTimeDate默认null脚本结束时由afterScriptExecution写入statusString枚举pending/success/error默认pendingvarsObject调用scriptRunner时传入的脚本参数progressLogs[{timestamp, message}]trackProgress追加的进度记录文档初始状态是pending只有脚本真正走到末尾无论成功或抛错才会流转为终态。从源码结构看这意味着如果一个 Pod 在脚本运行中被杀掉会留下一条pending的悬挂日志——排查长时间任务时可据此判断脚本是否异常中断。在 SaaS 侧迁移脚本 为scriptLogs集合建立了canonicalName_1与username_1两个索引支撑管理后台按脚本名和执行人查询日志列表。通过 ESLint 规则强制使用Script Runner 不是“建议”而是“规范”。Overleaf 自研的 ESLint 插件提供了一条名为overleaf/require-script-runner的规则见 libraries/eslint-plugin/require-script-runner.jsImportDeclaration(node) { if (node.source.value.endsWith(lib/ScriptRunner.mjs)) { hasImport true } }, Program:exit() { if (!hasImport) { context.report({ loc: { line: 1, column: 0 }, message: Please use Script Runner for scripts. ..., }) } }规则逻辑很直接检查services/web/scripts下脚本的顶层 import只要没有任何一条以lib/ScriptRunner.mjs结尾就在文件首行报告错误。这正是 ScriptRunner.mjs 文件头部写着/* eslint-disable overleaf/require-script-runner */注释并标注 “ThisisScriptRunner” 的原因——它是唯一豁免自己这条规则的脚本。查看执行结果执行记录统一在管理后台的/admin/script-logs页面查看单条日志详情路径为/admin/script-log/{logId}。该菜单的可见条件写在 navbar-marketing.pug 中- var canDisplayScriptLogMenu hasFeature(saas) hasAdminCapability(view-script-log, false) canDisplayAdminMenu即需要 SaaS 特性开关、view-script-log管理权限且处于可显示管理菜单的状态前端组件 admin-menu.tsx 据此渲染 “View Script Logs” 入口。这与前文源码剖析一致数据库日志链路本身也只对 SaaS 部署启用自建社区版运行脚本时直接查看容器标准输出即可。小结Script Runner 用约 80 行代码解决了一个普遍痛点一次性运维脚本执行后可观测性为零。它的分工非常清晰——调用方只负责写async main(trackProgress)框架负责日志文档生命周期pending → success/error、进度时间线progressLogs数组和环境快照Pod、用户、镜像版本配合 ESLint 规则强制接入再配合管理后台的 Script Logs 页面形成了从“触发脚本”到“审计执行历史”的闭环。在为 Overleaf 的services/web新增数据修复或迁移脚本时直接参照 track_progress.mjs 的结构并调用scriptRunner即可。【免费下载链接】overleafA web-based collaborative LaTeX editor项目地址: https://gitcode.com/GitHub_Trending/ov/overleaf创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。