<?php
namespace App\Console\Commands;
use App\Jobs\CompileReportJob;
use Carbon\CarbonImmutable;
use Illuminate\Console\Command;
class GenerateWeeklyReport extends Command
{
protected $signature = 'report:weekly {--date= : Anchor date inside the target week (Y-m-d)}';
protected $description = 'Queue compilation of the weekly activity report';
public function handle(): int
{
$anchor = $this->option('date')
? CarbonImmutable::parse($this->option('date'))
: CarbonImmutable::now()->subWeek();
$start = $anchor->startOfWeek();
$end = $anchor->endOfWeek();
CompileReportJob::dispatch($start, $end);
$this->info(sprintf(
'Queued weekly report for %s - %s',
$start->toDateString(),
$end->toDateString()
));
return self::SUCCESS;
}
}
<?php
namespace App\Jobs;
use App\Mail\WeeklyReportMail;
use App\Services\ReportCompiler;
use Carbon\CarbonImmutable;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Throwable;
class CompileReportJob implements ShouldQueue, ShouldBeUnique
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public int $tries = 3;
public int $backoff = 60;
public int $uniqueFor = 3600;
public function __construct(
public CarbonImmutable $start,
public CarbonImmutable $end
) {
$this->onQueue('reports');
}
public function uniqueId(): string
{
return 'weekly-report:' . $this->start->toDateString();
}
public function handle(ReportCompiler $compiler): void
{
$report = $compiler->forRange($this->start, $this->end);
Mail::to(config('reports.recipients'))
->send(new WeeklyReportMail($report));
}
public function failed(Throwable $e): void
{
Log::error('Weekly report failed', [
'start' => $this->start->toDateString(),
'error' => $e->getMessage(),
]);
}
}
<?php
namespace App\Console;
use App\Console\Commands\GenerateWeeklyReport;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
protected function schedule(Schedule $schedule): void
{
$schedule->command('report:weekly')
->weeklyOn(1, '07:00')
->timezone('America/New_York')
->withoutOverlapping()
->onOneServer()
->runInBackground()
->emailOutputOnFailure(config('reports.ops_alert'));
}
protected function commands(): void
{
$this->load(__DIR__ . '/Commands');
require base_path('routes/console.php');
}
}
This snippet shows how a recurring report is wired up in Laravel: a custom Artisan command dispatches a queued job, and the scheduler in the console kernel decides when that command runs. The three tabs form one story — the command that is the entry point, the job that does the heavy lifting, and the kernel that schedules the command on a cron cadence.
In GenerateWeeklyReport command, the command is deliberately thin. Its handle() method resolves a date range from the --date option (defaulting to last week via a small helper) and then calls dispatch() on CompileReportJob. Keeping the command lightweight matters: Artisan commands run in a single foreground process, and doing report compilation inline would block the scheduler's schedule:run invocation and risk timeouts. By dispatching to a queue, the command returns almost immediately and the actual work happens in a worker. The command also writes to $this->info(...) so operators watching the scheduler log get feedback that the job was enqueued.
CompileReportJob is the queued unit of work. It implements ShouldQueue and pulls in Queueable/SerializesModels, so its constructor arguments ($start, $end) are serialized onto the queue and rehydrated in the worker. The $uniqueId() method combined with ShouldBeUnique is the key reliability detail: it prevents two overlapping reports for the same week from being processed at once, which protects against duplicate emails if the scheduler fires twice or a retry stacks up. $tries and $backoff give it bounded retries with a delay, and failed() logs the exception so a poisoned job is visible rather than silent.
Console Kernel ties it together. The schedule() method registers report:weekly with weeklyOn(1, '07:00') for Monday mornings, then chains guards that are easy to miss but important in production: timezone() pins the cron interpretation, withoutOverlapping() stops a slow run from colliding with the next tick, onOneServer() ensures only one node in a multi-server deployment fires it, and runInBackground() keeps schedule:run from blocking. A single system cron entry running schedule:run every minute is all that drives this. The trade-off is that correctness now depends on that cron plus a running queue worker, so the unique and overlap guards are what keep the pipeline from double-reporting when infrastructure hiccups.
Related snips
require "csv"
class PeopleCsvStream
include Enumerable
HEADERS = %w[id full_name email signed_up_at plan].freeze
Resilient CSV Export as a Streamed Response
<?php
namespace App\Providers;
use App\Contracts\PaymentGateway;
use App\Services\StripePaymentGateway;
Laravel service container and dependency injection
module EmailNormalization
extend ActiveSupport::Concern
included do
attr_accessor :soft_warnings
Soft Validation: Normalize + Validate Email
{
"private": true,
"scripts": {
"dev": "vite",
"build": "vite build"
},
Laravel mix/Vite for asset compilation
class CreateTopSellersMv < ActiveRecord::Migration[7.0]
def up
execute <<~SQL
CREATE MATERIALIZED VIEW top_sellers AS
SELECT p.id AS product_id,
p.name AS product_name,
Cache-Friendly “Top N” with Materialized View Refresh
class CreateDeadJobs < ActiveRecord::Migration[7.1]
def change
create_table :dead_jobs do |t|
t.string :jid, null: false
t.string :queue, null: false
t.string :klass, null: false
Background Job Dead Letter Queue (DLQ) Table
Share this code
Here's the card — post it anywhere.