Skip to content

Commit

Permalink
feat: delay queued jobs using a random window (#87)
Browse files Browse the repository at this point in the history
to prevent excessive call at time from all existing SeAT instances in the world, add some randomness to token update batches.

also queue jobs related to corporation only for token having a Director role.
most of corporation endpoints are requiring that role and that should reduce the amount of calls by the meantime.

seed scheduler using random values overriding default scheduler at every time it's ran.
to ensure all existing instance benefits of the change, we force scheduler to be seeded even if commands already exist.

Related to eveseat/seat#731
  • Loading branch information
warlof authored Dec 21, 2020
1 parent 2dd3e10 commit a5ae475
Show file tree
Hide file tree
Showing 9 changed files with 214 additions and 77 deletions.
71 changes: 71 additions & 0 deletions src/Bus/Alliance.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php

/*
* This file is part of SeAT
*
* Copyright (C) 2015 to 2020 Leon Jacobs
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

namespace Seat\Console\Bus;

use Seat\Eveapi\Jobs\Alliances\Info;
use Seat\Eveapi\Jobs\Alliances\Members;
use Seat\Eveapi\Jobs\Contacts\Alliance\Contacts;
use Seat\Eveapi\Jobs\Contacts\Alliance\Labels;
use Seat\Eveapi\Models\RefreshToken;

/**
* Class Alliance.
*
* @package Seat\Console\Bus
*/
class Alliance extends BusCommand
{
/**
* @var int
*/
private $alliance_id;

/**
* @var \Seat\Eveapi\Models\RefreshToken
*/
private $token;

/**
* Alliance constructor.
*
* @param int $alliance_id
* @param \Seat\Eveapi\Models\RefreshToken $token
*/
public function __construct(int $alliance_id, RefreshToken $token)
{
$this->token = $token;
$this->alliance_id = $alliance_id;
}

public function fire()
{
Info::withChain([
new Members($this->alliance_id),
new Labels($this->alliance_id, $this->token),
new Contacts($this->alliance_id, $this->token),
])->dispatch($this->alliance_id)->delay(now()->addSeconds(rand(120, 600)));
// in order to prevent ESI to receive massive income of all existing SeAT instances in the world
// add a bit of randomize when job can be processed - we use seconds here, so we have more flexibility
// https://github.com/eveseat/seat/issues/731
}
}
9 changes: 4 additions & 5 deletions src/Bus/Character.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,9 @@
use Seat\Eveapi\Jobs\Clones\Implants;
use Seat\Eveapi\Jobs\Contacts\Character\Contacts;
use Seat\Eveapi\Jobs\Contacts\Character\Labels as ContactLabels;
use Seat\Eveapi\Jobs\Contracts\Character\Contracts;
use Seat\Eveapi\Jobs\Fittings\Character\Fittings;
use Seat\Eveapi\Jobs\Industry\Character\Jobs;
use Seat\Eveapi\Jobs\Industry\Character\Mining;
use Seat\Eveapi\Jobs\Killmails\Character\Recent;
use Seat\Eveapi\Jobs\Location\Character\Location;
use Seat\Eveapi\Jobs\Location\Character\Online;
use Seat\Eveapi\Jobs\Location\Character\Ship;
Expand Down Expand Up @@ -111,7 +109,6 @@ public function fire()

// collect military informations
new Fittings($this->token),
new Recent($this->token),

new Fatigue($this->token),
new Medals($this->token),
Expand All @@ -124,7 +121,6 @@ public function fire()

// collect financial informations
new Orders($this->token),
new Contracts($this->token),
new Planets($this->token),
new Balance($this->token),
new Journal($this->token),
Expand All @@ -149,6 +145,9 @@ public function fire()
new Names($this->token),
new Locations($this->token),
new CharacterStructures($this->token),
])->dispatch($this->token->character_id);
])->dispatch($this->token->character_id)->delay(now()->addSeconds(rand(10, 120)));
// in order to prevent ESI to receive massive income of all existing SeAT instances in the world
// add a bit of randomize when job can be processed - we use seconds here, so we have more flexibility
// https://github.com/eveseat/seat/issues/731
}
}
11 changes: 4 additions & 7 deletions src/Bus/Corporation.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
use Seat\Eveapi\Jobs\Assets\Corporation\Names;
use Seat\Eveapi\Jobs\Contacts\Corporation\Contacts;
use Seat\Eveapi\Jobs\Contacts\Corporation\Labels;
use Seat\Eveapi\Jobs\Contracts\Corporation\Contracts;
use Seat\Eveapi\Jobs\Corporation\AllianceHistory;
use Seat\Eveapi\Jobs\Corporation\Blueprints;
use Seat\Eveapi\Jobs\Corporation\ContainerLogs;
Expand All @@ -52,7 +51,6 @@
use Seat\Eveapi\Jobs\Industry\Corporation\Mining\Extractions;
use Seat\Eveapi\Jobs\Industry\Corporation\Mining\ObserverDetails;
use Seat\Eveapi\Jobs\Industry\Corporation\Mining\Observers;
use Seat\Eveapi\Jobs\Killmails\Corporation\Recent;
use Seat\Eveapi\Jobs\Market\Corporation\Orders;
use Seat\Eveapi\Jobs\PlanetaryInteraction\Corporation\CustomsOfficeLocations;
use Seat\Eveapi\Jobs\PlanetaryInteraction\Corporation\CustomsOffices;
Expand Down Expand Up @@ -116,9 +114,6 @@ public function fire()
new Medals($this->corporation_id, $this->token),
new IssuedMedals($this->corporation_id, $this->token),

