• 发生时间:2022-10-25

  • 问题描述:

    • 我想将一个文件上传服务 upload-server 简单部署到服务器,以方便平时上传一些文件到服务器。
    • 我首先将 upload-server 二进制文件通过 scp 远程拷贝到服务器的特定目录下。
    • 然后使用 ssh 登录服务器,进入上述目录,输入 ./upload-server &,让文件上传服务在后台运行。
    • 接着我在本地简单测试了一下上传功能,验证 OK 后,便输入 exit 退出服务器。
    • 过了一段时间,我再次上传文件却失败了,报错 404 Not Found,登录服务器,使用 ps 发现找不到 upload-server 进程了!
  • 问题类别:软件部署

  • 原因分析:

    • 我重新输入 ./upload-server & 命令,本地验证 OK 后,输入 exit 以退出服务器,发现服务器终端输出一行提示(如下所示)。 它在提醒我还有正在运行的服务。这不废话吗?我的文件上传服务当然正在运行中。
    wuhualong@server [08:06:58 PM] [~]
    -> % exit
    zsh: you have running jobs.
    
    • 于是我再次输入 exit,这次终于退出服务器了,但终端仍然打印一行提示(如下所示),它提示说一个任务接收到 SIGHUP 信号。
    wuhualong@server [08:07:00 PM] [~]
    -> % exit
    zsh: warning: 1 jobs SIGHUPed
    Connection to pa.minieye.tech closed.
    
    • 使用 man -7 signal 查看 SIGHUP 的相关描述,发现 SIGHUP 信号的默认处理是终止进程。难道我的 upload-server 已经被终止了?
    • 重新 ssh 登录服务器,使用 ps 发现 upload-server 进程果然又没有了!
    • 经过网上调查,在 stack overflow 找到原因:zsh 创建后台进程需要使用 &!,并非像 bash 那样使用 & 创建后台进程!
  • 解决方案:改用 ./upload-server &! 来创建后台进程。

  • 实施结果:修改完成并退出服务器后,可以正常访问服务器的文件上传服务。

  • 经验总结:

    • bash 创建后台进程使用 &,zsh 创建后台进程使用 &!,要注意两者的区别。
    • 如果想让后台进程在终端关闭时仍能运行,正确写法为:nohup ./upload-server >/dev/null 2>&1 &!
    • 不同的 shell 确实存在兼容性问题,这点也需要注意。之前看过的一篇博客 Shell Script Best Practices 就建议尽量只用 bash。