laravel-mongodb
laravel-mongodb copied to clipboard
Can't store cache lock
- Laravel-mongodb Version: #.#.#
- PHP Version: #.#.#
- Database Driver & Version:
Description:
I have issue when store data to cache lock with MongoDB driver. error also occurs when dispatch a job implements ShouldBeUnique.
Method acquire Illuminate\Cache\DatabaseLock catch QueryException to update record cache lock table. But with mongodb driver connection throw MongoDB\Driver\Exception\BulkWriteException so can not excute snippet code in catch block
Illuminate\Cache\DatabaseLock
public function acquire()
{
$acquired = false;
try {
$this->connection->table($this->table)->insert([
'key' => $this->name,
'owner' => $this->owner,
'expiration' => $this->expiresAt(),
]);
$acquired = true;
} catch (QueryException $e) {
$updated = $this->connection->table($this->table)
->where('key', $this->name)
->where(function ($query) {
return $query->where('owner', $this->owner)->orWhere('expiration', '<=', time());
})->update([
'owner' => $this->owner,
'expiration' => $this->expiresAt(),
]);
$acquired = $updated >= 1;
}
if (random_int(1, $this->lottery[1]) <= $this->lottery[0]) {
$this->connection->table($this->table)->where('expiration', '<=', time())->delete();
}
return $acquired;
}
Steps to reproduce
$lock = Cache::lock('foo', 10); $lock->block(5);
Job:
class ExampleJob implements ShouldQueue, ShouldBeUnique {
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, UsesBackoffStrategy;
public RequestQueue $request;
public $tries = 2;
/**
* The number of seconds the job can run before timing out.
*
* @var int
*/
public $timeout = 600;
/**
* Indicate if the job should be marked as failed on timeout.
*
* @var bool
*/
public $failOnTimeout = true;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct() {
//
}
/**
* Execute the job.
*
* @return void
*/
public function handle() {
}
dispatch job:
ExampleJob ::dispatch();
Logs:
Exception message like:local.ERROR: E11000 duplicate key error collection: mes.cache_locks index: key_1 dup key: { key: "_cachefoo" } {"userId":"admin","exception":"[object] (MongoDB\\Driver\\Exception\\BulkWriteException(code: 11000): E11000 duplicate key error collection: mes.cache_locks index: key_1 dup key: { key: \"_cachefoo\" } at /var/www/vendor/mongodb/mongodb/src/Operation/InsertMany.php:157)
Could you suggest any ways solve this issue ?
Thank you for reporting this! It looks like one way would be to only throw a QueryException
from the MongoDB connection. However, this is not really desirable, as QueryException
extends PDOException
, which definitely isn't the right inheritance chain. Instead, we would either have to provide our own DatabaseStore
for people to use with MongoDB, or teach the DatabaseLock
class in Laravel itself that there may be other exceptions that needed to be caught (e.g. by providing a marker interface instead of a class to extend).
We'll take a look internally and discuss this further. Could you also please share your cache configuration so we have an idea how you configured the cache and can reproduce it in our own tests? Thank you!
Thank you for reporting this! It looks like one way would be to only throw a
QueryException
from the MongoDB connection. However, this is not really desirable, asQueryException
extendsPDOException
, which definitely isn't the right inheritance chain. Instead, we would either have to provide our ownDatabaseStore
for people to use with MongoDB, or teach theDatabaseLock
class in Laravel itself that there may be other exceptions that needed to be caught (e.g. by providing a marker interface instead of a class to extend).We'll take a look internally and discuss this further. Could you also please share your cache configuration so we have an idea how you configured the cache and can reproduce it in our own tests? Thank you!
Yes sure this is my cache config
<?php
use Illuminate\Support\Str;
return [
/*
|--------------------------------------------------------------------------
| Default Cache Store
|--------------------------------------------------------------------------
|
| This option controls the default cache connection that gets used while
| using this caching library. This connection is used when another is
| not explicitly specified when executing a given caching function.
|
| Supported: "apc", "array", "database", "file",
| "memcached", "redis", "dynamodb"
|
*/
'default' => env('CACHE_DRIVER', 'file'),
/*
|--------------------------------------------------------------------------
| Cache Stores
|--------------------------------------------------------------------------
|
| Here you may define all of the cache "stores" for your application as
| well as their drivers. You may even define multiple stores for the
| same cache driver to group types of items stored in your caches.
|
*/
'stores' => [
'array' => [
'driver' => 'array',
'serialize' => false,
],
'database' => [
'driver' => 'database',
'table' => 'cache',
'connection' => null,
],
'file' => [
'driver' => 'file',
'path' => storage_path('framework/cache/data'),
],
],
'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache'),
];
in .env set CACHE_DRIVER=database
Hope we can find the way to solve it, @alcaeus . Thanks!
Ticked by PHPORM-99
The DatabaseLock
can't be used. We need to create a dedicated MongoDBStore
(cache) and MongoDBLock
(lock), like there is for DynamoDB and Redis in the Laravel Framework.
Are you interested in working on this topic?
The
DatabaseLock
can't be used. We need to create a dedicatedMongoDBStore
(cache) andMongoDBLock
(lock), like there is for DynamoDB and Redis in the Laravel Framework.Are you interested in working on this topic?
Yes thanks @GromNaN , I think it is the best solution. Could you detail about this topic?
How I think it should be implemented (but I never worked with Laravel lock and cache store before):
Cache
- Create
MongoDB\Cache\
in this project, looking atIlluminate\Cache\RedisStore
for the structure. - Implement the cache logic using
Cache\Adapter\MongoDB\MongoDBCachePool
as an example: create a collection with anexpireAfterSeconds
index. - Add tests and documentation
Lock
- Create
MongoDB\Cache\MongoDBLock
in this project, looking atIlluminate\Cache\RedisLock
for the structure. - Implement the cache logic using
Symfony\Component\Lock\MongoDbStore
as an example: create a collection with anexpireAfterSeconds
index. - Add tests and documentation