php-fpm有三种定时器

1)主进程接收到用户的信号,例如sigusr,主进程执行kill(子进程号,sigquit),的同时,设置定时器,在一个无限循环里如果当前时间 大于或等于 该定时器的过期时间,则主进程执行kill(子进程号,sigterm);

2)对于在php-fpm里设置了request_terminate_timeout 和request_slowlog_timeout

  注:set_time_limit()和max_execution_time只影响脚本本身执行的时间。

  (这两个参数在php.ini中)任何发生在诸如使用system()的系统调用,流操作,数据库操作等的脚本执行的最大时间不包括其中.

  建立定时器是在函数fpm_event_loop中的fpm_pctl_heartbeat函数,调用前有个判断条件 fpm_globals.heartbeat需要大于0

在解析php-fpm.conf文件中,fpm_globals.heartbeat最终为request_terminate_timeout和request_slowlog_timeout较小的一个

static int fpm_conf_process_all_pools(){
//省略无关代码 if (wp->config->request_terminate_timeout) {
fpm_globals.heartbeat = fpm_globals.heartbeat ? MIN(fpm_globals.heartbeat, (wp->config->request_terminate_timeout * ) / ) : (wp->config->request_terminate_timeout * ) / ;
} if (wp->config->request_slowlog_timeout) {
fpm_globals.heartbeat = fpm_globals.heartbeat ? MIN(fpm_globals.heartbeat, (wp->config->request_slowlog_timeout * ) / ) : (wp->config->request_slowlog_timeout * ) / ; }
}

/* a minimum of 130ms heartbeat for pctl */

#define FPM_PCTL_MIN_HEARTBEAT (130)

void fpm_pctl_heartbeat(struct fpm_event_s *ev, short which, void *arg) /* {{{ */
{
static struct fpm_event_s heartbeat;
struct timeval now; if (fpm_globals.parent_pid != getpid()) {
return; /* sanity check */
} if (which == FPM_EV_TIMEOUT) {
fpm_clock_get(&now);
fpm_pctl_check_request_timeout(&now);
return;
} /* ensure heartbeat is not lower than FPM_PCTL_MIN_HEARTBEAT */ //这里又和默认的相比,取最大的
fpm_globals.heartbeat = MAX(fpm_globals.heartbeat, FPM_PCTL_MIN_HEARTBEAT); /* first call without setting to initialize the timer */
zlog(ZLOG_DEBUG, "heartbeat have been set up with a timeout of %dms", fpm_globals.heartbeat);
fpm_event_set_timer(&heartbeat, FPM_EV_PERSIST, &fpm_pctl_heartbeat, NULL);
fpm_event_add(&heartbeat, fpm_globals.heartbeat);
}

3)对于dynamic方式的子进程,需要定时检查,例如:当空闲的子进程个数小于允许最小的空闲子进程个数时,需要fork;当空闲的子进程个数大于允许的最大的空闲子进程个数时,需要kill掉

/* 1s (in ms) heartbeat for idle server maintenance */
#define FPM_IDLE_SERVER_MAINTENANCE_HEARTBEAT (1000)

  即每1S执行一次

  假设当前时间为10:00:00,那么超时时间为10:01:00, 在fpm_event_loop这个无限循环中,当 当前 时间 大于或等于这个超时时间时,会触发fpm_pctl_perform_idle_server_maintenance这个函数,当空闲的子进程个数小于允许最小的空闲子进程个数时,需要fork;当空闲的子进程个数大于允许的最大的空闲子进程个数时,需要kill掉,执行完函数后,假设当前时间为10:05:00,那么下一次超时时间为10:06:00,依次类推 ,参考这里

  建立定时器是在函数fpm_event_loop中的fpm_pctl_perform_idle_server_maintenance_heartbeat(NULL, 0, NULL)

  

void fpm_pctl_perform_idle_server_maintenance_heartbeat(struct fpm_event_s *ev, short which, void *arg) /* {{{ */
{
static struct fpm_event_s heartbeat;
struct timeval now; if (fpm_globals.parent_pid != getpid()) {
return; /* sanity check */
} if (which == FPM_EV_TIMEOUT) {
fpm_clock_get(&now);
if (fpm_pctl_can_spawn_children()) {
fpm_pctl_perform_idle_server_maintenance(&now); /* if it's a child, stop here without creating the next event
* this event is reserved to the master process
*/
if (fpm_globals.is_child) {
return;
}
}
return;
} /* first call without setting which to initialize the timer */
fpm_event_set_timer(&heartbeat, FPM_EV_PERSIST, &fpm_pctl_perform_idle_server_maintenance_heartbeat, NULL);
fpm_event_add(&
heartbeat, FPM_IDLE_SERVER_MAINTENANCE_HEARTBEAT);
}

