systemctl使用reload及踩坑

systemctl使用reload及踩坑1 demo service 文件 Unit Description demo demoserverDo http git demo com demoAfter network targetremote fs targetnss lookup target Service Type sampleUser rootPIDFile run demo

systemctl使用reload及踩坑

1.demo.service文件

[Unit] Description=demo - demo server Documentation=http://git.demo.com/demo After=network.target remote-fs.target nss-lookup.target [Service] Type=sample User=root PIDFile=/run/demo.pid ExecStart=/home/codes/test/src/demo/demo/demo ExecReload=/bin/kill -s HUP $MAINPID ExecStop=/bin/kill -s QUIT $MAINPID Restart=0 LimitNOFILE=65536 [Install] WantedBy=multi-user.target 

[Unit]主要是描述和规定启动前后的顺序依赖关系

[Service]主要是核心的控制语句

[Install]主要是定义服务启动相关

2.程序代码

这里使用go做一个简单的信号量的捕获,

func main() { 
    go signalHandle() // 信号量处理函数 http.ListenAndServe("localhost:8080", nil) // 用于将进程挂起,避免退出 } func signalHandle() { 
    ch := make(chan os.Signal) signal.Notify(ch, syscall.SIGHUP) sig := <-ch for { 
    fmt.Printf("Signal received: %v", sig) if sig == syscall.SIGHUP { 
    fmt.Println("syscall.SIGHUP") writeFile("syscall.SIGHUP received") return } } } func writeFile(wiriteString string) { 
    var filename = "/home/codes/test/src/demo/demo/output.txt" var f *os.File f, err := os.Create(filename) if err != nil { 
    fmt.Println(err) return } l, err := f.WriteString(wiriteString) if err != nil { 
    fmt.Println(err) f.Close() return } fmt.Println(l, "bytes written successfully") err = f.Close() if err != nil { 
    fmt.Println(err) return } } 

3.测试

情况一:

实验步骤:

[root@bogon demo]# cat output.txt  [root@bogon demo]# systemctl start demo.service  [root@bogon demo]# ps -ef|grep demo root 41159 1 0 14:30 ? 00:00:00 /home/codes/test/src/demo/demo/demo root 41168 37883 0 14:30 pts/3 00:00:00 grep --color=auto demo [root@bogon demo]# systemctl reload demo.service  [root@bogon demo]# cat output.txt  syscall.SIGHUP received[root@bogon demo]#  

systemctl start可以启动,进程存在,执行reload,进程可以捕获到SIGHUP信号量,执行了写文件操作,文件中输出syscall.SIGHUP received。

情况二:

有时候进程在启动时去读取配置文件,然后初始化log配置,及log输出路径后才会实现日志记录,在此之前或者有些没有打印日志的位置,怕程序跑飞,往往会用重定向来记录控制台日志,例如go的fmt。

service文件中ExecStart、ExecReload、ExecStop是不支持> 、>>等重定向符号的,这里可以用/bin/sh -c来实现。例如:

ExecStart=/bin/sh -c '/home/codes/test/src/demo/demo/demo >>/home/codes/test/src/demo/demo/reload.log 2>&1' 

实验步骤:

[root@bogon system]# systemctl daemon-reload  [root@bogon system]# systemctl start demo.service  [root@bogon system]# systemctl reload demo.service  Job for demo.service failed because the control process exited with error code. See "systemctl status demo.service" and "journalctl -xe" for details. [root@bogon system]# systemctl status demo.service ● demo.service - demo - demo server Loaded: loaded (/usr/lib/systemd/system/demo.service; disabled; vendor preset: disabled) Active: failed (Result: exit-code) since Thu 2019-07-11 14:42:33 CST; 1min 13s ago Docs: http://git.jd.com/database/jdcloud-rds Process: 41395 ExecStop=/bin/kill -s QUIT $MAINPID (code=exited, status=1/FAILURE) Process: 41394 ExecReload=/bin/kill -s HUP $MAINPID (code=exited, status=0/SUCCESS) Process: 41372 ExecStart=/bin/sh -c /home/codes/test/src/demo/demo/demo >>/home/codes/test/src/demo/demo/reload.log 2>&1 (code=killed, signal=HUP) Main PID: 41372 (code=killed, signal=HUP) Jul 11 14:42:33 bogon kill[41395]: -p, --pid print pids without signaling them Jul 11 14:42:33 bogon kill[41395]: -l, --list [=<signal>] list signal names, or convert one to a name Jul 11 14:42:33 bogon kill[41395]: -L, --table list signal names and numbers Jul 11 14:42:33 bogon kill[41395]: -h, --help display this help and exit Jul 11 14:42:33 bogon kill[41395]: -V, --version output version information and exit Jul 11 14:42:33 bogon kill[41395]: For more details see kill(1). Jul 11 14:42:33 bogon systemd[1]: demo.service: control process exited, code=exited status=1 Jul 11 14:42:33 bogon systemd[1]: Reload failed for demo - demo server. Jul 11 14:42:33 bogon systemd[1]: Unit demo.service entered failed state. Jul 11 14:42:33 bogon systemd[1]: demo.service failed. 

