mpyw / laravel-cached-database-stickiness
保证相同用户的连续请求中数据库的粘性
v2.1.0
2023-03-13 08:30 UTC
Requires
- php: ^8.0
- ext-pdo: *
- illuminate/container: ^9.0 || ^10.0 || ^11.0
- illuminate/contracts: ^9.0 || ^10.0 || ^11.0
- illuminate/database: ^9.0 || ^10.0 || ^11.0
- illuminate/queue: ^9.0 || ^10.0 || ^11.0
- illuminate/support: ^9.0 || ^10.0 || ^11.0
Requires (Dev)
- mockery/mockery: ^1.3.3 || ^1.4.2
- orchestra/testbench: *
- orchestra/testbench-core: >=7.0
- phpunit/phpunit: >=9.5
README
保证相同用户的连续请求中数据库的粘性。
要求
- PHP:
^8.0
- Laravel:
^9.0 || ^10.0
安装
composer require mpyw/laravel-cached-database-stickiness
重要
默认实现由 ConnectionServiceProvider
提供,但是,包发现不可用。请注意,您必须自己将其注册到 config/app.php
。
<?php return [ /* ... */ 'providers' => [ /* ... */ Mpyw\LaravelCachedDatabaseStickiness\ConnectionServiceProvider::class, /* ... */ ], /* ... */ ];
然后选择适当的缓存驱动程序
功能
此库提供以下功能。
- 使HTTP服务器从之前用户的请求中接管最后5秒内的数据库粘性状态。
- 使队列工作程序默认引用主节点。
- 通过在您的 Queueable(作业、监听器、通知和可邮寄的)上实现
ShouldAssumeFresh
,使队列工作程序引用从属节点。
图表
默认
粘性
粘性缓存
高级用法
自定义粘性TTL
注意
默认粘性TTL为 5
秒。
您可以通过将 stickiness_ttl
指令添加到您的 config/database.php
来配置此值。
<?php return [ /* ... */ 'default' => env('DB_CONNECTION', 'mysql'), /* |-------------------------------------------------------------------------- | Database Connections |-------------------------------------------------------------------------- | | Here are each of the database connections setup for your application. | Of course, examples of configuring each database platform that is | supported by Laravel is shown below to make development simple. | | | All database work in Laravel is done through the PHP PDO facilities | so make sure you have the driver for your particular database of | choice installed on your machine before you begin development. | */ 'connections' => [ /* ... */ 'mysql' => [ 'read' => env('DB_HOST_READONLY') ? [ 'host' => env('DB_HOST_READONLY'), ] : null, 'write' => [], 'sticky' => (bool)env('DB_HOST_READONLY'), 'stickiness_ttl' => 3, // Set the stickiness TTL to 3 seconds 'driver' => 'mysql', 'host' => env('DB_HOST', '127.0.0.1'), 'port' => env('DB_PORT', '3306'), 'database' => env('DB_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''), /* ... */ ], ], ];
自定义连接实现
提示
您可以配置连接实现。
- 确保从
config/app.php
中移除ConnectionServiceProvider
。 - 通过自行扩展
DispatchesConnectionEvents
特性来自定义连接。
<?php namespace App\Providers; use App\Database\MySqlConnection; use Illuminate\Database\Connection; use Illuminate\Support\ServiceProvider; class DatabaseServiceProvider extends ServiceProvider { public function register(): void { Connection::resolverFor('mysql', function (...$parameters) { return new MySqlConnection(...$parameters); }); } }
<?php namespace App\Database; use Illuminate\Database\Connection as BaseMySqlConnection; use Mpyw\LaravelCachedDatabaseStickiness\DispatchesConnectionEvents; class MySqlConnection extends BaseMySqlConnection { use DispatchesConnectionEvents; }
自定义粘性来源
提示
您可以将 StickinessResolverInterface
实现注册到更改粘性确定来源。
<?php namespace App\Providers; use Illuminate\Support\ServiceProvider; use Mpyw\LaravelCachedDatabaseStickiness\StickinessResolvers\AuthBasedResolver; use Mpyw\LaravelCachedDatabaseStickiness\StickinessResolvers\StickinessResolverInterface; class DatabaseServiceProvider extends ServiceProvider { public function register(): void { $this->app->bind(StickinessResolverInterface::class, AuthBasedResolver::class); } }
重要
当您使用 AuthBasedResolver
时,您必须在 Authenticate
之后添加 ResolveStickinessOnResolvedConnections
中间件。
--- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php <?php namespace App\Http; use Illuminate\Foundation\Http\Kernel as HttpKernel; class Kernel extends HttpKernel { /* ... */ /** * The application's route middleware groups. * * @var array */ protected $middlewareGroups = [ 'web' => [ \App\Http\Middleware\EncryptCookies::class, \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, \Illuminate\Session\Middleware\StartSession::class, // \Illuminate\Session\Middleware\AuthenticateSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, \App\Http\Middleware\VerifyCsrfToken::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, ], 'api' => [ 'throttle:60,1', \Illuminate\Routing\Middleware\SubstituteBindings::class, ], + + 'auth' => [ + \App\Http\Middleware\Authenticate::class, + \Mpyw\LaravelCachedDatabaseStickiness\Http\Middleware\ResolveStickinessOnResolvedConnections::class, + ], + + 'auth.basic' => [ + \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, + \Mpyw\LaravelCachedDatabaseStickiness\Http\Middleware\ResolveStickinessOnResolvedConnections::class, + ], ]; /** * The application's route middleware. * * These middleware may be assigned to groups or used individually. * * @var array */ protected $routeMiddleware = [ - 'auth' => \App\Http\Middleware\Authenticate::class, - 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class, 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class, 'can' => \Illuminate\Auth\Middleware\Authorize::class, 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, 'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class, 'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class, 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class, ]; /* ... */ }
自定义工作程序行为
提示
您可以将 JobInitializerInterface
实现注册以更改工作程序的行为。
<?php namespace App\Providers; use Illuminate\Support\ServiceProvider; use Mpyw\LaravelCachedDatabaseStickiness\JobInitializers\AlwaysFreshInitializer; use Mpyw\LaravelCachedDatabaseStickiness\JobInitializers\JobInitializerInterface; class DatabaseServiceProvider extends ServiceProvider { public function register(): void { $this->app->bind(JobInitializerInterface::class, AlwaysFreshInitializer::class); } }
注意
小心
不要在 ServiceProvider::boot()
中调用 Schema::defaultStringLength()
问题
假设您有以下 ServiceProvider
。
<?php namespace App\Providers; use Illuminate\Support\Facades\Schema; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider { /** * Bootstrap any application services. * * @return void */ public function boot() { Schema::defaultStringLength(191); } }
如果您运行 composer install
或直接调用 php artisan pacakge:discover
,它将意外地使用缓存。当我们在无法访问缓存存储库的环境中执行命令时,它将触发错误。
RedisException : Operation timed out
解决方案
直接使用 Illuminate\Database\Schema\Builder
。不要通过 Illuminate\Support\Facades\Schema
Facade 调用。
<?php namespace App\Providers; -use Illuminate\Support\Facades\Schema; +use Illuminate\Database\Schema\Builder as SchemaBuilder; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider { /** * Bootstrap any application services. * * @return void */ public function boot() { - Schema::defaultStringLength(191); + SchemaBuilder::defaultStringLength(191); } }