resgen/lumen-proc

v1.0.22 2022-04-25 16:57 UTC

README

运行 artisan 命令作为守护进程的控制过程。尊重所有发送的 sigterm 命令。包括 TTL 驱动和 RunOnce 驱动。这应该也适用于 Laravel,但只经过 lumen 测试。

为什么?

当将 artisan 命令作为后台守护进程运行时,ProcessControl 将确保尊重 SIGTERMs。当以 docker 入口点运行 artisan 命令时,这尤为重要。它会尊重 docker 的 kill 信号,并给你机会在退出前完成工作。

安装

使用 composer

composer require resgen/lumen-proc:1.0.*

确保为你的 php 安装启用 pcntl_async_signals。例如,使用 docker alpine RUN

RUN docker-php-ext-install pcntl 

配置

将 Laravel 服务提供程序 Resgen\Common\Proc\ProcessControlProvider 添加到您的应用程序中。

然后添加以下 ENV 变量,使用选定的驱动程序

LUMEN_PROC_DRIVER=runonce

默认情况下,TTL 驱动程序每 ~5 秒记录一个 INFO 心跳。您也可以通过以下方式禁用心跳日志:

LUMEN_PROC_HEARTBEAT=disabled

您可以选择在处理信号时异步抛出 SignalException,这将从您的常规代码执行的地方发生,并给您机会优雅地清理事物,同时仍然立即响应信号(或根据需要忽略它们)。

LUMEN_PROC_THROW_SIGNAL_EXCEPTION=enabled

可用驱动程序

TtlProcessDriver

环境变量名称:ttl

运行 N 秒数。默认为 300 秒运行时间。每 ~6 秒记录一个心跳消息。您可以通过设置 LUMEN_PROC_TTL=1000s 来调整运行时间。如果收到 SIGTERM 信号,将退出。旨在与运行监督程序(如 runit、supervisord)或 Docker 编排环境(如 Kubernetes)一起使用。

TtlInstantKillProcessDriver

环境变量名称:ttl_hardexit

与 TtlProcessDriver 相同,但在收到信号时立即抛出异常。

KeepAliveProcessDriver

环境变量名称:keepalive

在发送 SIGTERM 信号之前一直运行。不建议在生产环境中使用。进程应该循环。

RunOnceProcessDriver

环境变量名称:runonce

当调用 check() 时立即退出。

示例用法

class ExampleCommand extends LoopingCommand
{
    /** {@inheritDoc} */
    protected $name = 'resgen';

    /** {@inheritDoc} */
    protected $signature = 'resgen:example';

    /** {@inheritDoc} */
    protected function init()
    {
        // Called prior to the first loop
        // returning `false` will cause the command to stop & exit
    }

    /** {@inheritDoc} */
    protected function loop()
    {
        // Called repeatedly until an exit signal is received or thrown

        return 1;   // Return the number of seconds to sleep/idle until loop() should be called again
    }

    /** {@inheritDoc} */
    protected function exiting()
    {
        // Called just prior to command handler returns for cleanup
    }
}

定时任务调用

LoopingCommand 自动使函数定期发生内部定时任务调用。这个检查发生在每次 loop() 返回控制或命令正在睡眠时。

示例用法

class ExampleCommand extends LoopingCommand
{
    /* ...snip... */
    protected function init()
    {
        $this->cron()
            ->dirCheck('/tmp')
            ->every(5);
            
        $this->cron()
            ->report()
            ->every(60);
    }
    
    /** Check that $dir exists, if not, create it. */
    protected function dirCheck($dir) 
    {
        if(!is_dir($dir)) {
            mkdir($dir, 0777, true);
        }
    }
    
    /** Report on the current state every 60 seconds */
    protected function report()
    {
        Log::info('Sample report every 60 seconds.');
    }
    
}