因为是第一次调用 ,所以直接走到倒数第二,第三行, FPM_EV_TIMEOUT 为1

#define FPM_EV_TIMEOUT  (1 << 0)
#define FPM_EV_READ (1 << 1)
#define FPM_EV_PERSIST (1 << 2)
#define FPM_EV_EDGE (1 << 3)
fpm_event_set_timer其实是个宏,
#define fpm_event_set_timer(ev, flags, cb, arg) fpm_event_set((ev), -1, (flags), (cb), (arg))
fpm_event_set中的fd参数传的是-1,因为是定时器,故没有文件描述符,并且调用回调函数
得到现在当前时间,由于是每1分钟执行一次,所以超时时间是当前时间+1分钟
int fpm_event_set(struct fpm_event_s *ev, int fd, int flags, void (*callback)(struct fpm_event_s *, short, void *), void *arg) /* {{{ */
{
if (!ev || !callback || fd < -) {
return -;
}
memset(ev, , sizeof(struct fpm_event_s));
ev->fd = fd;
ev->callback = callback;
ev->arg = arg;
ev->flags = flags;
return ;
}
/* }}} */ int fpm_event_add(struct fpm_event_s *ev, unsigned long int frequency) /* {{{ */
{
struct timeval now;
struct timeval tmp; if (!ev) {
return -;
} ev->index = -; /* it's a triggered event on incoming data */
if (ev->flags & FPM_EV_READ) {
ev->which = FPM_EV_READ;
if (fpm_event_queue_add(&fpm_event_queue_fd, ev) != ) {
return -;
}
return ;
} /* it's a timer event */
ev->which = FPM_EV_TIMEOUT; fpm_clock_get(&now);
if (frequency >= ) {
tmp.tv_sec = frequency / ;
tmp.tv_usec = (frequency % ) * ;
} else {
tmp.tv_sec = ;
tmp.tv_usec = frequency * ;
}
ev->frequency = tmp;
fpm_event_set_timeout(ev, now); //#define fpm_event_set_timeout(ev, now) timeradd(&(now), &(ev)->frequency, &(ev)->timeout); if (fpm_event_queue_add(&fpm_event_queue_timer, ev) != ) {
return -;
} return ;
}

将该定时器放到定时器专属的队列中
static int fpm_event_queue_add(struct fpm_event_queue_s **queue, struct fpm_event_s *ev) /* {{{ */
{
struct fpm_event_queue_s *elt; if (!queue || !ev) {
return -;
} if (fpm_event_queue_isset(*queue, ev)) {
return ;
} if (!(elt = malloc(sizeof(struct fpm_event_queue_s)))) {
zlog(ZLOG_SYSERROR, "Unable to add the event to queue: malloc() failed");
return -;
}
elt->prev = NULL;
elt->next = NULL;
elt->ev = ev; if (*queue) {
(*queue)->prev = elt;
elt->next = *queue;
}
*queue = elt; /* ask the event module to add the fd from its own queue */ //定时器不会走到这里
if (*queue == fpm_event_queue_fd && module->add) {
module->add(ev);
} return ;
}

定时器队列结构体, static struct fpm_event_queue_s *fpm_event_queue_timer = NULL; 是个全局变量

typedef struct fpm_event_queue_s {
struct fpm_event_queue_s *prev;
struct fpm_event_queue_s *next;
struct fpm_event_s *ev;
} fpm_event_queue;

