From 072ad2c3319fc36563caf6a5296e8e94ba777940 Mon Sep 17 00:00:00 2001 From: mostafaznv Date: Thu, 22 Jun 2023 01:07:48 +0330 Subject: [PATCH] Configurable onQueue and onConnection --- README.md | 47 ++++++++++++------------ config/config.php | 19 +++------- src/Cache.php | 5 ++- src/CacheEntity.php | 40 +++++++++++++++++++-- src/Jobs/RefreshCache.php | 4 +-- src/Jobs/UpdateLaraCacheModelsList.php | 4 ++- src/Traits/InteractsWithCache.php | 5 ++- tests/Feature/CacheEntityTest.php | 50 +++++++++++++++++++++++++- tests/Feature/QueueCacheTest.php | 36 ++++++++++--------- 9 files changed, 149 insertions(+), 61 deletions(-) diff --git a/README.md b/README.md index 73954eb..882704f 100644 --- a/README.md +++ b/README.md @@ -132,20 +132,20 @@ Therefore, if you decide to use my packages, please kindly consider making a don ## CacheEntity Methods -| method | Arguments | description | -|----------------------|-----------------------------------------|-------------------------------------------------------------------------------| -| setDriver | driver (type: `string`) | Specifies custom driver for cache entity | -| isQueueable | status (type: `bool`, default: 'true') | Specifies if cache operation should perform in the background or not | -| refreshAfterCreate | status (type: `bool`, default: `true`) | Specifies if the cache should refresh after create a record | -| refreshAfterUpdate | status (type: `bool`, default: `true`) | Specifies if the cache should refresh after update a record | -| refreshAfterDelete | status (type: `bool`, default: `true`) | Specifies if the cache should refresh after delete a record | -| refreshAfterRestore | status (type: `bool`, default: `true`) | Specifies if the cache should refresh after restore a record | -| forever | | Specifies that the cache should be valid forever | -| validForRestOfDay | | Specify that cache entity should be valid till end of day | -| validForRestOfWeek | | Specify that cache entity should be valid till end of week | -| ttl | seconds (type: `int`) | Specifies cache time to live in second | -| setDefault | defaultValue (type: `mixed`) | Specifies default value for the case that cache entity doesn't have any value | -| cache | Closure | **Main** part of each cache entity. defines cache content | +| method | Arguments | description | +|----------------------|-------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| setDriver | driver (type: `string`) | Specifies custom driver for cache entity | +| isQueueable | status (type: `bool`, default: 'true')
onConnection (type: `string`, default: '')
onQueue (type: `string`, default: '') | This option specifies whether the cache operation should be performed in the background or not.
**Note**: By using the `onConnection` and `onQueue` arguments, you have the ability to specify custom connection and queue names for each cache entity. | +| refreshAfterCreate | status (type: `bool`, default: `true`) | Specifies if the cache should refresh after create a record | +| refreshAfterUpdate | status (type: `bool`, default: `true`) | Specifies if the cache should refresh after update a record | +| refreshAfterDelete | status (type: `bool`, default: `true`) | Specifies if the cache should refresh after delete a record | +| refreshAfterRestore | status (type: `bool`, default: `true`) | Specifies if the cache should refresh after restore a record | +| forever | | Specifies that the cache should be valid forever | +| validForRestOfDay | | Specify that cache entity should be valid till end of day | +| validForRestOfWeek | | Specify that cache entity should be valid till end of week | +| ttl | seconds (type: `int`) | Specifies cache time to live in second | +| setDefault | defaultValue (type: `mixed`) | Specifies default value for the case that cache entity doesn't have any value | +| cache | Closure | **Main** part of each cache entity. defines cache content | ## Disable/Enable Cache @@ -391,14 +391,16 @@ To unlock the cache management capabilities provided by Nova LaraCache, please r ## Config Properties -| method | Type | description | -|-------------------|------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------| -| driver | string (default: `null`) | The default mechanism for handling cache storage.
If you keep this option `null`, LaraCache will use the default cache storage from `config/cache.php` | -| laracache-list | string (default: `laracache.list`) | LaraCache uses a separate list to store name of all entities. using these keys, we can perform some actions to all entities (such as update or delete them) | -| first-day-of-week | integer (default: `0`) | In some regions, saturday is first day of the week and in another regions it may be different. you can change the first day of a week by changing this property | -| last-day-of-week | integer (default: `6`) | In some regions, friday is last day of the week and in another regions it may be different. you can change the last day of a week by changing this property | -| queue | bool (default: `false`) | Sometimes caching process is very heavy, so you have to queue the process and do it in background. | -| groups | array (default: `[]`) | You can group some entities and perform some operations on them | +| method | Type | description | +|-------------------|------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| driver | string (default: `null`) | The default mechanism for handling cache storage.
If you keep this option `null`, LaraCache will use the default cache storage from `config/cache.php` | +| laracache-list | string (default: `laracache.list`) | LaraCache uses a separate list to store name of all entities. using these keys, we can perform some actions to all entities (such as update or delete them) | +| first-day-of-week | integer (default: `0`) | In some regions, saturday is first day of the week and in another regions it may be different. you can change the first day of a week by changing this property | +| last-day-of-week | integer (default: `6`) | In some regions, friday is last day of the week and in another regions it may be different. you can change the last day of a week by changing this property | +| queue.status | bool (default: `false`) | Sometimes caching process is very heavy, so you have to queue the process and do it in background. | +| queue.name | string (default: `default`) | You have the option to set custom name for the queue process. This name will be used when invoking the `onQueue` method while dispatching the queue job. | +| queue.connection | string (default: `null`) | You have the option to set custom connection for the queue process. This connection will be used when invoking the `onConnection` method while dispatching the queue job. | +| groups | array (default: `[]`) | You can group some entities and perform some operations on them | ## Complete Example @@ -437,6 +439,7 @@ class Article extends Model }), CacheEntity::make('list.week') + ->isQueueable(true, 'redis', 'low') ->validForRestOfWeek() ->cache(function() { return Article::query()->latest()->get(); diff --git a/config/config.php b/config/config.php index 78e13a4..a683fe4 100644 --- a/config/config.php +++ b/config/config.php @@ -27,19 +27,6 @@ 'laracache-list' => 'laracache.list', - - /* - |-------------------------------------------------------------------------- - | Cache Name - |-------------------------------------------------------------------------- - | - | The default queue for heavy jobs - | - */ - - 'queue-name' => 'default', - - /* |-------------------------------------------------------------------------- | First Day of Week @@ -73,7 +60,11 @@ | */ - 'queue' => false, + 'queue' => [ + 'status' => false, + 'name' => 'default', + 'connection' => null + ], /* |-------------------------------------------------------------------------- diff --git a/src/Cache.php b/src/Cache.php index 43708e2..f50f8f6 100644 --- a/src/Cache.php +++ b/src/Cache.php @@ -61,7 +61,10 @@ public function refresh(CacheEvent $event): void foreach ($this->model::cacheEntities() as $entity) { if ($entity->isQueueable) { $this->initCache($entity, $entity->getTtl()); - RefreshCache::dispatch($this->model, $entity->name, $event); + + RefreshCache::dispatch($this->model, $entity->name, $event) + ->onConnection($entity->queueConnection) + ->onQueue($entity->queueName); } else { $this->updateCacheEntity($entity->name, $event, $entity); diff --git a/src/CacheEntity.php b/src/CacheEntity.php index 4b6a2cf..0b5fe7c 100644 --- a/src/CacheEntity.php +++ b/src/CacheEntity.php @@ -34,6 +34,20 @@ class CacheEntity */ public bool $isQueueable; + /** + * Queue name + * + * @var string + */ + public string $queueName; + + /** + * Queue connection + * + * @var string + */ + public string $queueConnection; + /** * Indicate if cache should exist till end of day * @@ -103,7 +117,19 @@ public function __construct(string $name) { $this->name = $name; $this->driver = config('laracache.driver') ?? config('cache.default'); - $this->isQueueable = config('laracache.queue') ?? false; + + $queue = config('laracache.queue'); + + if (is_array($queue)) { + $this->isQueueable = $queue['status'] ?? false; + $this->queueName = $queue['name'] ?? 'default'; + $this->queueConnection = $queue['connection'] ?? config('queue.default'); + } + else { + $this->isQueueable = (bool)$queue; + $this->queueName = 'default'; + $this->queueConnection = config('queue.default'); + } } /** @@ -134,12 +160,22 @@ public function setDriver(string $driver): CacheEntity * Specify if cache operation should perform in background or not * * @param bool $status + * @param string $onConnection + * @param string $onQueue * @return $this */ - public function isQueueable(bool $status = true): CacheEntity + public function isQueueable(bool $status = true, string $onConnection = '', string $onQueue = ''): CacheEntity { $this->isQueueable = $status; + if ($onConnection) { + $this->queueConnection = $onConnection; + } + + if ($onQueue) { + $this->queueName = $onQueue; + } + return $this; } diff --git a/src/Jobs/RefreshCache.php b/src/Jobs/RefreshCache.php index 36da50a..f2b3fed 100644 --- a/src/Jobs/RefreshCache.php +++ b/src/Jobs/RefreshCache.php @@ -17,9 +17,7 @@ public function __construct( private string $model, private string $name, private CacheEvent $event - ) { - $this->queue = config('laracache.queue-name'); - } + ) {} public function handle(): void { diff --git a/src/Jobs/UpdateLaraCacheModelsList.php b/src/Jobs/UpdateLaraCacheModelsList.php index 8708bf9..1d382df 100644 --- a/src/Jobs/UpdateLaraCacheModelsList.php +++ b/src/Jobs/UpdateLaraCacheModelsList.php @@ -22,7 +22,9 @@ public function __construct(private string $model) { $this->driver = config('laracache.driver') ?: config('cache.default'); $this->key = self::LARACACHE_MODELS_LIST; - $this->queue = config('laracache.queue-name'); + + $this->connection = config('laracache.queue.connection', 'default'); + $this->queue = config('laracache.queue.name', 'default'); } diff --git a/src/Traits/InteractsWithCache.php b/src/Traits/InteractsWithCache.php index bc9084a..5ef3fa6 100644 --- a/src/Traits/InteractsWithCache.php +++ b/src/Traits/InteractsWithCache.php @@ -165,7 +165,10 @@ private function retrieve(string $name): CacheData if ($cache->status->equals(CacheStatus::NOT_CREATED())) { if ($entity->isQueueable) { $this->initCache($entity, $entity->getTtl()); - RefreshCache::dispatch($this->model, $entity->name, CacheEvent::RETRIEVED()); + + RefreshCache::dispatch($this->model, $entity->name, CacheEvent::RETRIEVED()) + ->onConnection($entity->queueConnection) + ->onQueue($entity->queueName); return CacheData::fromCache($entity, $this->prefix, $entity->ttl); } diff --git a/tests/Feature/CacheEntityTest.php b/tests/Feature/CacheEntityTest.php index 29dab1a..ffb4ab0 100644 --- a/tests/Feature/CacheEntityTest.php +++ b/tests/Feature/CacheEntityTest.php @@ -28,7 +28,7 @@ expect($entity->driver)->toBe('fake-driver'); }); -it('will set is queueable by default', function() { +it('will set is-queueable by default if laracache.queue is boolean', function() { expect($this->entity->isQueueable)->toBeFalse(); config()->set('laracache.queue', true); @@ -38,6 +38,16 @@ expect($entity->isQueueable)->toBeTrue(); }); +it('will set is-queueable by default', function() { + expect($this->entity->isQueueable)->toBeFalse(); + + config()->set('laracache.queue.status', true); + + $entity = CacheEntity::make('test-name'); + + expect($entity->isQueueable)->toBeTrue(); +}); + it('will set custom queue status', function() { expect($this->entity->isQueueable)->toBeFalse(); @@ -48,6 +58,44 @@ expect($this->entity->isQueueable)->toBeFalse(); }); +it('will set queue name and connection by default', function() { + expect($this->entity->queueName)->toBe('default') + ->and($this->entity->queueConnection)->toBe('database'); +}); + +it('will set queue name and connection by default with deprecated config file', function() { + config()->set('laracache.queue', true); + + $entity = CacheEntity::make('test-name'); + + expect($entity->queueName)->toBe('default') + ->and($entity->queueConnection)->toBe('database'); +}); + +it('will set custom queue name and connection using config file', function() { + expect($this->entity->queueName)->toBe('default') + ->and($this->entity->queueConnection)->toBe('database'); + + config()->set('laracache.queue.name', 'test-queue'); + config()->set('laracache.queue.connection', 'test-connection'); + + $entity = CacheEntity::make('test-name'); + + expect($entity->queueName)->toBe('test-queue') + ->and($entity->queueConnection)->toBe('test-connection'); +}); + +it('will set custom queue name and connection using entity method', function() { + expect($this->entity->queueName)->toBe('default') + ->and($this->entity->queueConnection)->toBe('database'); + + $entity = CacheEntity::make('test-name') + ->isQueueable(true, 'test-connection', 'test-queue'); + + expect($entity->queueName)->toBe('test-queue') + ->and($entity->queueConnection)->toBe('test-connection'); +}); + it('will set specific driver for entity', function() { expect($this->entity->driver)->toBe('array'); diff --git a/tests/Feature/QueueCacheTest.php b/tests/Feature/QueueCacheTest.php index 809aad0..6e0a190 100644 --- a/tests/Feature/QueueCacheTest.php +++ b/tests/Feature/QueueCacheTest.php @@ -10,7 +10,7 @@ use Illuminate\Support\Str; use Illuminate\Support\Facades\DB; -beforeEach(function () { +beforeEach(function() { Bus::fake([ UpdateLaraCacheModelsList::class ]); @@ -20,33 +20,35 @@ } }); -it('will initiate cache object with CREATING status', function () { +it('will initiate cache object with CREATING status', function() { $cache = QueueTestModel::cache()->get('latest', true); $isCreating = $cache->status->equals(CacheStatus::CREATING()); expect($isCreating)->toBeTrue(); }); -it('will initiate cache object with entity default value', function () { +it('will initiate cache object with entity default value', function() { $cache = QueueTestModel::cache()->get('latest', true); expect($cache->value)->toBe(-1); }); -it('will initiate cache object with properly expiration ttl', function () { +it('will initiate cache object with properly expiration ttl', function() { $cache = QueueTestModel::cache()->get('latest', true); expect(is_null($cache->expiration))->toBeFalse(); }); -it('will dispatch refresh-cache [without-model]', function () { +it('will dispatch refresh-cache [without-model]', function() { Queue::fake(); createQueueModel(); - expect(Queue::assertPushedOn(config('laracache.queue-name'), RefreshCache::class)); + $onQueue = config('laracache.queue.name'); + + Queue::assertPushedOn($onQueue, RefreshCache::class); }); -it('will create cache after processing queue', function () { +it('will create cache after processing queue', function() { $before = now(); $model = createQueueModel(); @@ -62,12 +64,12 @@ ->and($isCreated)->toBeTrue(); }); -it('will return default value and dispatch cache creation job on retrieving entity [without-model]', function () { +it('will return default value and dispatch cache creation job on retrieving entity [without-model]', function() { Queue::fake(); DB::table('test_models') ->insert([ - 'name' => 'queue-test-name', - 'content' => 'content', + 'name' => 'queue-test-name', + 'content' => 'content', 'created_at' => now() ]); @@ -77,17 +79,19 @@ expect($isCreating)->toBeTrue() ->and($cache->value)->toBe(-1); - expect(Queue::assertPushedOn(config('laracache.queue-name'), RefreshCache::class)); + $onQueue = config('laracache.queue.name'); + + Queue::assertPushedOn($onQueue, RefreshCache::class); }); -it('will create cache in background on retrieving entity [without-model]', function () { +it('will create cache in background on retrieving entity [without-model]', function() { $name = 'queue-test-name'; $before = now(); DB::table('test_models') ->insert([ - 'name' => $name, - 'content' => 'content', + 'name' => $name, + 'content' => 'content', 'created_at' => now() ]); @@ -109,7 +113,7 @@ ->and($isCreated)->toBeTrue(); }); -it('will change cache status to creating on model update [without-model]', function () { +it('will change cache status to creating on model update [without-model]', function() { $model = createQueueModel(); $cache = QueueTestModel::cache()->get('latest', true); @@ -141,7 +145,7 @@ ->and($cache->value->name)->toBe('new name'); }); -it('will return old cache until queue process of updating model is done [without-model]', function () { +it('will return old cache until queue process of updating model is done [without-model]', function() { $model = createQueueModel('old-name'); $cache = QueueTestModel::cache()->get('latest');