【问题标题】:uglify crashing after running child_process.execFile运行 child_process.execFile 后 uglify 崩溃
【发布时间】:2016-08-28 07:15:13
【问题描述】:

编辑 2

我“解决”了这个问题,但我不想将它作为答案发布,因为它没有解释实际发生的事情。在我使用的 .NET resourceReader.exe 代码中

Console.OutputEncoding = System.Text.Encoding.UTF8;

将国际化资源以 unicode 格式输出到stdout。如果我在程序结束时使用

重置编码
Console.OutputEncoding = System.Text.Encoding.Default;

那么我在 Node.js 中没有收到任何错误。如果我不重置它,我会收到原始问题中描述的错误。 .NET 似乎以某种方式弄乱了cmd.exe 上的一些输出编码设置,并导致后续节点运行失败!

编辑

我将错误范围缩小为由resourceReader.exe 引起的。这是一个.NET 程序,它从.NET 程序集中读取一些资源流,并使用Console.WriteLine 将它们打印到标准输出。我将Console.OutputEncoding = System.Text.Encoding.UTF8 添加到resourceReader.exe,因为某些资源是非ASCII 字母,这就是导致崩溃的原因!

如果我去掉那行,任务不会崩溃,但资源会以不可打印的 ASCII 字符显示!此外,只有当我实际将非 ASCII 打印到 sdtout 时才会发生崩溃。如果我不打印它们,它不会出错。

原创

我在 Gruntfile 中添加了一个步骤,它使用 child_process.execFile 从外部程序运行读取一些数据并在构建中使用它。现在,每当我运行构建时,它第一次运行良好,但第二次崩溃!

这是崩溃的输出(这是在 uglify 任务期间):

File build/Scripts/NDB.contacts.min.js created: 16.85 kBevents.js:85
  throw er; // Unhandled 'error' event
        ^
Error: This socket is closed.
  at WriteStream.Socket._writeGeneric (net.js:656:19)
  at WriteStream.Socket._write (net.js:709:8)
  at doWrite (_stream_writable.js:301:12)
  at writeOrBuffer (_stream_writable.js:288:5)
  at WriteStream.Writable.write (_stream_writable.js:217:11)
  at WriteStream.Socket.write (net.js:634:40)
  at Log._write (C:\...\node_modules\grunt\node_modules\grunt-legacy-log\index.js:161:26)
  at Log.wrapper [as _write] (C:\...\node_modules\grunt\node_modules\grunt-legacy-log\node_modules\lodash\index.js:3095:19)
  at Log._writeln (C:\...\node_modules\grunt\node_modules\grunt-legacy-log\index.js:166:8)
  at Log.wrapper [as _writeln] (C:\...\node_modules\grunt\node_modules\grunt-legacy-log\node_modules\lodash\index.js:3095:19)
  at Log.writeln (C:\...\node_modules\grunt\node_modules\grunt-legacy-log\index.js:177:8)
  at Log.wrapper (C:\...\node_modules\grunt\node_modules\grunt-legacy-log\node_modules\lodash\index.js:3095:19)
  at writeln (C:\...\node_modules\grunt\lib\grunt\fail.js:30:13)
  at Object.fail.fatal (C:\...\node_modules\grunt\lib\grunt\fail.js:46:3)
  at process.uncaughtHandler (C:\...\node_modules\grunt\lib\grunt.js:121:10)
  at process.emit (events.js:129:20)
  at process._fatalException (node.js:236:26)
  at Task.runTaskFn (C:\...\node_modules\grunt\lib\util\task.js:250:7)
  at Task.<anonymous> (C:\...\node_modules\grunt\lib\util\task.js:293:12)
  at C:\...\node_modules\grunt\lib\util\task.js:220:11
  at process._tickCallback (node.js:355:11)

这是使用 child_process 的任务的代码。

    function readAllCultures() {
        var readDeferred = q.defer();

        childProc.execFile("../tools/resourceReader.exe", function (err, stdout, stderr) {
            if (err) throw new Error(err);

            var cultures = JSON.parse(stdout);
            readDeferred.resolve(cultures);
        });

        return readDeferred.promise;
    }

以下是我发现调试可能有用的一些事情

  1. 如果我重定向 grunt 的输出(使用 &gt; filename| process),它运行良好
  2. 当我重定向输出时,我从来没有看到来自 uglify 的消息表明它创建了主输出,只有它创建了源映射。
  3. 如果我关闭并重新打开命令提示符 (cmd.exe),它可以正常工作
  4. 我使用rdr.on("close", function() { console.log("close"); }); 为子进程的exitclose 事件添加了一个侦听器,退出也是如此。在第一次运行中,这两个事件都按预期触发。
  5. 使用 Process Explorer,我可以看到 node.exe 在命令提示符下打开,并在我的命令运行完毕后再次关闭。命令提示符下没有明显“保持打开状态”的进程。

【问题讨论】:

  • 我认为您的程序在您第一次 Grunt 调用后仍在后台运行,请使用 htop 确认。
  • @RaNdoM_PoWneD 我在 Windows 上。我没有看到它在进程管理器中运行。
  • 对不起,我没有更多的想法:/我觉得有些东西没有很好地终止(比如一个开放的管道,一个套接字......)阻止新实例运行。祝你好运
  • 顺便说一句,您应该使用 return readDeferred.reject() 而不是从回调处理程序中抛出。
  • @just.another.programmer:当您查看 grunt-legacy-log 正在做什么时,重定向会影响这一点是有道理的。如果你看这里:github.com/gruntjs/grunt-legacy-log/blob/master/index.js#L161(在堆栈跟踪中找到)试图写入的“套接字”似乎是标准输出

标签: c# .net node.js gruntjs child-process


【解决方案1】:

堆栈跟踪最终显示socket.write 错误的事实很有趣。您提供的代码中没有任何内容表明您正在尝试写入套接字。

如果我们沿着堆栈向下,我们可以看到它实际上是在尝试写入套接字,因为它正在尝试记录未捕获的异常。

所以,首先你的 grunt 任务会抛出一个当前未知的错误,然后 grunt 本身会出错,因为它无法告诉你。

我会首先尝试记录您的子进程中发生的错误。目前,如果出现错误,您只需throw 即可,而不会找出它是什么。这很可能是 grunt 正在尝试但未能记录的原因。

替换

if (err) throw new Error(err);

if (err) console.error(err);

这有望避免socket.write 问题,并为您提供有关子进程发生错误的具体信息。你看到了什么?

其次,我会尝试使用child_process.exec 而不是child_process.execFile。这将生成一个 shell 并在其中运行resourceReader.exe(而不是直接运行它)。这可能有助于避免您在后台运行/失败的命令时遇到的任何问题,这可能是导致 socket.write 错误的原因。

【讨论】:

  • 我的阅读文化任务在 uglify 任务之后运行。我尝试了您的建议,但对输出没有任何改变。
猜你喜欢
  • 1970-01-01
  • 2014-04-17
  • 2015-04-27
  • 1970-01-01
  • 1970-01-01
  • 2017-11-02
  • 1970-01-01
  • 2022-01-22
  • 2017-05-01
相关资源
最近更新 更多