From 0f963b1918c47daced6fd82cc8c871caadcd27ee Mon Sep 17 00:00:00 2001 From: Simon Chawla Date: Tue, 19 Sep 2023 12:18:56 -0300 Subject: [PATCH] Limit shipments per minute and added tests --- .gitignore | 1 + README.md | 54 +++++++- config/data-shipper.php | 4 +- .../create_failed_packages_table.php.stub | 4 +- .../create_failed_shipments_table.php.stub | 3 + src/Commands/RetryFailedShipments.php | 5 +- src/Commands/ShipIt.php | 1 + src/DataShipper.php | 2 +- src/Jobs/ClearPackagesFromShipment.php | 16 ++- src/Jobs/NotifySubscriberOfShipment.php | 40 +++++- src/Jobs/RetryFailedShipment.php | 4 +- src/Models/FailedPackage.php | 4 + src/Models/FailedShipment.php | 2 +- src/ShipmentRepository.php | 9 +- src/Subscribers/ElasticsearchSubscriber.php | 7 +- tests/DataShipperTest.php | 114 ++++++++++++++++- tests/TestCase.php | 121 +++++++++--------- 17 files changed, 303 insertions(+), 88 deletions(-) diff --git a/.gitignore b/.gitignore index 9324a51..c29af35 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ yarn-error.log .idea/ phpstan-baseline.neon phpstan.neon.dist +build/ # Laravel 4 specific bootstrap/compiled.php diff --git a/README.md b/README.md index 3a2b5e5..1b26251 100644 --- a/README.md +++ b/README.md @@ -12,14 +12,14 @@ composer require autoklose/laravel-data-shipper You can publish and run the migrations with: ```bash -php artisan vendor:publish --tag="data_shipper-migrations" +php artisan vendor:publish --tag="data-shipper-migrations" php artisan migrate ``` You can publish the config file with: ```bash -php artisan vendor:publish --tag=":data_shipper-config" +php artisan vendor:publish --tag="data-shipper-config" ``` You can customize how often data shipments happen by changing the following values in the config file: @@ -30,12 +30,20 @@ You can customize how often data shipments happen by changing the following valu ### max_wait_minutes - How many minutes should Data Shipper wait until shipping changes regardless of not yet reaching the max queue size. +### max_shipments_per_minute +- How many times a shipment can be handled per a minute. + +### max_retries +- How many times a failed shipment can be retried before no longer being handled. + ```php return [ 'subscribers' => ['elasticsearch'], 'shipments' => [ 'max_size' => 10, - 'max_wait_minutes' => 5 + 'max_wait_minutes' => 5, + 'max_shipments_per_minute' => 10, + 'max_retries' => 3 ] ]; ``` @@ -47,7 +55,7 @@ protected function schedule(Schedule $schedule) { // ... - $shedule->command('data-shipper:ship-it')->everyMinute(); + $schedule->command('data-shipper:ship-it')->everyMinute(); } ``` @@ -155,6 +163,44 @@ class Record extends Model } ``` +## Available Data Subscribers + +### Elasticsearch +Elasticsearch is available as the default data subscriber. In order to work with this subscriber, each class that is passed through Data Shipper must have an `elasticsearch_index` field that is publically available. + +It can be as simple as a public string property on your class. + +```php +use Illuminate\Database\Eloquent\Model; +use Autoklose\DataShipper\Traits\HasDataSubscribers; + +class Record extends Model +{ + use HasDataSubscribers; + + public string $elasticsearch_index = 'record_index'; +} +``` + +Alternatively if you need to retrieve the index name programmatically we recommend making use of an attribute. Please note that you should not rely on class properties when creating the index attribute as the class will not have any data loaded. + +```php +use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Casts\Attribute; +use Autoklose\DataShipper\Traits\HasDataSubscribers; + +class Record extends Model +{ + use HasDataSubscribers; + + public function elasticsearchIndex(): Attribute + { + return Attribute::make(get: fn() => config('elasticsearch.recordIndex')); + } +} +``` + + ## Changelog Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. diff --git a/config/data-shipper.php b/config/data-shipper.php index 8f31b13..9a76330 100644 --- a/config/data-shipper.php +++ b/config/data-shipper.php @@ -4,6 +4,8 @@ 'subscribers' => ['elasticsearch'], 'shipments' => [ 'max_size' => 10, - 'max_wait_minutes' => 5 + 'max_wait_minutes' => 5, + 'max_shipments_per_minute' => 10, + 'max_retries' => 3 ] ]; diff --git a/database/migrations/create_failed_packages_table.php.stub b/database/migrations/create_failed_packages_table.php.stub index a0fde69..3ffc45a 100644 --- a/database/migrations/create_failed_packages_table.php.stub +++ b/database/migrations/create_failed_packages_table.php.stub @@ -8,13 +8,13 @@ return new class extends Migration { public function up() { - Schema::create('failed_shipments', function (Blueprint $table) { + Schema::create('failed_packages', function (Blueprint $table) { $table->id(); $table->string('model_id'); $table->json('payload'); $table->unsignedBigInteger('failed_shipment_id'); - $table->foreign('failed_shipment')->references('id')->on('failed_shipments'); + $table->foreign('failed_shipment_id')->references('id')->on('failed_shipments')->cascadeOnDelete(); $table->timestamps(); }); diff --git a/database/migrations/create_failed_shipments_table.php.stub b/database/migrations/create_failed_shipments_table.php.stub index d897763..3938310 100644 --- a/database/migrations/create_failed_shipments_table.php.stub +++ b/database/migrations/create_failed_shipments_table.php.stub @@ -12,6 +12,9 @@ return new class extends Migration $table->id(); $table->string('class_name'); $table->string('shipment'); + $table->string('subscriber'); + $table->timestamp('last_retried_at'); + $table->unsignedInteger('retries')->default(0); $table->timestamps(); }); diff --git a/src/Commands/RetryFailedShipments.php b/src/Commands/RetryFailedShipments.php index 579a2a3..d305e77 100644 --- a/src/Commands/RetryFailedShipments.php +++ b/src/Commands/RetryFailedShipments.php @@ -14,10 +14,9 @@ class RetryFailedShipments extends Command public function handle() { - $threshold = now()->subMinutes(15); + $maxRetries = config('data-shipper.shipments.max_retries'); - FailedShipment::where(fn($query) => $query->whereNull('last_retried_at')->orWhere('last_retried_at', '<=', $threshold)) - ->where('retries', '<', 3)->chunk(250, function($failedShipments) { + FailedShipment::where('retries', '<', $maxRetries)->chunk(250, function($failedShipments) { foreach ($failedShipments as $failedShipment) { RetryFailedShipment::dispatch($failedShipment); } diff --git a/src/Commands/ShipIt.php b/src/Commands/ShipIt.php index 1cc1fd4..5ed83c1 100644 --- a/src/Commands/ShipIt.php +++ b/src/Commands/ShipIt.php @@ -7,6 +7,7 @@ use Autoklose\DataShipper\Jobs\NotifySubscriberOfShipment; use Illuminate\Console\Command; use Illuminate\Support\Facades\Bus; +use Illuminate\Support\Facades\Redis; class ShipIt extends Command { diff --git a/src/DataShipper.php b/src/DataShipper.php index 50b92f2..9498e6d 100644 --- a/src/DataShipper.php +++ b/src/DataShipper.php @@ -170,7 +170,7 @@ protected function setup(): void { protected function resolveSubscriber($subscriber): DataSubscriberInterface { if ($subscriber === 'elasticsearch') { - return new ElasticsearchSubscriber($this->app); + return app()->make(ElasticsearchSubscriber::class); } throw new InvalidArgumentException("No resolver exists for $subscriber data source."); diff --git a/src/Jobs/ClearPackagesFromShipment.php b/src/Jobs/ClearPackagesFromShipment.php index d54639a..0218d5f 100644 --- a/src/Jobs/ClearPackagesFromShipment.php +++ b/src/Jobs/ClearPackagesFromShipment.php @@ -9,6 +9,7 @@ use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; +use Illuminate\Support\Facades\Cache; class ClearPackagesFromShipment implements ShouldQueue { @@ -18,16 +19,25 @@ class ClearPackagesFromShipment implements ShouldQueue protected int $length; - public function __construct(string $shipment, int $length) + protected bool $limitHit; + + public function __construct(string $shipment, int $length, bool $limitHit) { $this->shipment = $shipment; $this->length = $length; + $this->limitHit = $limitHit; } public function handle() { - $repository = new ShipmentRepository(app()->make(Factory::class)); + $repository = new ShipmentRepository(app()->make(Factory::class), config('data-shipper.shipments.max_wait_minutes'), config('data-shipper.shipments.max_size')); + + $canShipAgain = $repository->flushPackagesForShipment($this->shipment, $this->length); + + Cache::lock("data-shipper-{$this->shipment}-active-lock")->forceRelease(); - $repository->flushPackagesForShipment($this->shipment, $this->length); + if ($canShipAgain) { + NotifySubscriberOfShipment::dispatch($this->shipment, true); + } } } diff --git a/src/Jobs/NotifySubscriberOfShipment.php b/src/Jobs/NotifySubscriberOfShipment.php index ae02337..55535b5 100644 --- a/src/Jobs/NotifySubscriberOfShipment.php +++ b/src/Jobs/NotifySubscriberOfShipment.php @@ -2,15 +2,16 @@ namespace Autoklose\DataShipper\Jobs; -use Autoklose\DataShipper\Facades\DataShipper; -use Autoklose\DataShipper\ShipmentRepository; +use Carbon\Carbon; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; -use Illuminate\Contracts\Redis\Factory; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; use Illuminate\Support\Facades\Bus; +use Illuminate\Support\Facades\Cache; +use Illuminate\Support\Facades\Redis; +use Autoklose\DataShipper\Facades\DataShipper; class NotifySubscriberOfShipment implements ShouldQueue { @@ -18,13 +19,44 @@ class NotifySubscriberOfShipment implements ShouldQueue { protected string $shipment; + protected int $maxShipmentsPerMinute; + public function __construct(string $shipment) { $this->shipment = $shipment; + $this->maxShipmentsPerMinute = config('data-shipper.shipments.max_shipments_per_minute'); } public function handle() { + $lock = Cache::lock("data-shipper-{$this->shipment}-active-lock", 50); + + if (!$lock->get()) { + return; + } + + $limitHit = false; + $lastShipment = Redis::connection('data-shipper')->zscore("data-shipper-records", $this->shipment); + + if (!$lastShipment || Carbon::createFromTimestamp($lastShipment)->isBefore(now()->startOfMinute())) { + // New throttle setup + $timestamp = now()->timestamp; + Redis::connection('data-shipper')->pipeline(function ($pipe) use($timestamp) { + $pipe->zadd("data-shipper-records", $timestamp, $this->shipment); + $pipe->expire("data-shipper-records", 60); + $pipe->del("data-shipper-{$this->shipment}-per-minute"); + $pipe->incr("data-shipper-{$this->shipment}-per-minute"); + $pipe->expire("data-shipper-{$this->shipment}-per-minute", 60); + }); + } else { + $handledThisMinute = Redis::connection('data-shipper')->incr("data-shipper-{$this->shipment}-per-minute"); + if ($handledThisMinute > $this->maxShipmentsPerMinute) { + return; + } + + $limitHit = $this->maxShipmentsPerMinute === $handledThisMinute; + } + $subscribers = DataShipper::getSubscribers(); $packageIds = DataShipper::getPackagesForShipment($this->shipment, true); @@ -33,7 +65,7 @@ public function handle() $jobs[] = new DispatchShipmentToSubscriber($this->shipment, $packageIds, $subscriberName); } - $jobs[] = new ClearPackagesFromShipment($this->shipment, count($packageIds)); + $jobs[] = new ClearPackagesFromShipment($this->shipment, count($packageIds), $limitHit); Bus::chain($jobs)->dispatch(); } diff --git a/src/Jobs/RetryFailedShipment.php b/src/Jobs/RetryFailedShipment.php index 088b379..7edbf1d 100644 --- a/src/Jobs/RetryFailedShipment.php +++ b/src/Jobs/RetryFailedShipment.php @@ -29,7 +29,7 @@ public function handle() $this->failedShipment->increment('retries'); $this->failedShipment->update(['last_retried_at' => now()]); - if ($this->failedShipment->retries >= 3) { + if ($this->failedShipment->retries >= (int)config('data-shipper.shipments.max_retries')) { return; } @@ -42,5 +42,7 @@ public function handle() $subscriber = $subscribers[$this->failedShipment->subscriber]; $subscriber->ship($preparedPackages); + + $this->failedShipment->delete(); } } diff --git a/src/Models/FailedPackage.php b/src/Models/FailedPackage.php index 069ac43..3dc5645 100644 --- a/src/Models/FailedPackage.php +++ b/src/Models/FailedPackage.php @@ -6,4 +6,8 @@ class FailedPackage extends Model { protected $guarded = []; + + protected $casts = [ + 'payload' => 'array' + ]; } diff --git a/src/Models/FailedShipment.php b/src/Models/FailedShipment.php index 5d8f7c7..6c763b9 100644 --- a/src/Models/FailedShipment.php +++ b/src/Models/FailedShipment.php @@ -13,6 +13,6 @@ class FailedShipment extends Model { public function packages() { - return $this->belongsToMany(FailedPackage::class); + return $this->hasMany(FailedPackage::class); } } diff --git a/src/ShipmentRepository.php b/src/ShipmentRepository.php index b526e24..1fb73c0 100644 --- a/src/ShipmentRepository.php +++ b/src/ShipmentRepository.php @@ -59,7 +59,7 @@ public function getPackagesByUuids(array $ids, string $key, $startingIndex = 0): // Remove these jobs from the queue $count = array_pop($packages) - count($ids); - if ($count >= 1 && $count < $this->maxShipmentLength) { + if ($count > 0 && $count < $this->maxShipmentLength) { $this->connection()->pipeline(function ($pipe) use ($key) { // Reset the timeout for the shipment $this->updateShipmentManifest($pipe, $key); @@ -117,14 +117,14 @@ public function flushPackagesForShipment(string $key, int $length): bool { $lock->block(10); - $packageIds = $this->connection()->zrange($key, 0, $length); + $packageIds = $this->connection()->zrange($key, 0, $length - 1); $results = $this->connection()->pipeline(function ($pipe) use ($key, $length, $packageIds) { foreach ($packageIds as $id) { $pipe->hdel($id); } - $pipe->zrem(...$packageIds); + $pipe->zrem($key, ...$packageIds); $pipe->decrby("{$key}-shipment-length", count($packageIds)); }); @@ -140,7 +140,7 @@ public function flushPackagesForShipment(string $key, int $length): bool { $lock->release(); - return $count === $this->maxShipmentLength; + return $count >= $this->maxShipmentLength; } /** @@ -174,6 +174,7 @@ protected function addPackageToShipment($pipe, string $key, PackageInterface $pa */ public function updateShipmentManifest($pipe, string $key, bool $now = false): void { $timestamp = !$now ? now()->addMinutes($this->minutesUntilShipment)->getPreciseTimestamp(4) : now()->getPreciseTimestamp(4); + $pipe->zrem("shipments", $key); $pipe->zadd("shipments", $timestamp, $key); } diff --git a/src/Subscribers/ElasticsearchSubscriber.php b/src/Subscribers/ElasticsearchSubscriber.php index 978dc1e..2078d66 100644 --- a/src/Subscribers/ElasticsearchSubscriber.php +++ b/src/Subscribers/ElasticsearchSubscriber.php @@ -8,13 +8,10 @@ use Elasticsearch\Common\Exceptions\Conflict409Exception; class ElasticsearchSubscriber implements DataSubscriberInterface { - protected $app; protected $retries; - public function __construct($app) + public function __construct() { - $this->app = $app; - $this->retries = config('data-shipper.subscribers.elasticsearch.retires', 3); } @@ -44,7 +41,7 @@ public function ship($packages) { } /** @var Client $client */ - $client = $this->app->make(Client::class); + $client = app()->make(Client::class); $retries = $this->retries; diff --git a/tests/DataShipperTest.php b/tests/DataShipperTest.php index adc5ea5..40edd2f 100644 --- a/tests/DataShipperTest.php +++ b/tests/DataShipperTest.php @@ -122,7 +122,7 @@ DataShipper::pushMany(\Autoklose\DataShipper\Tests\Models\TestModel::class, $changes, 'id'); $key = \Autoklose\DataShipper\Tests\Models\TestModel::class; - $job = new \Autoklose\DataShipper\Jobs\ClearPackagesFromShipment($key, count($changes)); + $job = new \Autoklose\DataShipper\Jobs\ClearPackagesFromShipment($key, count($changes), false); $job->handle(); $remainingShipment = DataShipper::getPackagesForShipment($key); @@ -132,6 +132,113 @@ expect(\Illuminate\Support\Facades\Redis::connection('data-shipper')->exists("{$key}-shipment-length"))->toBeFalsy(); })->with('bulk-changes'); +it('will automatically requeue job if more shipments are available', function($changes) { + config()->set('data-shipper.shipments.max_size', 5); + + $key = \Autoklose\DataShipper\Tests\Models\TestModel::class; + DataShipper::pushMany($key, $changes, 'id'); + + $command = new \Autoklose\DataShipper\Commands\ShipIt(); + $command->handle(); + + $remainingShipment = DataShipper::getPackagesForShipment($key); + expect($remainingShipment->all())->toBeEmpty(); +})->with('bulk-changes'); + +it('will not requeue if max shipments per a minute have been reached', function($changes) { + config()->set('data-shipper.shipments.max_shipments_per_minute', 1); + + $key = \Autoklose\DataShipper\Tests\Models\TestModel::class; + DataShipper::pushMany($key, $changes, 'id'); + + $command = new \Autoklose\DataShipper\Commands\ShipIt(); + $command->handle(); + + /** @var \Autoklose\DataShipper\ShipmentRepository $repository */ + $repository = app()->make(\Autoklose\DataShipper\ShipmentRepository::class); + expect($repository->getShipmentLength($key))->toEqual(10); + + // Should not handle another shipment + $command = new \Autoklose\DataShipper\Commands\ShipIt(); + $command->handle(); + + expect($repository->getShipmentLength($key))->toEqual(10); + + \Carbon\Carbon::setTestNow(now()->addMinute()); + $command = new \Autoklose\DataShipper\Commands\ShipIt(); + $command->handle(); + + expect($repository->getShipmentLength($key))->toEqual(0); +})->with('bulk-changes-large'); + +it('will not process a shipment while another is in progress', function($changes) { + $key = \Autoklose\DataShipper\Tests\Models\TestModel::class; + DataShipper::pushMany($key, $changes, 'id'); + \Illuminate\Support\Facades\Cache::lock("data-shipper-{$key}-active-lock")->get(); + + $command = new \Autoklose\DataShipper\Commands\ShipIt(); + $command->handle(); + + $remainingShipment = DataShipper::getPackagesForShipment($key); + expect($remainingShipment->count())->toEqual(10); +})->with('bulk-changes'); + +it('will not retry a shipment that has reached max retries', function() { + \Autoklose\DataShipper\Models\FailedShipment::create([ + 'class_name' => 'Test', + 'shipment' => 'TestKey', + 'subscriber' => 'elasticsearch', + 'last_retried_at' => now()->subHour(), + 'retries' => config('data-shipper.shipments.max_retries') + ]); + + \Illuminate\Support\Facades\Queue::fake(); + + $command = new \Autoklose\DataShipper\Commands\RetryFailedShipments(); + $command->handle(); + + \Illuminate\Support\Facades\Queue::assertNothingPushed(); +}); + +it('will retry shipments if they have not already been retried too many times', function() { + \Autoklose\DataShipper\Models\FailedShipment::create([ + 'class_name' => 'Test', + 'shipment' => 'TestKey', + 'subscriber' => 'elasticsearch', + 'last_retried_at' => now()->subHour(), + ]); + + \Illuminate\Support\Facades\Queue::fake(); + + $command = new \Autoklose\DataShipper\Commands\RetryFailedShipments(); + $command->handle(); + + \Illuminate\Support\Facades\Queue::assertPushed(\Autoklose\DataShipper\Jobs\RetryFailedShipment::class); +}); + +it('will resubmit packages to be retried', function($changes) { + $failedShipment = \Autoklose\DataShipper\Models\FailedShipment::create([ + 'class_name' => 'Test', + 'shipment' => 'TestKey', + 'subscriber' => 'elasticsearch', + 'last_retried_at' => now()->subHour(), + ]); + + \Pest\Laravel\partialMock(\Autoklose\DataShipper\Subscribers\ElasticsearchSubscriber::class, function(\Mockery\MockInterface $mock) { + $mock->expects('ship')->once(); + }); + + $failedShipment->packages()->saveMany(collect($changes)->map(fn($change) => new \Autoklose\DataShipper\Models\FailedPackage([ + 'model_id' => $change['id'], + 'payload' => $change, + ]))); + + $retryFailedShipment = new \Autoklose\DataShipper\Jobs\RetryFailedShipment($failedShipment); + $retryFailedShipment->handle(); + + \Pest\Laravel\assertDatabaseMissing('failed_shipments', ['id' => $failedShipment->id]); +})->with('bulk-changes'); + dataset('test-models', [ [fn() => \Autoklose\DataShipper\Tests\Models\TestModel::create([ 'string_field' => 'some string', @@ -148,6 +255,11 @@ [fn() => array_map(fn($i) => ['id' => $i, 'text_field' => "text change $i", 'integer' => $i * 10], range(1, 10))] ]); +dataset('bulk-changes-large', [ + [fn() => array_map(fn($i) => ['id' => $i, 'text_field' => "text change $i", 'integer' => $i * 10], range(1, 20))] +]); + beforeEach(function() { \Illuminate\Support\Facades\Redis::connection('data-shipper')->flushdb(); + \Illuminate\Support\Facades\Cache::clear(); }); diff --git a/tests/TestCase.php b/tests/TestCase.php index 169c5c4..ecf6599 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -9,27 +9,28 @@ use Orchestra\Testbench\TestCase as Orchestra; use MailerLite\LaravelElasticsearch\ServiceProvider; -class TestCase extends Orchestra -{ - protected function setUp(): void - { +class TestCase extends Orchestra { + protected function setUp(): void { parent::setUp(); Factory::guessFactoryNamesUsing( - fn (string $modelName) => 'Autoklose\\DataShipper\\Database\\Factories\\'.class_basename($modelName).'Factory' + fn(string $modelName) => 'Autoklose\\DataShipper\\Database\\Factories\\'.class_basename($modelName).'Factory' ); } - protected function getPackageProviders($app) - { + protected function getPackageProviders($app) { return [ ServiceProvider::class, DataShipperServiceProvider::class ]; } - public function getEnvironmentSetUp($app) - { + public function getEnvironmentSetUp($app) { + config()->set('queue.default', 'sync'); + config()->set('queue.connections', + ['sync' => [ + 'driver' => 'sync', + ]]); config()->set('database.connections.testing', [ "driver" => "mysql", "url" => null, @@ -49,17 +50,23 @@ public function getEnvironmentSetUp($app) ]); config()->set('database.default', 'testing'); - $result = DB::statement("DROP TABLE IF EXISTS test_models;"); + DB::statement("DROP TABLE IF EXISTS test_models;"); + DB::statement("DROP TABLE IF EXISTS failed_packages;"); + DB::statement("DROP TABLE IF EXISTS failed_shipments;"); $migration = include __DIR__.'/Migrations/create_test_model_table.php.stub'; $migration->up(); + $migration = include __DIR__.'/../database/migrations/create_failed_shipments_table.php.stub'; + $migration->up(); + $migration = include __DIR__.'/../database/migrations/create_failed_packages_table.php.stub'; + $migration->up(); + $this->setupElasticSearch($app); $this->setupRedis($app); } - public function setupRedis($app) - { + public function setupRedis($app) { config()->set('database.redis', [ 'client' => env('REDIS_CLIENT', 'phpredis'), @@ -75,58 +82,56 @@ public function setupRedis($app) $redisClient->connection('data-shipper')->flushDb(); } - public function setupElasticSearch($app) - { + public function setupElasticSearch($app) { config()->set('elasticsearch', [ - 'defaultConnection' => 'default', - 'connections' => [ + 'defaultConnection' => 'default', + 'connections' => [ - 'default' => [ - 'hosts' => [ - env('ELASTICSEARCH_HOST_CONFIG1', 'elasticsearch:9200'), - ], - 'sslVerification' => null, - 'logging' => false, - 'logPath' => storage_path('logs/elasticsearch.log'), - 'logLevel' => 'info', - 'retries' => null, - 'sniffOnStart' => false, - 'httpHandler' => null, - 'connectionPool' => null, - 'connectionSelector' => null, - 'serializer' => null, - 'connectionFactory' => null, - 'endpoint' => null, - ], - 'logger' => [ - 'hosts' => [ - env('ELASTICSEARCH_LOG_HOST', '192.168.221.8:9200'), - ], - 'sslVerification' => null, - 'logging' => false, - 'logPath' => storage_path('logs/elasticsearch.log'), - 'logLevel' => 'info', - 'retries' => null, - 'sniffOnStart' => false, - 'httpHandler' => null, - 'connectionPool' => null, - 'connectionSelector' => null, - 'serializer' => null, - 'connectionFactory' => null, - 'endpoint' => null, - ], - 'readonly' => [ - 'hosts' => [ - env('ELASTICSEARCH_HOST_CONFIG_READ', 'elasticsearch:9200'), - ], - ] - ]]); + 'default' => [ + 'hosts' => [ + env('ELASTICSEARCH_HOST_CONFIG1', 'elasticsearch:9200'), + ], + 'sslVerification' => null, + 'logging' => false, + 'logPath' => storage_path('logs/elasticsearch.log'), + 'logLevel' => 'info', + 'retries' => null, + 'sniffOnStart' => false, + 'httpHandler' => null, + 'connectionPool' => null, + 'connectionSelector' => null, + 'serializer' => null, + 'connectionFactory' => null, + 'endpoint' => null, + ], + 'logger' => [ + 'hosts' => [ + env('ELASTICSEARCH_LOG_HOST', '192.168.221.8:9200'), + ], + 'sslVerification' => null, + 'logging' => false, + 'logPath' => storage_path('logs/elasticsearch.log'), + 'logLevel' => 'info', + 'retries' => null, + 'sniffOnStart' => false, + 'httpHandler' => null, + 'connectionPool' => null, + 'connectionSelector' => null, + 'serializer' => null, + 'connectionFactory' => null, + 'endpoint' => null, + ], + 'readonly' => [ + 'hosts' => [ + env('ELASTICSEARCH_HOST_CONFIG_READ', 'elasticsearch:9200'), + ], + ] + ]]); $this->recreateIndex(); } - public function recreateIndex() - { + public function recreateIndex() { /** @var Client $client */ $client = app()->make(Client::class);