// collect military informations
new Recent($this->corporation_id, $this->token),

// collect industrial informations
new Blueprints($this->corporation_id, $this->token),
new Facilities($this->corporation_id, $this->token),
Expand All @@ -128,7 +123,6 @@ public function fire()

// collect financial informations
new Orders($this->corporation_id, $this->token),
new Contracts($this->corporation_id, $this->token),
new Shareholders($this->corporation_id, $this->token),
new Balances($this->corporation_id, $this->token),
new Journals($this->corporation_id, $this->token),
Expand All @@ -153,6 +147,9 @@ public function fire()
new Locations($this->corporation_id, $this->token),
new Names($this->corporation_id, $this->token),
new CorporationStructures($this->corporation_id, $this->token),
])->dispatch($this->corporation_id);
])->dispatch($this->corporation_id)->delay(now()->addSeconds(rand(120, 300)));
// in order to prevent ESI to receive massive income of all existing SeAT instances in the world
// add a bit of randomize when job can be processed - we use seconds here, so we have more flexibility
// https://github.com/eveseat/seat/issues/731
}
}
58 changes: 38 additions & 20 deletions src/Commands/Esi/Update/Alliances.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,10 @@
namespace Seat\Console\Commands\Esi\Update;

use Illuminate\Console\Command;
use Seat\Console\Bus\Alliance as AllianceBus;
use Seat\Eveapi\Jobs\Alliances\Alliances as AlliancesJob;
use Seat\Eveapi\Jobs\Alliances\Info;
use Seat\Eveapi\Jobs\Alliances\Members;
use Seat\Eveapi\Jobs\Contacts\Alliance\Contacts;
use Seat\Eveapi\Jobs\Contacts\Alliance\Labels;
use Seat\Eveapi\Models\Alliances\Alliance;
use Seat\Eveapi\Models\RefreshToken;

Expand All @@ -48,10 +47,40 @@ class Alliances extends Command
*/
protected $description = 'Schedule update jobs for alliances';

/**
* @var array
*/
private $alliance_blacklist = [];

/**
* Execute the console command.
*/
public function handle()
{
$this->processTokens();
$this->processPublics();
}

