使用自定义远程缓存时Nx Daemon停止工作的问题排查
当使用搭载自定义远程缓存的自定义任务运行器构建Angular应用时,Nx Daemon停止工作。常规的修复操作(比如重启Daemon、清理缓存)都无法解决问题,怀疑是自定义远程缓存的store方法实现存在问题。
自定义缓存 store 方法代码
store = async (hash: string, cacheDirectory: string): Promise<boolean> => { console.debug('writing in cache...'); console.debug(`hash: ${hash}`); const hashCommit = hash + '.commit'; const localCommit = path.join(cacheDirectory, hashCommit); const local = path.join(cacheDirectory, hash); const zipped = zip(local); const blobContainer = getBlobContainer( this.connectionString, this.container ); const remote = blobContainer.getBlockBlobClient(`${hash}.zip`); const remoteCommit = blobContainer.getBlockBlobClient(hashCommit); await remote.uploadData(zipped); await remoteCommit.uploadFile(localCommit); return Promise.resolve(true); };
Nx Daemon 错误提示及日志
NX 无法启动或连接到Nx Daemon进程。
日志信息:
[NX Daemon Server] - 2022-12-24T22:56:35.583Z - [REQUEST]: 收到客户端的项目图请求
[NX Daemon Server] - 2022-12-24T22:56:35.635Z - [REQUEST]: 根据监听的变更更新文件哈希器,重新计算项目图...
[NX Daemon Server] - 2022-12-24T22:56:36.541Z - 开始监听:\.\pipe\nx\C:\Users\stefa\AppData\Local\Temp\78c4dcdc4cfc72d78c62\d.sock
[NX Daemon Server] - 2022-12-24T22:56:37.033Z - 已建立连接。当前开放连接数:1
[NX Daemon Server] - 2022-12-24T22:56:37.034Z - 已建立连接。当前开放连接数:2
[NX Daemon Server] - 2022-12-24T22:56:37.035Z - [WATCHER]: 已订阅目录变更:c:\Users\stefa\Local_Storage\projects\nx-giant
[NX Daemon Server] - 2022-12-24T22:56:37.037Z - [REQUEST]: 收到客户端的项目图请求
[NX Daemon Server] - 2022-12-24T22:56:37.073Z - [REQUEST]: 根据监听的变更更新文件哈希器,重新计算项目图...
[NX Daemon Server] - 2022-12-24T22:56:37.327Z - [REQUEST]: 正在向客户端响应项目图
[NX Daemon Server] - 2022-12-24T22:56:37.331Z - 创建并序列化项目图总耗时:289.47169998288155ms
[NX Daemon Server] - 2022-12-24T22:56:37.335Z - 已关闭连接。当前开放连接数:1
[NX Daemon Server] - 2022-12-24T22:56:37.335Z - 已完成向客户端响应项目图
[NX Daemon Server] - 2022-12-24T22:56:37.614Z - 已建立连接。当前开放连接数:2
[NX Daemon Server] - 2022-12-24T22:56:37.614Z - 已建立连接
[NX Daemon Server] - 2022-12-24T22:56:37.618Z - [REQUEST]: 正在向客户端响应项目图
[NX Daemon Server] - 2022-12-24T22:56:37.622Z - 创建并序列化项目图总耗时:0.30550000071525574ms
[NX Daemon Server] - 2022-12-24T22:56:37.622Z - 已完成向客户端响应项目图
问题排查与修复
1. 核心问题分析
- 同步操作阻塞主线程:Nx Daemon是单进程服务,所有任务都在主线程执行。如果
zip(local)是同步阻塞式压缩,当缓存目录内容较大时,会长时间占用主线程,导致Daemon无法响应其他请求,最终被判定为无响应而终止。 - 未处理的异常:代码中没有异常捕获逻辑,压缩或远程上传过程中出现的错误(如文件缺失、网络故障、权限问题)会直接抛出未捕获异常,导致Daemon进程崩溃。
- 冗余Promise处理:异步函数本身返回Promise,无需额外
Promise.resolve(true),虽不直接引发崩溃,但属于不必要的冗余代码。
2. 修复后的代码
store = async (hash: string, cacheDirectory: string): Promise<boolean> => { console.debug('writing in cache...'); console.debug(`hash: ${hash}`); const hashCommit = hash + '.commit'; const localCommit = path.join(cacheDirectory, hashCommit); const local = path.join(cacheDirectory, hash); try { // 改用异步压缩避免阻塞主线程,若现有库无异步API,可封装子进程或更换库(如archiver) const zipped = await zipAsync(local); const blobContainer = getBlobContainer( this.connectionString, this.container ); const remote = blobContainer.getBlockBlobClient(`${hash}.zip`); const remoteCommit = blobContainer.getBlockBlobClient(hashCommit); // 并行上传提升效率,减少等待时间 await Promise.all([ remote.uploadData(zipped), remoteCommit.uploadFile(localCommit) ]); return true; } catch (err) { console.error('缓存存储失败:', err); // 捕获异常并返回false,避免Daemon崩溃 return false; } };
3. 额外优化建议
- 确保压缩操作异步化:如果当前使用的压缩库只有同步API,建议更换为支持异步的库(如
archiver),或把压缩逻辑放到子进程中执行,彻底避免阻塞Daemon主线程。 - 增加前置校验:在压缩前检查
local和localCommit文件是否存在,提前拦截文件缺失的错误。 - 细化错误日志:在异常捕获中记录错误栈、文件路径等信息,方便后续快速定位问题。
内容的提问来源于stack exchange,提问作者Stefan

