mirror of
https://github.com/jikan-me/jikan-rest.git
synced 2025-02-20 11:23:35 +08:00
add automatic MAL health checker/failover based on uncached response statuses
This commit is contained in:
parent
b542d100c7
commit
7d9d60833e
31
app/Events/SourceHealthEvent.php
Normal file
31
app/Events/SourceHealthEvent.php
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Events;
|
||||||
|
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class SourceHealthEvent
|
||||||
|
* @package App\Events
|
||||||
|
*/
|
||||||
|
class SourceHealthEvent extends Event
|
||||||
|
{
|
||||||
|
public const BAD_HEALTH = 1;
|
||||||
|
public const GOOD_HEALTH = 0;
|
||||||
|
|
||||||
|
public $health;
|
||||||
|
public $status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SourceHealthEvent constructor.
|
||||||
|
* @param int $health
|
||||||
|
* @param int $status
|
||||||
|
*/
|
||||||
|
public function __construct(int $health = self::BAD_HEALTH, ?int $status)
|
||||||
|
{
|
||||||
|
$this->health = $health;
|
||||||
|
$this->status = $status ?? 0;
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Exceptions;
|
namespace App\Exceptions;
|
||||||
|
|
||||||
|
use App\Events\SourceHealthEvent;
|
||||||
use App\Http\HttpHelper;
|
use App\Http\HttpHelper;
|
||||||
use Exception;
|
use Exception;
|
||||||
use GuzzleHttp\Exception\ClientException;
|
use GuzzleHttp\Exception\ClientException;
|
||||||
@ -109,10 +110,17 @@ class Handler extends ExceptionHandler
|
|||||||
'message' => 'Jikan is being rate limited by MyAnimeList',
|
'message' => 'Jikan is being rate limited by MyAnimeList',
|
||||||
'error' => $e->getMessage()
|
'error' => $e->getMessage()
|
||||||
], $e->getCode());
|
], $e->getCode());
|
||||||
|
case 403:
|
||||||
case 500:
|
case 500:
|
||||||
|
case 501:
|
||||||
case 502:
|
case 502:
|
||||||
case 503:
|
case 503:
|
||||||
case 504:
|
case 504:
|
||||||
|
// Dispatch Bad source health event to prompt database fallback if enabled
|
||||||
|
if (env('SOURCE_BAD_HEALTH_FALLBACK') && env('DB_CACHING')) {
|
||||||
|
event(new SourceHealthEvent(SourceHealthEvent::BAD_HEALTH, $e->getCode()));
|
||||||
|
}
|
||||||
|
|
||||||
return response()
|
return response()
|
||||||
->json([
|
->json([
|
||||||
'status' => $e->getCode(),
|
'status' => $e->getCode(),
|
||||||
|
@ -3,8 +3,11 @@
|
|||||||
namespace App\Http\Middleware;
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
use App\DatabaseHandler;
|
use App\DatabaseHandler;
|
||||||
|
use App\Events\SourceHealthEvent;
|
||||||
use App\Http\HttpHelper;
|
use App\Http\HttpHelper;
|
||||||
use App\Jobs\UpdateCacheJob;
|
use App\Jobs\UpdateCacheJob;
|
||||||
|
use App\Jobs\UpdateDatabaseJob;
|
||||||
|
use App\Providers\SourceHealthServiceProvider;
|
||||||
use Closure;
|
use Closure;
|
||||||
use Flipbox\LumenGenerator\LumenGeneratorServiceProvider;
|
use Flipbox\LumenGenerator\LumenGeneratorServiceProvider;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
@ -12,6 +15,7 @@ use Illuminate\Support\Facades\Cache;
|
|||||||
use Illuminate\Support\Facades\Date;
|
use Illuminate\Support\Facades\Date;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\Schema;
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Jenssegers\Mongodb\MongodbServiceProvider;
|
use Jenssegers\Mongodb\MongodbServiceProvider;
|
||||||
use MongoDB\BSON\UTCDateTime;
|
use MongoDB\BSON\UTCDateTime;
|
||||||
use MongoDB\Client;
|
use MongoDB\Client;
|
||||||
@ -33,6 +37,8 @@ class DatabaseResolver
|
|||||||
|
|
||||||
private $queueable = true;
|
private $queueable = true;
|
||||||
|
|
||||||
|
private $table;
|
||||||
|
|
||||||
private const NON_QUEUEABLE = [
|
private const NON_QUEUEABLE = [
|
||||||
'UserController@profile',
|
'UserController@profile',
|
||||||
'UserController@history',
|
'UserController@history',
|
||||||
@ -47,6 +53,7 @@ class DatabaseResolver
|
|||||||
|
|
||||||
public function handle(Request $request, Closure $next)
|
public function handle(Request $request, Closure $next)
|
||||||
{
|
{
|
||||||
|
|
||||||
if ($request->header('auth') === env('APP_KEY')) {
|
if ($request->header('auth') === env('APP_KEY')) {
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
@ -73,35 +80,49 @@ class DatabaseResolver
|
|||||||
$this->route = end($this->route);
|
$this->route = end($this->route);
|
||||||
|
|
||||||
$db = new DatabaseHandler();
|
$db = new DatabaseHandler();
|
||||||
$table = $db::getMappedTableName($this->route);
|
$this->table = $db::getMappedTableName($this->route);
|
||||||
|
$this->requestCached = DB::table($this->table)->where('request_hash', $this->fingerprint)->exists();
|
||||||
|
|
||||||
$this->requestCached = DB::table($table)->where('request_hash', $this->fingerprint)->exists();
|
// Is the request queueable?
|
||||||
|
if (\in_array($this->route, self::NON_QUEUEABLE) || env('CACHE_METHOD', 'legacy') === 'legacy') {
|
||||||
// Cache if it doesn't exist
|
$this->queueable = false;
|
||||||
if (!$this->requestCached) {
|
|
||||||
$response = $next($request);
|
|
||||||
|
|
||||||
if (HttpHelper::hasError($response)) {
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
DB::table($table)->insert(array_merge(
|
|
||||||
[
|
|
||||||
'expireAfterSeconds' => $this->requestCacheTtl,
|
|
||||||
'request_hash' => $this->fingerprint
|
|
||||||
],
|
|
||||||
json_decode($response->original, true)
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If cache does not exist
|
||||||
|
if (!$this->requestCached) {
|
||||||
|
return $this->fetchFresh($request, $next);
|
||||||
|
}
|
||||||
|
|
||||||
// Return response
|
// Fetch Cache & Generate Meta
|
||||||
$meta = $this->generateMeta($request);
|
$meta = $this->generateMeta($request);
|
||||||
|
|
||||||
$cache = DB::table($table)->where('request_hash', $this->fingerprint)->get();
|
$cache = DB::table($this->table)->where('request_hash', $this->fingerprint)->get();
|
||||||
$cacheMutable = json_decode($cache, true)[0];
|
$cacheMutable = json_decode($cache, true)[0];
|
||||||
$cacheMutable = $this->cacheMutation($cacheMutable);
|
$cacheMutable = $this->cacheMutation($cacheMutable);
|
||||||
|
|
||||||
|
// If cache is expired, handle it depending on whether it's queueable
|
||||||
|
$expiresAt = $cacheMutable['expiresAt']['$date']['$numberLong']/1000;
|
||||||
|
|
||||||
|
if ($this->requestCached && $expiresAt > time() && !$this->queueable) {
|
||||||
|
return $this->fetchFresh($request, $next);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $this->queueable && $expiresAt > time()) {
|
||||||
|
$queueFingerprint = "queue_update:{$this->fingerprint}";
|
||||||
|
$queueHighPriority = \in_array($this->route, self::HIGH_PRIORITY_QUEUE);
|
||||||
|
|
||||||
|
// Don't duplicate the job in the queue for same request
|
||||||
|
$job = DB::table(env('QUEUE_TABLE', 'jobs'))->where('request_hash', $this->fingerprint);
|
||||||
|
|
||||||
|
if (!$job->exists()) {
|
||||||
|
dispatch(
|
||||||
|
(new UpdateDatabaseJob($request))
|
||||||
|
->onQueue($queueHighPriority ? 'high' : 'low')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$response = array_merge($meta, $cacheMutable);
|
$response = array_merge($meta, $cacheMutable);
|
||||||
unset($response['createdAt'], $response['expireAfterSeconds'], $response['_id']);
|
unset($response['createdAt'], $response['expireAfterSeconds'], $response['_id']);
|
||||||
|
|
||||||
@ -163,4 +184,21 @@ class DatabaseResolver
|
|||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function fetchFresh($request, $next)
|
||||||
|
{
|
||||||
|
$response = $next($request);
|
||||||
|
|
||||||
|
if (HttpHelper::hasError($response)) {
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
DB::table($this->table)->insert(array_merge(
|
||||||
|
[
|
||||||
|
'expiresAt' => new UTCDateTime((time()+$this->requestCacheTtl)*1000),
|
||||||
|
'request_hash' => $this->fingerprint
|
||||||
|
],
|
||||||
|
json_decode($response->original, true)
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
25
app/Http/Middleware/SourceHealthMonitor.php
Normal file
25
app/Http/Middleware/SourceHealthMonitor.php
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use App\Events\SourceHealthEvent;
|
||||||
|
|
||||||
|
class SourceHealthMonitor
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @param \Closure $next
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle($request, Closure $next)
|
||||||
|
{
|
||||||
|
if (env('SOURCE_BAD_HEALTH_FAILOVER') && env('DB_CACHING')) {
|
||||||
|
event(new SourceHealthEvent(SourceHealthEvent::GOOD_HEALTH, 200));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
77
app/Jobs/UpdateDatabaseJob.php
Normal file
77
app/Jobs/UpdateDatabaseJob.php
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use App\Http\HttpHelper;
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class UpdateDatabaseJob
|
||||||
|
* @package App\Jobs
|
||||||
|
*/
|
||||||
|
class UpdateDatabaseJob extends Job
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
public $timeout = 60;
|
||||||
|
|
||||||
|
public $retryAfter = 60;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $requestUri;
|
||||||
|
protected $requestType;
|
||||||
|
protected $requestCacheTtl;
|
||||||
|
protected $fingerprint;
|
||||||
|
protected $cacheExpiryFingerprint;
|
||||||
|
protected $requestCached;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct(Request $request)
|
||||||
|
{
|
||||||
|
$this->fingerprint = HttpHelper::resolveRequestFingerprint($request);
|
||||||
|
|
||||||
|
$this->requestCached = DB::table(env('QUEUE_TABLE', 'jobs'))->where('request_hash', $this->fingerprint);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \GuzzleHttp\Exception\GuzzleException
|
||||||
|
*/
|
||||||
|
public function handle() : void
|
||||||
|
{
|
||||||
|
$client = new Client();
|
||||||
|
|
||||||
|
$response = $client
|
||||||
|
->request(
|
||||||
|
'GET',
|
||||||
|
env('APP_URL') . $this->requestUri,
|
||||||
|
[
|
||||||
|
'headers' => [
|
||||||
|
'auth' => env('APP_KEY') // skip middleware
|
||||||
|
]
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$cache = json_decode($response->getBody()->getContents(), true);
|
||||||
|
unset($cache['request_hash'], $cache['request_cached'], $cache['request_cache_expiry']);
|
||||||
|
$cache = json_encode($cache);
|
||||||
|
|
||||||
|
sleep((int) env('QUEUE_DELAY_PER_JOB', 5));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function failed(\Exception $e)
|
||||||
|
{
|
||||||
|
Log::error($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
150
app/Listeners/SourceHealthListener.php
Normal file
150
app/Listeners/SourceHealthListener.php
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Listeners;
|
||||||
|
|
||||||
|
use App\Events\ExampleEvent;
|
||||||
|
use App\Events\SourceHealthEvent;
|
||||||
|
use App\Providers\SourceHealthServiceProvider;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use League\Flysystem\FileNotFoundException;
|
||||||
|
use Monolog\Handler\StreamHandler;
|
||||||
|
use Monolog\Logger;
|
||||||
|
|
||||||
|
class SourceHealthListener
|
||||||
|
{
|
||||||
|
|
||||||
|
private $logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the event listener.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->logger = new Logger('source-health-monitor');
|
||||||
|
$this->logger->pushHandler(new StreamHandler(storage_path().'/logs/source-health-monitor.log'), Logger::DEBUG);
|
||||||
|
|
||||||
|
if (SourceHealthServiceProvider::isFailoverEnabled()) {
|
||||||
|
$lastFailoverLockTimestamp = $this->getLastFailoverLockTimestamp();
|
||||||
|
$this->logger->debug('Failover is RUNNING');
|
||||||
|
|
||||||
|
// Disable failover if it has expired
|
||||||
|
if (time() > ($lastFailoverLockTimestamp + env('SOURCE_BAD_HEALTH_RECHECK'))) {
|
||||||
|
// Disable failover if successful requests score
|
||||||
|
$this->attemptDisableFailover();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the event.
|
||||||
|
*
|
||||||
|
* @param ExampleEvent $event
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handle(SourceHealthEvent $event)
|
||||||
|
{
|
||||||
|
$eventCount = $this->insertFail($event);
|
||||||
|
$this->logger->debug('Event count: '.$eventCount);
|
||||||
|
|
||||||
|
if ($this->getSuccessfulRequestsScore() <= 0.25) {
|
||||||
|
$this->enableFailover();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function insertFail(SourceHealthEvent $event) : int
|
||||||
|
{
|
||||||
|
$fails = $this->getRecentFails();
|
||||||
|
$fails[] = [time(), $event->status, $event->health];
|
||||||
|
|
||||||
|
$failsJson = json_encode($fails);
|
||||||
|
Storage::put('failovers.json', $failsJson);
|
||||||
|
|
||||||
|
return count($fails);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function enableFailover()
|
||||||
|
{
|
||||||
|
// create lock file
|
||||||
|
Storage::put('source_failover.lock', '');
|
||||||
|
$this->logger->debug('Failover ENABLED');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function disableFailover()
|
||||||
|
{
|
||||||
|
// delete lock file
|
||||||
|
Storage::delete('source_failover.lock');
|
||||||
|
|
||||||
|
// Delete meta
|
||||||
|
Storage::delete('failovers.json');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function attemptDisableFailover()
|
||||||
|
{
|
||||||
|
$score = $this->getSuccessfulRequestsScore();
|
||||||
|
|
||||||
|
if ($score >= 0.9) {
|
||||||
|
$this->disableFailover();
|
||||||
|
$this->logger->debug('Failover disabled; Score: '.$score);
|
||||||
|
$this->logger->debug('Failover DISABLED');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getLastFailoverLockTimestamp()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return Storage::lastModified('source_failover.lock');
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getRecentFails()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$failsJson = Storage::get('failovers.json');
|
||||||
|
$fails = json_decode($failsJson, true);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$fails = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove any fails greater than SOURCE_BAD_HEALTH_RANGE
|
||||||
|
foreach ($fails as $fail) {
|
||||||
|
|
||||||
|
if ($fail[0] >= (time()-env('SOURCE_BAD_HEALTH_RANGE'))) {
|
||||||
|
unset($fail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// slice
|
||||||
|
if (count($fails) > env('SOURCE_BAD_HEALTH_MAX_STORE')) {
|
||||||
|
$fails = array_slice($fails, 0 - env('SOURCE_BAD_HEALTH_MAX_STORE'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $fails;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getSuccessfulRequestsScore() : float
|
||||||
|
{
|
||||||
|
$fails = $this->getRecentFails();
|
||||||
|
$score = 0;
|
||||||
|
$totalFails = count($fails) - 1;
|
||||||
|
|
||||||
|
foreach ($fails as $fail) {
|
||||||
|
if ((int) $fail[2] === SourceHealthEvent::GOOD_HEALTH) {
|
||||||
|
$score++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$scored = $score / max($totalFails, 1);
|
||||||
|
$this->logger->debug('Failover successful requests score: '.$scored);
|
||||||
|
|
||||||
|
return $scored;
|
||||||
|
}
|
||||||
|
}
|
@ -235,9 +235,6 @@ class SearchQueryBuilder
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Anime
|
// Anime
|
||||||
if ($request instanceof AnimeSearchRequest) {
|
if ($request instanceof AnimeSearchRequest) {
|
||||||
// Rating/Rated
|
// Rating/Rated
|
||||||
|
28
app/Providers/SourceHealthServiceProvider.php
Normal file
28
app/Providers/SourceHealthServiceProvider.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Laravel\Lumen\Providers\EventServiceProvider as ServiceProvider;
|
||||||
|
|
||||||
|
class SourceHealthServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
|
||||||
|
const BAD_HEALTH_STATUSES = [403, 500, 501, 502, 503, 504, 505];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The event listener mappings for the application.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $listen = [
|
||||||
|
'App\Events\SourceHealthEvent' => [
|
||||||
|
'App\Listeners\SourceHealthListener',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
public static function isFailoverEnabled() : bool
|
||||||
|
{
|
||||||
|
return Storage::exists('source_failover.lock');
|
||||||
|
}
|
||||||
|
}
|
@ -77,7 +77,8 @@ $app->routeMiddleware([
|
|||||||
'throttle' => App\Http\Middleware\Throttle::class,
|
'throttle' => App\Http\Middleware\Throttle::class,
|
||||||
'etag' => \App\Http\Middleware\EtagMiddleware::class,
|
'etag' => \App\Http\Middleware\EtagMiddleware::class,
|
||||||
'microcaching' => \App\Http\Middleware\MicroCaching::class,
|
'microcaching' => \App\Http\Middleware\MicroCaching::class,
|
||||||
'database-resolver' => \App\Http\Middleware\DatabaseResolver::class
|
'database-resolver' => \App\Http\Middleware\DatabaseResolver::class,
|
||||||
|
'source-health-monitor' => \App\Http\Middleware\SourceHealthMonitor::class
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -108,6 +109,10 @@ $app->instance('GuzzleClient', $guzzleClient);
|
|||||||
$jikan = new \Jikan\MyAnimeList\MalClient(app('GuzzleClient'));
|
$jikan = new \Jikan\MyAnimeList\MalClient(app('GuzzleClient'));
|
||||||
$app->instance('JikanParser', $jikan);
|
$app->instance('JikanParser', $jikan);
|
||||||
|
|
||||||
|
if (env('SOURCE_BAD_HEALTH_FAILOVER') && env('DB_CACHING')) {
|
||||||
|
$app->register(\App\Providers\SourceHealthServiceProvider::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load Blacklist into Redis
|
* Load Blacklist into Redis
|
||||||
@ -134,6 +139,7 @@ $commonMiddleware = [
|
|||||||
// 'microcaching',
|
// 'microcaching',
|
||||||
// 'cache-resolver',
|
// 'cache-resolver',
|
||||||
// 'throttle'
|
// 'throttle'
|
||||||
|
'source-health-monitor'
|
||||||
];
|
];
|
||||||
|
|
||||||
$app->router->group(
|
$app->router->group(
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
"jikan-me/jikan": "^3.0",
|
"jikan-me/jikan": "^3.0",
|
||||||
"jms/serializer": "^1.13",
|
"jms/serializer": "^1.13",
|
||||||
"laravel/lumen-framework": "^7.0",
|
"laravel/lumen-framework": "^7.0",
|
||||||
|
"league/flysystem": "^1.0",
|
||||||
"ocramius/package-versions": "^1.4",
|
"ocramius/package-versions": "^1.4",
|
||||||
"predis/predis": "^1.1",
|
"predis/predis": "^1.1",
|
||||||
"symfony/yaml": "^4.1",
|
"symfony/yaml": "^4.1",
|
||||||
|
86
composer.lock
generated
86
composer.lock
generated
@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "6d42be876cc0e4c456de620bd8aa6321",
|
"content-hash": "14c8c6eb422e03b6838bba397af565ff",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "brick/math",
|
"name": "brick/math",
|
||||||
@ -2523,6 +2523,90 @@
|
|||||||
],
|
],
|
||||||
"time": "2020-05-05T18:17:08+00:00"
|
"time": "2020-05-05T18:17:08+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "league/flysystem",
|
||||||
|
"version": "1.0.69",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/thephpleague/flysystem.git",
|
||||||
|
"reference": "7106f78428a344bc4f643c233a94e48795f10967"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/7106f78428a344bc4f643c233a94e48795f10967",
|
||||||
|
"reference": "7106f78428a344bc4f643c233a94e48795f10967",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-fileinfo": "*",
|
||||||
|
"php": ">=5.5.9"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"league/flysystem-sftp": "<1.0.6"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpspec/phpspec": "^3.4",
|
||||||
|
"phpunit/phpunit": "^5.7.26"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-fileinfo": "Required for MimeType",
|
||||||
|
"ext-ftp": "Allows you to use FTP server storage",
|
||||||
|
"ext-openssl": "Allows you to use FTPS server storage",
|
||||||
|
"league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2",
|
||||||
|
"league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3",
|
||||||
|
"league/flysystem-azure": "Allows you to use Windows Azure Blob storage",
|
||||||
|
"league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching",
|
||||||
|
"league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem",
|
||||||
|
"league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files",
|
||||||
|
"league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib",
|
||||||
|
"league/flysystem-webdav": "Allows you to use WebDAV storage",
|
||||||
|
"league/flysystem-ziparchive": "Allows you to use ZipArchive adapter",
|
||||||
|
"spatie/flysystem-dropbox": "Allows you to use Dropbox storage",
|
||||||
|
"srmklive/flysystem-dropbox-v2": "Allows you to use Dropbox storage for PHP 5 applications"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.1-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"League\\Flysystem\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Frank de Jonge",
|
||||||
|
"email": "info@frenky.net"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Filesystem abstraction: Many filesystems, one API.",
|
||||||
|
"keywords": [
|
||||||
|
"Cloud Files",
|
||||||
|
"WebDAV",
|
||||||
|
"abstraction",
|
||||||
|
"aws",
|
||||||
|
"cloud",
|
||||||
|
"copy.com",
|
||||||
|
"dropbox",
|
||||||
|
"file systems",
|
||||||
|
"files",
|
||||||
|
"filesystem",
|
||||||
|
"filesystems",
|
||||||
|
"ftp",
|
||||||
|
"rackspace",
|
||||||
|
"remote",
|
||||||
|
"s3",
|
||||||
|
"sftp",
|
||||||
|
"storage"
|
||||||
|
],
|
||||||
|
"time": "2020-05-18T15:13:39+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "mongodb/mongodb",
|
"name": "mongodb/mongodb",
|
||||||
"version": "1.6.0",
|
"version": "1.6.0",
|
||||||
|
3
storage/app/.gitignore
vendored
3
storage/app/.gitignore
vendored
@ -0,0 +1,3 @@
|
|||||||
|
!.gitignore
|
||||||
|
failovers.json
|
||||||
|
source_failover.lock
|
3
storage/logs/.gitignore
vendored
3
storage/logs/.gitignore
vendored
@ -1,2 +1,5 @@
|
|||||||
*
|
*
|
||||||
!.gitignore
|
!.gitignore
|
||||||
|
source-health-monitor.log
|
||||||
|
worker.error.log
|
||||||
|
worker.log
|
Loading…
x
Reference in New Issue
Block a user