pathardepavan's avatar

Lumen Queue dispatch error with pgsql driver only

In Laravel Queue dispatch is working fine with pgsql, but in Lumen Queue dispatch though an error with pgsql. But Lumen queue same code works well with mysql.

DB_CONNECTION=pgsql ---- works well with mysql (no error with mysql driver)

QUEUE_DRIVER=database Lumen(5.3) Queue DB error :

SQLSTATE[23502]: Not null violation: 7 ERROR: null value in column "reserved" violates not-null constraint DETAIL: Failing row contains (6, default, {"job":"Illuminate\Queue\CallQueuedHandler@call","data":{"comm..., 0, null, null, 1475202214, 1475202214).)

Jobs

public function up()
{
    //
   Schema::create('jobs', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('queue');
$table->longText('payload');
$table->tinyInteger('attempts')->unsigned();
$table->tinyInteger('reserved')->unsigned();
$table->unsignedInteger('reserved_at')->nullable();
$table->unsignedInteger('available_at');
$table->unsignedInteger('created_at');
$table->index(['queue', 'reserved', 'reserved_at']);

});

 Schema::create('failed_jobs',function(Blueprint $table){
   $table->bigIncrements('id');
   $table->string('connection');
   $table->string('queue');
   $table->string('payload');
   $table->string('exception');
   $table->timestamp('failed_at');

});

0 likes
2 replies
ElpsySec's avatar

TL:DR: Mark the 'reserved' column as nullable in your migration. Read the full post for potential risks.

The dispatch method (found in foundation helpers.php) resolves the dispatcher and calls dispatch on it. Depending on the job, it runs a method on the queue driver. Most likely, it is running the 'push' method.

If you look at the push method on the DatabaseQueue class, there are three main methods:

public function push($job, $data = '', $queue = null)
{
        return $this->pushToDatabase($queue, $this->createPayload($job, $data));
}

protected function pushToDatabase($queue, $payload, $delay = 0, $attempts = 0)
{
        return $this->database->table($this->table)->insertGetId($this->buildDatabaseRecord(
            $this->getQueue($queue), $payload, $this->availableAt($delay), $attempts
        ));
}

protected function buildDatabaseRecord($queue, $payload, $availableAt, $attempts = 0)
{
        return [
            'queue' => $queue,
            'payload' => $payload,
            'attempts' => $attempts,
            'reserved_at' => null,
            'available_at' => $availableAt,
            'created_at' => $this->currentTime(),
        ];
}

You'll notice 'reserved' is not present in the the buildDatabaseRecord. So it is very possible that reserved can be null.

I'm not quite sure how reserved works. Looking at some other methods, it may be a way to tell the dispatcher to retry the jobs. However, from what I can tell by looking at other methods, when the queue queries reserved jobs from the db, it typically looks at 'reserved_at' column, not 'reserved'. Even when it "markJobAsReserved' (toggles the reserved "status" of the jobs), it modifies reserved_at and not reserved.

Ultimately, the reserved flag is used in other drivers such as the RedisQueue, but it seems the flag itself is not entirely necessary for the DatabaseQueue. I could be wrong. If I'm right, it'd be an easy PR to fix (change the migration stub, and change the docs).

Please or to participate in this conversation.