Brand stats part 1 Create and schedule brand stats

This commit is contained in:
Jérémy Munsch 2021-10-29 12:53:46 +02:00
parent 8938dc4201
commit 6bd00e78d6
No known key found for this signature in database
GPG key ID: 55196BEE445F6049
6 changed files with 221 additions and 0 deletions

View file

@ -0,0 +1,35 @@
<?php
namespace App\Console\Commands;
use App\Jobs\StartStatJobs as JobsStartStatJobs;
use Illuminate\Console\Command;
class StartStatJobs extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'stats:collect';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Force push the collect stats jobs into the queue (stats)';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
\dispatch(new JobsStartStatJobs())->afterResponse();
return 0;
}
}

View file

@ -2,6 +2,7 @@
namespace App\Console;
use App\Jobs\StartStatJobs;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
@ -23,6 +24,8 @@ class Kernel extends ConsoleKernel
*/
protected function schedule(Schedule $schedule)
{
// stats job on night
$schedule->job(StartStatJobs::class)->dailyAt('03:30');
}
/**

View file

@ -0,0 +1,17 @@
<?php
namespace App\Jobs;
use App\Models\Brand;
class StartStatJobs
{
public function handle()
{
$brands = Brand::all();
foreach ($brands as $brand) {
\dispatch(new StatJob($brand))->onQueue('stats')->delay(rand(0, 90));
}
}
}

78
app/Jobs/StatJob.php Normal file
View file

@ -0,0 +1,78 @@
<?php
namespace App\Jobs;
use App\Models\Brand;
use App\Models\BrandStat;
use App\Models\CustomerInfo;
use App\Models\CustomerLogin;
use App\Models\SingleOptin;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\Middleware\WithoutOverlapping;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Carbon;
class StatJob implements ShouldQueue
{
use Dispatchable;
use InteractsWithQueue;
use Queueable;
use SerializesModels;
// Set high max tries as using prevent overlap
public $tries = 10;
/** Used to prevent overlaping */
private const JOBKEY = 32644296;
/** @var \App\Models\Brand */
private $brand;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct(Brand $brand)
{
$this->brand = $brand;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
$stats = new BrandStat([
'active' => CustomerLogin::whereBrandId($this->brand->id)
->whereDate('last_connection', '<', Carbon::now()->subMonths(6))->count(),
'inactive' => CustomerLogin::whereBrandId($this->brand->id)
->whereDate('last_connection', '>', Carbon::now()->subMonths(6))->count(),
'new_accounts' => CustomerLogin::whereBrandId($this->brand->id)
->whereDate('created_at', '<', Carbon::now()->subMonths(6))->count(),
'old_accounts' => CustomerLogin::whereBrandId($this->brand->id)
->whereDate('created_at', '>', Carbon::now()->subMonths(6))->count(),
'total_accounts' => CustomerLogin::whereBrandId($this->brand->id)->count(),
'total_opt_in' => CustomerInfo::whereBrandId($this->brand->id)
->whereOptIn(true)->count() + SingleOptin::whereBrandId($this->brand->id)->count()
]);
$stats->brand()->associate($this->brand);
$stats->saveOrFail();
}
/**
* Get the middleware the job should pass through.
*
* @return array
*/
public function middleware()
{
// dispatch randomly overlaping jobs if overlapping
return [(new WithoutOverlapping(self::JOBKEY))->releaseAfter(rand(20, 90))];
}
}

36
app/Models/BrandStat.php Normal file
View file

@ -0,0 +1,36 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Carbon;
class BrandStat extends Model
{
use HasFactory;
public $timestamps = false;
public $casts = [
'created_at' => 'date'
];
protected $fillable = [
'active', 'inactive',
'old_accounts', 'new_accounts',
'total_accounts', 'total_opt_in'
];
protected static function booted()
{
static::creating(function (BrandStat $stat) {
$stat->created_at = Carbon::now();
});
}
public function brand()
{
return $this->belongsTo(Brand::class);
}
}

View file

@ -0,0 +1,52 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateBrandStatsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('brand_stats', function (Blueprint $table) {
// Le nombre de comptes actifs (dernière connexion inférieure à 6 mois)
$table->unsignedInteger('active');
// Le nombre de comptes inactifs (dernière connexion supérieure à 6 mois)
$table->unsignedInteger('inactive');
// Le nombre d’anciens comptes (date de création supérieure à 6 mois
$table->unsignedInteger('old_accounts');
// Le nombre de nouveaux comptes (date de création inférieure à 6 mois)
$table->unsignedInteger('new_accounts');
// Le nombre de comptes total
$table->unsignedInteger('total_accounts');
// Le nombre d’optins (single optin compris)
$table->unsignedInteger('total_opt_in');
$table->timestamp('created_at')->nullable();
$table->foreignId('brand_id')->constrained('brands');
$table->index(['brand_id', 'created_at']);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('brand_stats');
}
}