private function processTokens()
{
$tokens = RefreshToken::whereHas('character.affiliation', function ($query) {
$query->whereNotNull('alliance_id');
})->when($this->argument('alliance_ids'), function ($tokens) {
return $tokens->whereIn('character.affiliation.alliance_id', $this->argument('alliance_ids'));
})->get()->unique('character.affiliation.alliance_id')->each(function ($token) {

// init a blacklist which will be seed by token loop in order to prevent multiple jobs targetting same alliance
// to be queued
$this->alliance_blacklist[] = $token->character->affiliation->alliance_id;

// Fire the class to update alliance information
(new AllianceBus($token->character->affiliation->alliance_id, $token))->fire();
});

$this->info('Processed ' . $tokens->count() . ' refresh tokens.');
}

private function processPublics()
{
// collect optional alliance ID from arguments
$alliance_ids = $this->argument('alliance_ids') ?: [];
Expand All @@ -65,25 +94,14 @@ public function handle()
// loop over alliances and queue detailed jobs
// if we don't have any alliance registered -> queue a global job to collect them
if ($alliances->get()->each(function ($alliance) {
Info::dispatch($alliance->alliance_id);
Members::dispatch($alliance->alliance_id);
})->isEmpty() && empty($alliance_ids)) AlliancesJob::dispatch();

$tokens = RefreshToken::all()
->when(count($this->argument('alliance_ids')) > 0, function ($tokens) {
// ignore already processed alliances
if (in_array($alliance->alliance_id, $this->alliance_blacklist))
return true;

return $tokens->whereIn('character.affiliation.alliance_id', $this->argument('alliance_ids'));
})
->each(function ($token) {

// Fire the class to update alliance information
if ($token->character->affiliation->alliance_id != null) {
Contacts::withChain([
new Labels($token->character->affiliation->alliance_id, $token),
])->dispatch($token->character->affiliation->alliance_id, $token);
}
});

$this->info('Processed ' . $tokens->count() . ' refresh tokens.');
Info::withChain([
new Members($alliance->alliance_id),
])->dispatch($alliance->alliance_id)->delay(now()->addSeconds(rand(20, 300)));
})->isEmpty() && empty($alliance_ids)) AlliancesJob::dispatch();
}
}
19 changes: 11 additions & 8 deletions src/Commands/Esi/Update/Contracts.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,19 +74,22 @@ public function handle()

private function enqueueContractsListJobs()
{
// process all tokens character contracts by batch of 100
RefreshToken::chunk(100, function ($tokens) {
foreach ($tokens as $token) {

// enqueue job to list contracts for that character
CharacterContracts::dispatch($token);

// in case this character is also a Director, enqueue job to list contracts for his corporation
if ($token->whereHas('character.corporation_roles', function ($query) {
$query->where('scope', 'roles');
$query->where('role', 'Director');
})) CorporationContracts::dispatch($token->character->affiliation->corporation_id, $token);
}
});

// process all tokens corporation contracts with a Director role
RefreshToken::whereHas('character.affiliation', function ($query) {
$query->whereNotNull('corporation_id');
})->whereHas('character.corporation_roles', function ($query) {
$query->where('scope', 'roles');
$query->where('role', 'Director');
})->get()->unique('character.affiliation.corporation_id')->each(function ($token) {
CorporationContracts::dispatch($token->character->affiliation->corporation_id, $token);
});
}

/**
Expand Down
27 changes: 15 additions & 12 deletions src/Commands/Esi/Update/Corporations.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class Corporations extends Command
* @var string
*/
protected $signature = 'esi:update:corporations {character_id? : Optional character_id to update ' .
'corporation information for}';
'corporation information for}';

