代码方式实现PHP服务定时拉取
定时拉取是一种很常见的操作,比如需要定时从配置中心拉取一下配置,或者同步一下状态等。这对于编译型语言来说十分简单,只需要开一个独立的线程,拉一下、sleep一会就好了。但是对于无状态的PHP服务,比如wordpress,或者一些API层的服务,由于他们没有常驻进程,想跑定时任务就比较麻烦了(swoole的除外,我们只讨论fpm的)。
其实搞定时任务的方式有挺多,比如起一个cron脚本,定时拉(配置或者什么)写到一个文件里,php每次读这个文件结果。这么搞是最简单的,但是当你维护的是一个几百台docker的集群的时候,这么搞运维可能会骂死你;如果是用git的webhook部署的话,如果改了脚本逻辑得手动上去改一下……我就是遇到了一个类似的复杂情况,不得已用了这种方法。留着以后当个面试题也是极好的。
这种方式需要几个小部分来配合:
- xxx.lock 文件锁,里面存有一个timestamp,表示更新时间。
- xxx.conf 拉取到的配置(或其他什么东西,存在里面)。
- lock.sh 脚本,用户检查锁
- sync.sh 脚本,用于执行拉取操作
- xxx.php php文件
他们之间相互的关系大概是这样:
xxx.php及钩子
xxx.php主要任务有两个:
- 从lockfile读一下时间,看需不需要启动任务
- 如果需要,启动lock脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
class Sync { private $lockFile; private $confFile; private static $instance = null; public static function getInstance() { if (self::$instance == null) { self::$instance = new self(); } return self::$instance; } private function __construct() { $this->lockFile = dirname(__FILE__) . '/' . 'xxx.lock'; $this->confFile = dirname(__FILE__) . '/' . 'xxx.conf'; } public function updateConfHook() { try { $fpTime = fopen($this->lockFile, 'r'); if ($fpTime !== false) { if (flock($fpTime, LOCK_EX | LOCK_NB)) { $size = filesize($this->lockFile); if ($size > 0) { $content |