added a help system, replaced the words "tenant" and "Pwa" with better alternatives. corrected and implemented cron jobs. prepared going live on a coolify-powered system.
This commit is contained in:
106
app/Console/Commands/DispatchStorageArchiveCommand.php
Normal file
106
app/Console/Commands/DispatchStorageArchiveCommand.php
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Console\Concerns\InteractsWithCacheLocks;
|
||||
use App\Jobs\ArchiveEventMediaAssets;
|
||||
use App\Models\Event;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Contracts\Cache\Lock;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class DispatchStorageArchiveCommand extends Command
|
||||
{
|
||||
use InteractsWithCacheLocks;
|
||||
|
||||
protected $signature = 'storage:archive-pending
|
||||
{--event= : Limit processing to a specific event ID}
|
||||
{--force : Run even if another dispatcher instance is active}';
|
||||
|
||||
protected $description = 'Queue archive jobs for events whose galleries expired or were manually archived.';
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
$lockSeconds = (int) config('storage-monitor.archive.lock_seconds', 1800);
|
||||
$lock = $this->acquireCommandLock('storage:archive-dispatcher', $lockSeconds, (bool) $this->option('force'));
|
||||
|
||||
if ($lock === false) {
|
||||
$this->warn('Another archive dispatcher run is already executing.');
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
$eventLockTtl = (int) config('storage-monitor.archive.event_lock_seconds', 3600);
|
||||
$graceDays = max(0, (int) config('storage-monitor.archive.grace_days', 3));
|
||||
$cutoff = now()->subDays($graceDays);
|
||||
$chunkSize = max(1, (int) config('storage-monitor.archive.chunk', 25));
|
||||
$maxDispatch = max(1, (int) config('storage-monitor.archive.max_dispatch', 100));
|
||||
$eventId = $this->option('event');
|
||||
$dispatched = 0;
|
||||
|
||||
try {
|
||||
$query = Event::query()
|
||||
->with('eventPackages:id,event_id,gallery_expires_at')
|
||||
->whereHas('mediaAssets', function ($builder) {
|
||||
$builder->where('status', '!=', 'archived');
|
||||
});
|
||||
|
||||
if ($eventId) {
|
||||
$query->whereKey($eventId);
|
||||
} else {
|
||||
$query->where(function ($builder) use ($cutoff) {
|
||||
$builder->where('status', 'archived')
|
||||
->orWhereHas('eventPackages', function ($packages) use ($cutoff) {
|
||||
$packages->whereNotNull('gallery_expires_at')
|
||||
->where('gallery_expires_at', '<=', $cutoff);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$query->chunkById($chunkSize, function ($events) use (&$dispatched, $maxDispatch, $eventLockTtl) {
|
||||
foreach ($events as $event) {
|
||||
if ($dispatched >= $maxDispatch) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$eventLock = $this->acquireCommandLock('storage:archive-event-'.$event->id, $eventLockTtl);
|
||||
if ($eventLock === false) {
|
||||
Log::channel('storage-jobs')->info('Archive dispatch skipped due to in-flight lock', [
|
||||
'event_id' => $event->id,
|
||||
]);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
ArchiveEventMediaAssets::dispatch($event->id);
|
||||
$dispatched++;
|
||||
|
||||
Log::channel('storage-jobs')->info('Archive job dispatched', [
|
||||
'event_id' => $event->id,
|
||||
'queue' => 'media-storage',
|
||||
]);
|
||||
} finally {
|
||||
if ($eventLock instanceof Lock) {
|
||||
$eventLock->release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
$this->info(sprintf('Dispatched %d archive job(s).', $dispatched));
|
||||
Log::channel('storage-jobs')->info('Archive dispatch run finished', [
|
||||
'dispatched' => $dispatched,
|
||||
'event_limit' => $eventId,
|
||||
]);
|
||||
|
||||
return self::SUCCESS;
|
||||
} finally {
|
||||
if ($lock instanceof Lock) {
|
||||
$lock->release();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user