守护进程

遇到个奇怪事儿,在轻量应用服务器上开启定时任务时,有两种方法可以实现,但是其中一种方法会出现 MySQL 报错,而另外一种则可以正常运行。

方法一:

crontab -e

该方法添加定时任务后,MySQL 在执行过程中,会报如下错误:

Traceback (most recent call last):
  File "/root/anaconda3/envs/spider/lib/python3.8/site-packages/mysql/connector/connection_cext.py", line 705, in cmd_query
    self._cmysql.query(
_mysql_connector.MySQLInterfaceError: Lost connection to MySQL server during query

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/root/anaconda3/envs/spider/lib/python3.8/site-packages/twisted/internet/defer.py", line 1078, in _runCallbacks
    current.result = callback(  # type: ignore[misc]
  File "/root/anaconda3/envs/spider/lib/python3.8/site-packages/scrapy/utils/defer.py", line 340, in f
    return deferred_from_coro(coro_f(*coro_args, **coro_kwargs))
  File "/root/magazines_spider/magazines_spider/pipelines.py", line 42, in process_item
    self.cur.execute("""select id from magazines where title_zh = %s""", (str(item['title_zh']),))
  File "/root/anaconda3/envs/spider/lib/python3.8/site-packages/mysql/connector/cursor_cext.py", line 357, in execute
    result = self._connection.cmd_query(
  File "/root/anaconda3/envs/spider/lib/python3.8/site-packages/mysql/connector/opentelemetry/context_propagation.py", line 97, in wrapper
    return method(cnx, *args, **kwargs)
  File "/root/anaconda3/envs/spider/lib/python3.8/site-packages/mysql/connector/connection_cext.py", line 713, in cmd_query
    raise get_mysql_exception(
mysql.connector.errors.OperationalError: 2013 (HY000): Lost connection to MySQL server during query


方法二:

手写守护进程,定时执行相关任务。

所谓守护进程,就是没有父进程的孤立进程,该进程可以在后台持续运行。在命令行中创建的进程,都属于该终端 tty 的子进程,当前终端关闭后,由该终端派生出的子进程都会随之结束。


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

#include <time.h>
#include <unistd.h>

int main() {
  pid_t pid;
  time_t t;

  // 创建子进程,父进程退出
  if ((pid = fork()) < 0) {
    perror("fork");
    exit(-1);
  } else if (pid > 0) {
    exit(0);
  } 
  
  // 创建新会话,与原先终端脱离
  if (setsid() < 0) {
    perror("setsid");
    exit(0);
  }

  // 更改当前工作目录
  chdir("/");

  // 重设文件权限掩码
  if (umask(0) < 0) {
    perror("unmask");
    exit(0);
  }   

  while(1) {
    time_t now = time(NULL);
    struct tm tm_now;
    localtime_r(&now, &tm_now);
    char buff[100];
    strftime(buff, sizeof(buff), "%H:%M", &tm_now);
    if (!strcmp(buff, "02:25")) {
      if ((pid = fork()) < 0) {
        perror("fork");
        exit(-1);
      } else if (pid > 0) {
        sleep(100);
      } else {
        worker();
      }
    }
    sleep(10);
  }

  return 0;
}

void worker() {
  if (execl("/bin/sh", "sh", "/root/magazines_spider/run.sh",  NULL) < 0) {
    printf("execl error!\n"); 
  }
  return ;
} 

使用这种方法就不会报错,不知道是什么原因导致的?