• Node中异常:exit code与 dockerfile


    最近观察项目 CI 跑的情况如何时,会偶尔发现一两个镜像虽然构建成功但是容器跑不起来的情况。究其原因,是因为一个 exit code 的问题

    throw new Error 与 Promise.reject 区别

    以下是两段代码,第一个是抛出一个异常,第二个是 Promise.reject,两段代码都会如下打印出一段异常信息,那么两者有什么区别?

    function error () {
      throw new Error('hello, error')
    }
    
    error()
    // /Users/shanyue/Documents/note/demo.js:2
    //   throw new Error('hello, world')
    //   ^
    // 
    // Error: hello, world
    //     at error (/Users/shanyue/Documents/note/demo.js:2:9)
    //     at Object.<anonymous> (/Users/shanyue/Documents/note/demo.js:5:1)
    //     at Module._compile (internal/modules/cjs/loader.js:701:30)
    async function error () {
      return new Error('hello, error')
    }
    
    error()
    
    // (node:60356) UnhandledPromiseRejectionWarning: Error: hello, world
    //    at error (/Users/shanyue/Documents/note/demo.js:2:9)
    //    at Object.<anonymous> (/Users/shanyue/Documents/note/demo.js:5:1)
    //    at Module._compile (internal/modules/cjs/loader.js:701:30)
    //    at Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)

    从一个比较底层的角度来说,两者的 exit code 不一样,那 exit code 是什么东西?

    exit code

    exit code 代表一个进程的返回码,通过系统调用 exit_group 来触发。在 POSIX 中,0 代表正常的返回码,而 1-255代表异常返回码,不过一般错误码都是 1。这里有一张附表 Appendix E. Exit Codes With Special Meanings

    所以,在 node 的应用中经常会有 process.exit(1) 来代表因为不期望的异常而中断。

    现在看一个关于 cat 的异常以及它的 exit code 与系统调用

    $ cat a
    cat: a: No such file or directory
    
    # -e 代表只显示 write 与 exit_group 的系统调用
    $ strace -e write,exit_group cat a
    write(2, "cat: ", 5cat: )                    = 5
    write(2, "a", 1a)                        = 1
    write(2, ": No such file or directory", 27: No such file or directory) = 27
    write(2, "
    ", 1
    )                       = 1
    exit_group(1)                           = ?
    +++ exited with 1 +++

    可以看出,它的 exit code 是 1,并且把错误信息写到 stderr (标准错误的 fd 为2) 中了

    广州品牌设计公司https://www.houdianzi.com PPT模板下载大全https://redbox.wode007.com

    如何查看 exit code

    其实从上边的内容可以看出,可以使用 strace 来判断进程的 exit code。但是这样实在太不方便了,特别是在 shell 编程环境中。

    有一种简单的方法,通过 echo $? 来输出返回码

    $ cat a
    cat: a: No such file or directory
    
    $ echo $?
    1

    在对上述两个测试用例查看 exit code,我们会发现 throw new Error() 的 exit code 为 1,而 Promise.reject() 的为 0。

     

    Dockerfile 在 node 中的注意点

    node 中的异常与 exit code 都说完了,接下来该说与 Dockerfile 的关联了。

    当使用 Dockerfile 构建镜像时,如果其中 RUN 的进程返回非0的返回码,则构建就会失败。

    而在 Node 中的错误处理中,我们倾向于所有的异常都交由 async/await 来处理,而当发生异常时,由于此时 exit code 为 0 并不会导致镜像构建失败。 如下所示

    FROM node:alpine
    
    RUN node -e "Promise.reject('hello, world')"
    $ docker build -t demo .
    Sending build context to Docker daemon  14.85kB
    Step 1/2 : FROM node:alpine
     ---> d97a436daee9
    Step 2/2 : RUN node -e "Promise.reject('hello, world')"
     ---> Running in 0281c660ab82
    (node:1) UnhandledPromiseRejectionWarning: hello, world
    (node:1) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
    (node:1) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
    Removing intermediate container 0281c660ab82
     ---> 2146545654d2
    Successfully built 2146545654d2
    Successfully tagged demo:latest

    而在编译时能发现的问题,绝不要放在运行时。所以,构建镜像需要执行 node 的脚本时,对异常处理需要手动指定 1 的 exit code:process.exit(1)。

    runScript().catch(() => {
      process.exit(1)
    })
    <hr/>
  • 相关阅读:
    Android源码之Gallery专题研究(2)
    Android源码之Gallery专题研究(1)
    Android UI 优化——使用HierarchyViewer工具
    如何打开USB OTG功能:
    JavaSE入门学习5:Java基础语法之keyword,标识符,凝视,常量和变量
    Multiply Strings
    android动态控制组件的位置、大小和新的动画
    linux系统编程:线程同步-信号量(semaphore)
    imx6q GPIO功能的用法
    NoSQL数据库概览及其与SQL语法的比較
  • 原文地址:https://www.cnblogs.com/qianxiaox/p/14119868.html
Copyright © 2020-2023  润新知