/**
* The console command description.
Expand All @@ -53,18 +53,21 @@ class Corporations extends Command
*/
public function handle()
{
// to prevent excessive calls, we queue only jobs for tokens with Director role.
// more than 80% of corporation endpoints are requiring this role anyway.
// https://github.com/eveseat/seat/issues/731
$tokens = RefreshToken::whereHas('character.affiliation', function ($query) {
$query->whereNotNull('corporation_id');
})->whereHas('character.corporation_roles', function ($query) {
$query->where('scope', 'roles');
$query->where('role', 'Director');
})->when($this->argument('character_id'), function ($tokens) {
return $tokens->where('character_id', $this->argument('character_id'));
})->get()->unique('character.affiliation.corporation_id')->each(function ($token) {

$tokens = RefreshToken::all()
->when($this->argument('character_id'), function ($tokens) {

return $tokens->where('character_id', $this->argument('character_id'));
})
->each(function ($token) {

// Fire the class to update corporation information
if ($token->character->affiliation->corporation_id != null)
(new Corporation($token->character->affiliation->corporation_id, $token))->fire();
});
// Fire the class to update corporation information
(new Corporation($token->character->affiliation->corporation_id, $token))->fire();
});

$this->info('Processed ' . $tokens->count() . ' refresh tokens.');

Expand Down
16 changes: 12 additions & 4 deletions src/Commands/Esi/Update/Killmails.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,19 @@ public function handle()
if ($killmails->get()->each(function ($killmail) {
Detail::dispatch($killmail->killmail_id, $killmail->killmail_hash);
})->isEmpty() && empty($killmail_ids)) {
RefreshToken::with('character', 'affiliation', 'character.corporation_roles')->get()->each(function ($token) {
RecentCharacterKills::dispatch($token);
RefreshToken::chunk(100, function ($tokens) {
$tokens->each(function ($token) {
RecentCharacterKills::dispatch($token);
});
});

if ($token->character->corporation_roles->where('role', 'Director')->isNotEmpty())
RecentCorporationKills::dispatch($token->character->affiliation->corporation_id, $token);
RefreshToken::whereHas('character.affiliation', function ($query) {
$query->whereNotNull('corporation_id');
})->whereHas('character.corporation_roles', function ($query) {
$query->where('scope', 'roles');
$query->where('role', 'Director');
})->get()->unique('character.affiliation.corporation_id')->each(function ($token) {
RecentCorporationKills::dispatch($token->character->affiliation->corporation_id, $token);
});
}
}
Expand Down
20 changes: 14 additions & 6 deletions src/Commands/Esi/Update/PublicInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class PublicInfo extends Command
*/
public function handle()
{
// NPC stations
// NPC stations using HQ
CorporationInfo::whereNotIn('home_station_id', UniverseStation::FAKE_STATION_ID)
->select('home_station_id')
->orderBy('home_station_id')
Expand All @@ -73,7 +73,7 @@ public function handle()
Stations::dispatch($corporations->pluck('home_station_id')->toArray());
});

// corporation assets
// NPC stations using corporation assets
CorporationAsset::where('location_type', 'station')
->select('location_id')
->orderBy('location_id')
Expand All @@ -90,13 +90,21 @@ public function handle()
Insurances::dispatch();

CharacterInfo::doesntHave('refresh_token')->each(function ($character) {
CharacterInfoJob::dispatch($character->character_id);
CorporationHistory::dispatch($character->character_id);
CharacterInfoJob::withChain([
new CorporationHistory($character->character_id),
])->dispatch($character->character_id)->delay(rand(10, 120));
// in order to prevent ESI to receive massive income of all existing SeAT instances in the world
// add a bit of randomize when job can be processed - we use seconds here, so we have more flexibility
// https://github.com/eveseat/seat/issues/731
});

CorporationInfo::all()->each(function ($corporation) {
CorporationInfoJob::dispatch($corporation->corporation_id);
AllianceHistory::dispatch($corporation->corporation_id);
CorporationInfoJob::withChain([
new AllianceHistory($corporation->corporation_id),
])->dispatch($corporation->corporation_id)->delay(rand(120, 300));
// in order to prevent ESI to receive massive income of all existing SeAT instances in the world
// add a bit of randomize when job can be processed - we use seconds here, so we have more flexibility
// https://github.com/eveseat/seat/issues/731
});
}
}
Loading

0 comments on commit a5ae475

Please sign in to comment.