Files
SkinbaseNova/routes/console.php

136 lines
5.2 KiB
PHP

<?php
use Illuminate\Foundation\Inspiring;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Schedule;
use App\Uploads\Services\CleanupService;
Artisan::command('inspire', function () {
$this->comment(Inspiring::quote());
})->purpose('Display an inspiring quote');
Artisan::command('uploads:cleanup {--limit=100 : Maximum drafts to clean in one run}', function (): void {
$limit = (int) $this->option('limit');
$deleted = app(CleanupService::class)->cleanupStaleDrafts($limit);
$this->info("Uploads cleanup deleted {$deleted} draft(s).");
})->purpose('Delete stale draft uploads and temporary files');
// ── Scheduled tasks ────────────────────────────────────────────────────────────
// Recalculate trending scores every 30 minutes (staggered: 24h first, then 7d)
Schedule::command('skinbase:recalculate-trending --period=24h')
->everyThirtyMinutes()
->name('trending-24h')
->withoutOverlapping();
Schedule::command('skinbase:recalculate-trending --period=7d --skip-index')
->everyThirtyMinutes()
->name('trending-7d')
->runInBackground()
->withoutOverlapping();
// Reset windowed view/download counters so trending uses recent-activity data.
// Downloads are recomputed from the artwork_downloads log (accurate).
// Views are zeroed (no per-view event log) and re-accumulate from midnight.
Schedule::command('skinbase:reset-windowed-stats --period=24h')
->dailyAt('03:30')
->name('reset-windowed-stats-24h')
->withoutOverlapping();
Schedule::command('skinbase:reset-windowed-stats --period=7d')
->weeklyOn(1, '03:30') // Monday 03:30
->name('reset-windowed-stats-7d')
->withoutOverlapping();
// Daily maintenance
Schedule::command('uploads:cleanup')->dailyAt('03:00');
Schedule::command('analytics:aggregate-similar-artworks')->dailyAt('03:10');
Schedule::command('analytics:aggregate-feed')->dailyAt('03:20');
// Drain Redis artwork-stat delta queue so MySQL counters stay fresh.
// Run every 5 minutes with overlap protection.
Schedule::command('skinbase:flush-redis-stats')
->everyFiveMinutes()
->name('flush-redis-stats')
->withoutOverlapping();
// Prune artwork_view_events rows older than 90 days.
// Runs Sunday at 04:00, after all other weekly maintenance.
Schedule::command('skinbase:prune-view-events --days=90')
->weekly()
->sundays()
->at('04:00')
->name('prune-view-events')
->withoutOverlapping();
// ── Similar Artworks (Hybrid Recommender) ──────────────────────────────────────
// Build co-occurrence pairs from favourites every 4 hours.
Schedule::job(new \App\Jobs\RecBuildItemPairsFromFavouritesJob())
->everyFourHours()
->name('rec-build-item-pairs')
->withoutOverlapping();
// Nightly: recompute tag, behavior, and hybrid similarity lists.
Schedule::job(new \App\Jobs\RecComputeSimilarByTagsJob())
->dailyAt('02:00')
->name('rec-compute-tags')
->withoutOverlapping();
Schedule::job(new \App\Jobs\RecComputeSimilarByBehaviorJob())
->dailyAt('02:15')
->name('rec-compute-behavior')
->withoutOverlapping();
Schedule::job(new \App\Jobs\RecComputeSimilarHybridJob())
->dailyAt('02:30')
->name('rec-compute-hybrid')
->withoutOverlapping();
// ── Feed 2.0: Scheduled Posts ─────────────────────────────────────────────────
// Publish queued posts every minute.
Schedule::command('posts:publish-scheduled')
->everyMinute()
->name('publish-scheduled-posts')
->withoutOverlapping();
// ── Feed 2.0: Trending Cache Warm-up ─────────────────────────────────────────
// Warm the post trending cache every 2 minutes (complements the 2-min TTL).
Schedule::command('posts:warm-trending')
->everyTwoMinutes()
->name('warm-post-trending')
->withoutOverlapping();
// ── Ranking Engine V2 ──────────────────────────────────────────────────────────
// Recalculate ranking_score + engagement_velocity every 30 minutes.
// Also syncs V2 scores to rank_artwork_scores so list builds benefit.
Schedule::command('nova:recalculate-rankings --sync-rank-scores')
->everyThirtyMinutes()
->name('ranking-v2')
->withoutOverlapping()
->runInBackground();
Schedule::command('forum:ai-scan')
->everyTenMinutes()
->name('forum-ai-scan')
->withoutOverlapping()
->runInBackground();
Schedule::command('forum:bot-scan')
->everyFiveMinutes()
->name('forum-bot-scan')
->withoutOverlapping()
->runInBackground();
Schedule::command('forum:scan-posts --limit=250')
->everyFifteenMinutes()
->name('forum-post-scan')
->withoutOverlapping()
->runInBackground();
Schedule::command('forum:firewall-scan')
->everyFiveMinutes()
->name('forum-firewall-scan')
->withoutOverlapping()
->runInBackground();