티스토리 뷰

목표

Laravel 기본 DB 연결은 mysql 로,
Queue driver 는 Redis 로,
Queue 작업 실패시 기록하는 failed table 은 sqlite 로 설정


환경설정

/app/config/database.php
'default' => 'mysql’,

'connections' => array(

        'sqlite' => array(
            'driver'   => 'sqlite',
            'database' => __DIR__.'/../database/production.sqlite',
            'prefix'   => '',
        ),

        'mysql' => array(
            'driver'    => 'mysql’,

……

'redis' => array(
        'cluster' => false,
        'default' => array(
            'host'     => ‘localhost',
            'password' => 'dialredis',
            'port'     => 6379,
            'database' => 0,
        ),
    ),

/app/config/queue.php
'default' => 'redis’,

'failed' => array(
    'database' => 'sqlite', 'table' => 'failed_jobs',
),

위의 failed_jobs 테이블 생성을 위해
아래의 쉘 명령 실행이 필요
$ php artisan queue:failed-table

위 명령으로 생성된 파일 수정. 연결을 sqlite 로 하도록.
$ vi /app/database/migrations/xxxx_xx_xx_xxxxxx_create_failed_jobs.php

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateFailedJobsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::connection('sqlite')->create('failed_jobs', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->text('connection')->default('');
            $table->text('queue')->default('');
            $table->longText('payload')->default('');
            $table->longText('exception')->default('');
            $table->timestamp('failed_at')->useCurrent();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::connection('sqlite')->dropIfExists('failed_jobs');
    }
}

이제 DB migration 명령 실행
$ php artisan migrate

개인적으로 운영서버의 환경에서 기본 mysql 을 건드리지 않아야 하는 환경이었기에
production.sqlite DB 파일만 만들어서 업로드하여 사용하는 꼼수
를 썼고 다음과 같이 수행:

로컬에서 laravel new 쉘 명령으로 새 프로젝트 만들고
위의 과정들 수행하여
/app/database/production.sqlite
파일을 생성해 내고 운영서버의 동일 경로에 업로드.


테스팅 삽질

/app/routes.php
Route::get('queuejob/{id}', 'QueueController@queueJob')->where('id', '[0-9]+');

/app/controller/QueueController.php
class QueueController extends Controller
{
    public function queueJob($id)
    {
        if (!isset($id) || empty($id)) return [];

        // Push a job to queue
        Queue::push(function ($job) use ($id)
        {
            $jobId = $job->getJobId();

            //if (!$jobId) {
                // fail 테스팅을 위해~
                // $job->fail() 메쏘드 없는 대신 아래와 같이 exception 발생시키면
                // failed_jobs 테이블에 삽입될거라 예상했으나 안됨!
                throw new \Exception("Queue fire scratch => JobID: {$jobId} , ID: {$id}.");
            //}

            // 위의 exception 발생하지 않으면 아래 출력, job 삭제 다 잘된다.
            // 즉, 오류나 예외 발생 없으면 queue 작동 잘 됨.
            echo "JobID: {$jobId} , UID: {$id} successfully processed.";

            // Delete a processed job from the queue
            $job->delete();
        });
    }

Client 에서 fail 테스팅 (job fail 시 failed_jobs 테이블에 실패한 queue 레코드 삽입)
curl -XGET http://localhost/queuejob/111
curl -XGET http://localhost/queuejob/222
curl -XGET http://localhost/queuejob/333
curl -XGET http://localhost/queuejob/444
curl -XGET http://localhost/queuejob/555

Queue 하나 서버에서 처리 쉘 명령 해보니:
$ php artisan queue:work
                                                                            
  [Exception]                                                               
  Queue fire scratch:: JobID: 1YMs5b8FATFaIjT4fM9fWBbLyIURUgVn , UID: 111.                                                                            
queue:work [--queue[="..."]] [--daemon] [--delay[="..."]] [--force] [--memory[="..."]] [--sleep[="..."]] [--tries[="..."]] [connection]
예외는 발생하고 다음의 echo 문은 실행이 안됨을 알 수 있음.

실패한 queue job 이 failed_jobs 테이블에 삽입되었는지 확인 쉘 명령:
$ php artisan queue:failed

No failed jobs!
뭐야? 예외 발생시켜도 failed 에 리스팅이 안되잖아?

구글링 하고 각종 삽질 후 아래의 해결책을 찾음.

Queue 처리 + 실패시 재시도 횟수 지정 (5번 실행, Client 에서 fail 테스팅 111 ~ 555 까지 5개 했으므로)
$ php artisan queue:work --tries=2

다시한번 실패한 queue job 이 failed_jobs 테이블에 삽입되었는지 확인 쉘 명령 수행:
$ php artisan queue:failed

+----+------------+---------+------------------------+-----------+---------------------+
| ID | Connection | Queue   | Class                  | Failed At |                     |
+----+------------+---------+------------------------+-----------+---------------------+
| 5  | redis      | default | IlluminateQueueClosure |           | 2017-08-29 17:49:22 |
| 4  | redis      | default | IlluminateQueueClosure |           | 2017-08-29 17:49:22 |
| 3  | redis      | default | IlluminateQueueClosure |           | 2017-08-29 17:49:21 |
| 2  | redis      | default | IlluminateQueueClosure |           | 2017-08-29 17:49:20 |
| 1  | redis      | default | IlluminateQueueClosure |           | 2017-08-29 17:49:10 |
+----+------------+---------+------------------------+-----------+---------------------+

실패한 ID 5번 queue job 재시도 명령:
$ php artisan queue:retry 5

실패한 ID 5번 queue job 삭제 명령:
$ php artisan queue:forget 5

Failed job deleted successfully!

실패한 queue job 전체 삭제 명령:
$ php artisan queue:flush

All failed jobs deleted successfully!

데몬 모드로 실행 명령은. (테스팅이 성공하였다면..)
$ php artisan queue:work --daemon --tries=3


기타

점검 모드 (php artisan down 명령) 후 queue 데몬 재시작하려면
$ php artisan queue:restart

supervisord 에 등록하여 start. (데몬 명령이 죽으면 자동으로 되살리거나 시스템 시작시 시작하도록 하려면..)
$ sudo yum install -y supervisor
$ sudo vim /etc/supervisor/conf.d/myqueue.conf

[program:myqueue]
command=php artisan queue:work --daemon --tries=3 --sleep=3 --env=your_environment
directory=/path/to/laravel
stdout_logfile=/path/to/laravel/app/storage/logs/myqueue_supervisord.log
redirect_stderr=true
autostart=true
autorestart=true

$ sudo supervisorctl
> reread              # Get available jobs
> add myqueue
> start myqueue


참고


댓글