php-fpm定时器的更多相关文章

  1. 纯PHP实现定时器任务(Timer)

    纯PHP实现定时器任务(Timer)   定时器任务,在WEB应用比较常见,如何使用PHP实现定时器任务,大致有两种方案:1)使用Crontab命令,写一个shell脚本,在脚本中调用PHP文件,然后 ...

  2. PHP-max_execution_time与fpm.request_terminate_timeout介绍

    前段时间一位同事跟我说php脚本超时时间以fpm配置优先.经过自己测试后,其实不然,前面的观点只是在某些情况下成立. php脚本超时时间可以在php.ini的max_execution_time和fp ...

  3. Fpm启动机制及流程分析———详细

    FPM(FastCGI Process Manager)是PHP FastCGI运行模式的一个进程管理器,从它的定义可以看出,FPM的核心功能是进程管理,那么它用来管理什么进程呢?这个问题就需要从Fa ...

  4. Objective-C三种定时器CADisplayLink / NSTimer / GCD的使用

    OC中的三种定时器:CADisplayLink.NSTimer.GCD 我们先来看看CADiskplayLink, 点进头文件里面看看, 用注释来说明下 @interface CADisplayLin ...

  5. 微信小程序中利用时间选择器和js无计算实现定时器(将字符串或秒数转换成倒计时)

    转载注明出处 改成了一个单独的js文件,并修改代码增加了通用性,点击这里查看 今天写小程序,有一个需求就是用户选择时间,然后我这边就要开始倒计时. 因为小程序的限制,所以直接选用时间选择器作为选择定时 ...

  6. [Java定时器]用Spring Task实现一个简单的定时器.

    今天做一个项目的的时候需要用到定时器功能.具体需求是: 每个月一号触发一次某个类中的方法去拉取别人的接口获取上一个月份车险过期的用户.如若转载请附上原文链接:http://www.cnblogs.co ...

  7. Node+fs+定时器(node-schedule)+MySql

    目标:将本人写博客时候的截图保存到桌面的图片 执行保存到指定文件进行整理 并写入数据库 先看最终的目录结构: package.json文件: { "name": "zqz ...

  8. 深入理解定时器系列第一篇——理解setTimeout和setInterval

    × 目录 [1]setTimeout [2]setInterval [3]运行机制[4]作用[5]应用 前面的话 很长时间以来,定时器一直是javascript动画的核心技术.但是,关于定时器,人们通 ...

  9. 前端开发:setTimeout与setInterval 定时器与异步循环数组

    前端开发:setTimeout与setInterval 定时器与异步循环数组 前言: 开通博客园三个月以来,随笔记录了工作中遇到的大大小小的难题,也看过无数篇令人启发的文章,我觉得这样的环境是极好的, ...

  10. 转载---javascript 定时器总结

    转载:http://www.jb51.net/article/40193.htm JS里设定延时: 使用SetInterval和设定延时函数setTimeout 很类似.setTimeout 运用在延 ...

随机推荐

  1. const stirng* 类型的指针cp,当cout<<*cp<<endl:会提示没有与之匹配的“<<”运算符

    #include<iostream> #include<cstring> #include<cstdio> #include<cstdlib> usin ...

  2. 2018.07.08 NOIP模拟 好数(线段树)

    好数 题目背景 SOURCE:NOIP2016-AHSDFZ T3 题目描述 我们定义一个非负整数是"好数",当且仅当它符合以下条件之一: 1. 这个数是 0 或 1 . 2. 所 ...

  3. 优秀前端工程师必备: cookie的增删改查Demo!

    1 cookie可以很好地解决微信浏览器登录状态的保存,具体教程看下面链接: https://www.cnblogs.com/autoXingJY/p/10456767.html 2 参考了w3c等的 ...

  4. spring @Transactional 声明式事务

    项目地址:git@github.com:witaste/transaction-annotation.git 情景一: A external method calls a method of the ...

  5. Robotframework 之常用断言关键字简介

    任何自动化测试框架或实例中断言是必不可少的,Robotframework同样如此,那下面就介绍下其常用断言关键字. 1.Should Be Empty   判断是否为空,如果不为空,执行失败,示例: ...

  6. EntityFramework 基本模式和Code-First的简单使用

    1.Database-First  Database First就是首先建立好数据库,或者存在现成的数据库也可以.然后在vs中添加ADO.Net实体数据模型,找到需要的数据库和表.它是以数据库设计为基 ...

  7. cordova3.X-4.0添加自定义插件方法

    cordova3.X之后,插件不能自己手动添加了,手动添加后,只要cordova build,数据立即被抹去. 因此,3.X后要添加插件,需要用 cordova plungin add "你 ...

  8. java Map集合学习

    学习语法还是从例子着手: FileDao fileDao=new FileBeanDaoImpl(); FileBean fileBean=new FileBean(); listBean=fileD ...

  9. [leetcode] 21. Implement strStr()

    这个题目是典型的KMP算法,当然也可以试试BM,当然有关KMP和BM的介绍阮一峰曾经写过比较好的科普,然后july也有讲解,不过那个太长了. 先放题目吧: Implement strStr(). Re ...

  10. Spring Boot 2 实践记录之 封装依赖及尽可能不创建静态方法以避免在 Service 和 Controller 的单元测试中使用 Powermock

    在前面的文章中(Spring Boot 2 实践记录之 Powermock 和 SpringBootTest)提到了使用 Powermock 结合 SpringBootTest.WebMvcTest ...