发现reload是报错的,查看status,发现ExecStop=/bin/kill -s QUIT $MAINPID (code=exited, status=1/FAILURE)失败。此时进程已经被杀掉了,执行systemctl strat将服务启动:

[root@bogon system]# ps -ef|grep demo root 41435 1 0 14:45 ? 00:00:00 /bin/sh -c /home/codes/test/src/demo/demo/demo >>/home/codes/test/src/demo/demo/reload.log 2>&1 root 41436 41435 0 14:45 ? 00:00:00 /home/codes/test/src/demo/demo/demo root 41444 37883 0 14:45 pts/3 00:00:00 grep --color=auto demo 

可以看到,这次/bin/sh -c命令循环fork出了两个子进程,41435是该进程组的首进程,负责与终端tty交互,41436才是真正的demo进程,当执行reload时,实际上执行了ExecReload=/bin/kill -s HUP M A I N P I D , 这 个 MAINPID,这个 MAINPIDMAINPID其实是41435,此时的reload信号量是发给了首进程(41435),进程如果没做信号量的捕获,默认是执行中断操作,与此同时会给子进程发送SIGTREM信号杀掉子进程,所以systemctl命令报了错误。

如果在这种情况下还想实现reload,可以换一种实现方法,就是查到demo进程的真实pid,修改如下:

ExecReload=/bin/sh -c '/bin/kill -HUP $(pidof /home/codes/test/src/demo/demo/demo)' 

通过pidof /home/codes/test/src/demo/demo/demo获取进程的pid,执行kill -HUP。

[root@bogon system]# systemctl start demo.service  [root@bogon system]# ps -ef|grep demo root 42728 1 0 15:26 ? 00:00:00 /bin/sh -c /home/codes/test/src/demo/demo/demo >/home/codes/test/src/demo/demo/reload.log 2>&1 root 42729 42728 0 15:26 ? 00:00:00 /home/codes/test/src/demo/demo/demo root 42736 37883 0 15:26 pts/3 00:00:00 grep --color=auto demo [root@bogon system]# systemctl reload demo.service  [root@bogon system]# cat /home/codes/test/src/demo/demo/reload.log  Signal received: hangupsyscall.SIGHUP 23 bytes written successfully 

这次可以看到reload没有报错,进程成功进到HUP信号量,cat reload.log 文件可以看到成功写入文件。

补充:为什么加入重定向就会循环fork出两个进程?

/bin/sh -c的原理就是fork+exec来产生一个进程,次进程是无法与tty(控制台)交互的后台进程,重定向需要与tty(控制台)交互,所以先fork出来一个重定向进程,再fork出一个真正的demo进程。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/232412.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • GBDT算法简介_gbdt算法原理

    GBDT算法简介_gbdt算法原理在网上看到一篇GBDT介绍非常好的文章,GBDT大概是非常好用又非常好用的算法之一了吧(哈哈两个好的意思不一样)        GBDT(Gradient Boosting Decision Tree) 又叫 MART(Multiple Additive Regression Tree),是一种迭代的决策树算法,该算法由多棵决策树组成,所有树的结论累加起来做最终答

    2022年10月12日
    2
  • JQuery的submitHandler

    之前做表单验证,有设置submitHandlersubmitHandler:function(){$(“form”).submit();}这样表单验证通过后会自动提交。。。。改为submitHandler:function(form){form.submit();}否则,button按钮提交表单之后,表单会提交两次,前端造成stack溢出…

    2022年4月5日
    273
  • chinese zodiac signs_icpc铜奖

    chinese zodiac signs_icpc铜奖输入23 14 3输出Impossible2 1 4 33 4 1 24 3 2 1题解 找规律+构造#include<bits/stdc++.h>using namespace std;const int N = 1001;int ch[N][N];int lowbit(int x){ return x & (-x);}int main(){ int n,k; int T; cin>>T; ..

    2022年8月11日
    3
  • ostaskcreate函数作用_认识上中下

    ostaskcreate函数作用_认识上中下OSTaskCreate()是学习ucos-Ⅱ操作系统的第一个函数,费了九牛二虎之力,现在感觉差不多可以过了。#ifOS_TASK_CREATE_EN>0INT8UOSTaskCreate(void(*task)(void*p_arg),void*p_arg,OS_STK*ptos,INT8Uprio)/*1*/{ OS_STK…

    2025年9月17日
    4
  • C语言的printf输出格式

    C语言的printf输出格式1、控制小数点后有多少位:printf(“%.10lf\n”,f_a); //将浮点数f_a输出时,输出其小数点后10位,默认是输出小数点后6位。2、控制一共(小数点前后以及小数点)输出多少位:printf(“%10.7f\n”,f_b); //将浮点数f_b输出时,输出其小数点前2位,小数点后7位(加上小数点共10位)。3、输出时让正数带”+”号,负数带”-“号:printf(“%+f\

    2022年7月24日
    16
  • idea大小写切换快捷键 idea大小写转换快捷键[通俗易懂]

    idea大小写切换快捷键 idea大小写转换快捷键[通俗易懂]ctr+shift+u

    2025年8月20日
    14

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号