HEX
Server: LiteSpeed
System: Linux s1049.use1.mysecurecloudhost.com 4.18.0-477.27.2.lve.el8.x86_64 #1 SMP Wed Oct 11 12:32:56 UTC 2023 x86_64
User: xedaptot (3356)
PHP: 8.3.31
Disabled: NONE
Upload Files
File: /home/xedaptot/ai.naniguide.com/app/Jobs/Ads/RefreshAdPlatformTokens.php
<?php

namespace App\Jobs\Ads;

use App\Model\AdPlatform;
use App\Services\Ads\AdActivityLogger;
use App\Services\Ads\AdPlatformManager;
use Illuminate\Support\Facades\Log;
use Throwable;

/**
 * Scheduled job to refresh ad platform tokens proactively.
 * Runs every 30 minutes. Refreshes tokens expiring within 24 hours.
 *
 * Platform-specific refresh timing:
 * - Meta: tokens last 60 days, no refresh (re-auth required)
 * - Google: refresh anytime via refresh_token
 * - TikTok: tokens last 24h, refresh proactively every ~20h
 * - LinkedIn: tokens last 60 days, refresh when <7 days remaining
 */
class RefreshAdPlatformTokens extends AbstractAdsJob
{
    public function __construct()
    {
        parent::__construct();
        // Override: batch job should not retry — each platform refresh has its
        // own error handling via AdPlatformManager::refreshIfExpired().
        $this->tries = 1;
        $this->timeout = 120;
    }

    public function handle(AdPlatformManager $manager): void
    {
        $platforms = AdPlatform::active()
            ->whereNotNull('token_expires_at')
            ->where('token_expires_at', '<=', now()->addDay()) // Expiring within 24h
            ->whereNotNull('refresh_token')
            ->get();

        foreach ($platforms as $platform) {
            try {
                $manager->refreshIfExpired($platform);
            } catch (\Throwable $e) {
                // Individual platform errors are already logged by the manager.
                // Just log at job level for debugging.
                Log::warning('RefreshAdPlatformTokens: failed for platform ' . $platform->uid, [
                    'platform' => $platform->platform,
                    'error' => $e->getMessage(),
                ]);
            }
        }

        // Also check for expiring tokens that need user notification (7-day warning)
        $expiringPlatforms = AdPlatform::active()
            ->whereNotNull('token_expires_at')
            ->where('token_expires_at', '<=', now()->addDays(7))
            ->where('token_expires_at', '>', now()->addDay())
            ->get();

        foreach ($expiringPlatforms as $platform) {
            // Only log warning once per day (check if we already logged today)
            $alreadyWarned = $platform->activityLogs()
                ->where('action', 'platform.token_expiring')
                ->where('created_at', '>=', now()->startOfDay())
                ->exists();

            if (!$alreadyWarned) {
                $daysLeft = now()->diffInDays($platform->token_expires_at);

                AdActivityLogger::log(
                    entity: $platform,
                    action: 'platform.token_expiring',
                    status: 'warning',
                    title: $platform->platform_label . " token expires in {$daysLeft} days",
                    description: "Token will expire on " . $platform->token_expires_at->format('Y-m-d H:i') . ". Reconnect to avoid disruption.",
                    resolutionHint: "Go to Ads > Platforms and click 'Reconnect' on " . $platform->platform_label . " before it expires.",
                    platform: $platform->platform,
                );
            }
        }
    }

    public function failed(Throwable $e): void
    {
        $this->logFailure($e);
    }
}