Docker + Laravel 队列:工作

Posted

技术标签:

【中文标题】Docker + Laravel 队列:工作【英文标题】:Docker + Laravel queue:work 【发布时间】:2018-07-30 18:54:58 【问题描述】:

我正在尝试在容器启动并运行后运行以下命令。

php artisan queue:work -n -q &

“&”之所以存在,是因为 daemon 选项已被弃用,后来从 Laravel 中删除。

但是,这完全破坏了我的容器启动。

CMD ["php", "artisan", "queue:work", "-n", "-q", "&"]

我应该如何以 Docker 的方式做到这一点?

编辑:

使用 docker-compose 我将此行添加到我的 docker-compose.yml 文件中

command: bash -c 'php artisan queue:work -n -q;'

容器已启动但未处理任何请求:S

使用这个:

command: bash -c 'php artisan queue:work -n -q &; echo "runs"; tail -f /dev/null'

容器启动后停止

最终解决方案

所以最后我想也许负责交付应用程序的服务器不应该是运行队列的服务器。

因此,我启动了同一个 docker 映像的另一个实例,其唯一目的是运行 artisan queue:work。

【问题讨论】:

启动同一个 docker 映像的另一个实例,其唯一目的是运行 artisan queue:work - ANSWER 【参考方案1】:

您不能在后台运行队列,否则容器将停止,因为命令已有效完成。删除&,它将保持活动状态。

但是,如果您想在后台运行队列并且仍然能够附加到容器并访问 shell,则可以执行类似 tail -f /dev/null 的最后命令来保持容器运行。

【讨论】:

所以你的建议是保持我的 CMD 不变,并在下面添加一个无限的“tail -f /dev/null”?我试试这个 是的,我不确定您是否可以在 Dockerfile 中运行多个命令,因此您可能需要为其创建脚本。如果您使用 compose,您可以执行以下操作:command: bash -c 'php artisan queue:work -n -q &; tail -f /dev/null' 不工作...不知道为什么,但容器不断停止 已编辑问题 你是否在容器中以分离模式运行?【参考方案2】:

queue:work 命令在前台运行,所以你应该这样运行它,这样容器就不会立即退出。

由于 Laravel 中的应用程序代码对于将容器作为 Web 应用程序、队列或调度程序运行是相同的,因此我构建了一个可以在这些上下文中使用的映像。我使用带有环境变量的 bash 启动脚本来定义容器角色,这就是我为队列工作容器运行的:

#!/bin/bash

# Defaults to an app server
role=$CONTAINER_ROLE:-app

if [ "$role" = "queue" ]; then
    # Run queue
    php artisan queue:work --verbose --tries=3 --timeout=90
elif [ "$role" = "app" ]; then
    # Run the web application
    /usr/bin/caddy --agree=true --conf=/etc/Caddyfile
elif [ "$role" = "scheduler" ]; then
    while [ true ]
    do
      php artisan schedule:run --verbose --no-interaction &
      sleep 60
    done
else
    echo "Could not match the container role...."
    exit 1
fi

还要注意无限循环和睡眠组合,以保持调度程序角色运行并在后台运行 schedule:run 命令,以防调度程序运行重叠(因为无论最后一个是否完成,它们都需要每分钟运行一次) .

【讨论】:

我目前正在使用它,工作正常...只是在寻找优雅关闭 queue:work & schedule:run 的方法...您找到任何解决方案了吗? 我终于找到了队列的优雅关闭。见***.com/a/63851444/1414178 我知道,但这现在有点老了,但看起来你的回答可能会解决我的问题。问是否可以在上下文中将其添加到 docker-compose 文件中会不会太过分了?我对 docker 不是很好......另外,“app”是容器的名称吗?提前谢谢你 CONTAINER_ROLE 是您设置的环境,默认为app (role=$CONTAINER_ROLE:-app)。您可以配置容器运行的角色(Web 服务器、调度程序或队列)。 不需要创建这个脚本。您可以重写 docker 命令并直接调用您想要的。例如"docker run .... your_container php artisan queue:work --verbose --tries=3 --timeout=90"【参考方案3】:

使用主管

apt-get 安装主管

cd /etc/supervisor/conf.d && sudo nano laravel-worker.conf

[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=docker exec php php /path/to/artisan queue:work redis --sleep=3 --tries=5
autostart=true
autorestart=true
user=root
numprocs=8
redirect_stderr=true
stdout_logfile=/var/logs/worker.log

【讨论】:

是的,这也是一个选项,谢谢。最后,我认为只是启动和集成和队列服务器更干净。我会试试主管的想法【参考方案4】:

如果您需要队列正常关闭,您可以按照此操作。

这取自@Paul RedmondLaravel News 上的文章,并扩展了他的 docker-entrypoint 文件以满足我的需要。经过大量测试正常关闭后,我终于能够做到。

docker-compose.yml 文件中的第一件事是为您的队列服务设置 stop_signal: SIGTERM

  queue:
    image: laravel-www
    container_name: laravel-queue
    stop_signal: SIGTERM
    depends_on:
      - app
    volumes:
      - .:/var/www/html
    ...

接下来在entrypoint.sh文件中,主要是使用exec命令运行queue:work。

#!/usr/bin/env bash

set -e

# Run our defined exec if args empty
if [ -z "$1" ]; then
    role=$CONTAINER_ROLE:-app
    env=$APP_ENV:-production

    if [ "$env" != "local" ]; then
        echo "Caching configuration..."
        (cd /var/www/html && php artisan cache:clear && php artisan config:clear && php artisan route:clear && php artisan view:clear)
        (cd /var/www/html && php artisan config:cache && php artisan event:cache && php artisan route:cache && php artisan view:cache)
    fi

    if [ "$role" = "app" ]; then

        echo "Running PHP-FPM..."
        exec php-fpm

    elif [ "$role" = "queue" ]; then

        echo "Running the queue..."
        exec php /var/www/html/artisan queue:work -vv --no-interaction --tries=3 --sleep=5 --timeout=300 --delay=10

    elif [ "$role" = "cron" ]; then

        echo "Running the cron..."
        while [ true ]
        do
          exec php /var/www/html/artisan schedule:run -vv --no-interaction
          sleep 60
        done

    else
        echo "Could not match the container role \"$role\""
        exit 1
    fi

else
    exec "$@"
fi

你已经完成了。下次停止队列服务时,它会优雅地停止,不会等待 10 秒 SIGKILL。我认为这与PID 1 的事情有关。

【讨论】:

当您在寻找适用于 Horizo​​n 的解决方案时偶然发现此问题时,您可能需要查看Horizon source code,它表明您应该使用SIGTERM 而不是SIGTERM 来停止过程优雅。

以上是关于Docker + Laravel 队列:工作的主要内容,如果未能解决你的问题,请参考以下文章

将 Laravel Echo 与 docker 一起使用(CORS 问题)

Laravel 5.1 cron不在OVH工作

代客工作但无法创建新的 Laravel 安装?

Laravel 队列:在主机中永远运行的工作?

使用 Supervisor 运行多个 Laravel 队列工作者

Laravel如何停止/重新启动特定队列的工作人员?