java实现退出功能 退出功能怎么实现java_进程退出


很多情况,当我们的服务进程遇到异常退出了,我们希望它能立即再起来。

大部分情况下,我们可以使用 Shell 脚本来做。写一个 while,定期检查进程还在不在。如果不在了,则立即启动。

类似如下:


while true do
  sleep 10
  if [ `pgrep my_server` == '' ]; then
    my_server -x aa -y bb &
  fi
done


这种非常简单,也非常粗暴。

但是,由于它是定期去查的,这个 sleep 的时间有点考究。设备长了,进程退了,最长也要一个sleep周期才能被检查重启。设置小了,CPU会花大量的时候做这个检查,很不值得。

另一种做法呢,就是利用父进程能使用 wait() 获取子进程状态的机制来实现。

父进程使用 fork() 创建了一个子进程,由子进程来跑业务逻辑,而父进程什么都不做,就阻塞调用 wait() 等子进程的状态化。一旦子进程退出或出异常,wait() 函数就会返回,那么父进程就知道子进程退出了。

对于服务器程序来说,服务器退出是不正常的。于是父进程就立即再 fork() 一个新的子进程来路业务逻辑。从而实现了业务进程异常退出立即重启的功能。

如果为核心的代码:


#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>

void EnableResurrection()
{
    pid_t cpid, w;
    int wstatus;

    while (1) {
        cpid = fork();
        if (cpid == -1) {
            perror("fork");
            exit(EXIT_FAILURE);
        }

        if (cpid == 0) {
            /* Code executed by child */
            printf("Child PID is %ldn", (long) getpid());
            return;
        }

        /* Code executed by parent */
        do {
            w = waitpid(cpid, &wstatus, WUNTRACED | WCONTINUED);
            if (w == -1) {
                perror("waitpid");
                exit(EXIT_FAILURE);
            }

            if (WIFEXITED(wstatus)) {
                printf("exited, status=%dn", WEXITSTATUS(wstatus));
            } else if (WIFSIGNALED(wstatus)) {
                printf("killed by signal %dn", WTERMSIG(wstatus));
            } else if (WIFSTOPPED(wstatus)) {
                printf("stopped by signal %dn", WSTOPSIG(wstatus));
            } else if (WIFCONTINUED(wstatus)) {
                printf("continuedn");
            }
        } while (!WIFEXITED(wstatus) && !WIFSIGNALED(wstatus));
    }
}


EnableResurrection() 意为“复活”,其函数实现也非常简单。

函数一直来,就 fork() 一个子进程,让子进程直接返回了。而父进程,就使用 waitpid() 等待子进程退出。一旦父进程等到了子进程退出,就立即再 fork() 一个新的子进程。从而达到了业务进程一旦退出,就立即恢复的效果。

当一个程序需要复活功能的时候,它只需要在真正开始业务之前调用一下该函数,就能神奇地达到业务进程退出立即“复活”的效果。

如下:


void DoSomething()
{
    char *dangle_ptr = NULL;
    strcpy(dangle_ptr, "hello");  //! 这里会出段错误
}

int main(int argc, char *argv[])
{
    EnableResurrection();

    while (1) {
        sleep(1);
        DoSomething();
    }

    return 0;
}


如上,从业务程序的角度上看,执行完 EnableResurrection() 之后,进程像是保存了一个状态。每当业务进程跑崩了,它都能从 EnableResurrection() 返回处重新运行。

除了上述的功能。我们还可以给它一些附加的功能。比如:异常日志记录、异常统计与分析、异常规避与修复等。