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/routes/console.php
<?php

use Illuminate\Support\Facades\Schedule;

use App\Model\Automation2;
use App\Notifications\System\BackendErrorOccurred;
use App\Services\Notifications\Notifier;
use App\Cashier\Cashier;
use App\Model\Subscription;
use App\Model\Setting;
use App\Model\Campaign;
use App\Model\Customer;
use Laravel\Tinker\Console\TinkerCommand;
use App\Library\Facades\SubscriptionFacade;
use App\Helpers\LicenseHelper;

// Call \Artisan::call(...) in the application will exit(). tmp fixed
// if (isInitiated()) {
//     exit();
// }

if (isInitiated()) {
    // Make sure CLI process is NOT executed as root
    /*
    Notification::recordIfFails(function () {
        if (!exec_enabled()) {
            throw new Exception('The exec() function is missing or disabled on the hosting server');
        }

        if (exec('whoami') == 'root') {
            throw new Exception("Cronjob process is executed by 'root' which might cause permission issues. Make sure the cronjob process owner is the same as the acellemail/ folder's owner");
        }
    }, 'CronJob issue');

    // Make sure CLI process is NOT executed as root
    Notification::recordIfFails(function () {
        $minPHPRecommended = config('custom.php_recommended');

        if (!version_compare(PHP_VERSION, $minPHPRecommended, '>=')) {
            throw new Exception(trans('messages.requirement.php_version.not_supuported.description', ['current' => PHP_VERSION, 'required' => $minPHPRecommended]));
        }
    }, $phpMsgTitle = trans('messages.requirement.php_version.not_supuported.title'));
    */
    
    Schedule::call(function () {
        event(new \App\Events\CronJobExecuted());
    })->name('cronjob_event:log')->everyMinute();

    // Echo okie
    Schedule::command('automation:dispatch')->everyFiveMinutes();

    // Bounce/feedback handler
    Schedule::command('handler:run')->everyThirtyMinutes();

    // Sender verifying
    Schedule::command('sender:verify')->everyFiveMinutes();

    // System clean up
    Schedule::command('system:cleanup')->daily();

    // Re verify tracking domains
    // No longer verify tracking domains periodically, it might cause a bulk update that
    //     makes all schedule set back to "unverified" (network issue for example)
    // Schedule::command('tracking-domains:verify')->weekly()->sundays()->at('13:00');

    // GeoIp database check
    Schedule::command('geoip:check')->everyMinute()->withoutOverlapping(60);

    // Subscription: check expiration. On failure, mirror to the admin
    // shared inbox so it's visible alongside other system alerts. On
    // success the same group_key is cleared so the banner auto-clears.
    Schedule::call(function () {
        try {
            SubscriptionFacade::endExpiredSubscriptions();
            SubscriptionFacade::createRenewOrders();
            SubscriptionFacade::autoChargeRenewOrders();
            app(Notifier::class)->clearGroup('subscription-monitor');
        } catch (\Throwable $e) {
            \Log::warning('subscription:monitor failed', ['error' => $e->getMessage()]);
            app(Notifier::class)->shareWithAdmins(new BackendErrorOccurred($e));
        }
    })->name('subscription:monitor')->hourly()->withoutOverlapping(60);

    // // Remote subscription sync: primary mechanism to keep local ↔ remote in sync.
    // // Runs every 5 minutes, only syncs subscriptions not synced in the last hour.
    // // Webhooks are secondary — if they fail, this catches everything.
    // Schedule::command('remote:sync --all --scheduled')
    //     ->name('remote:sync')
    //     ->everyFiveMinutes()
    //     ->withoutOverlapping(10);

    // Check for scheduled campaign to execute
    Schedule::command('campaign:schedule')->everyMinute();

    // R7 — Ads pipeline maintenance.
    // Metrics pull runs every `ads.metrics_sync_interval` minutes (default 15).
    // Reconcile log sweep runs every `ads.reconcile_interval` minutes (default 5).
    // Both jobs are no-ops when the customer has no connected ad platforms,
    // and mock-mode installs still exercise the full pipeline against the
    // decorator chain so customers can verify their Horizon dashboards.
    Schedule::job(new App\Jobs\Ads\PullAdMetrics())
        ->name('ads:pull-metrics')
        ->cron('*/' . (int) config('ads.metrics_sync_interval', 15) . ' * * * *')
        ->withoutOverlapping(30);

    Schedule::job(new App\Jobs\Ads\ReconcileAdPublishLog())
        ->name('ads:reconcile-publish-logs')
        ->cron('*/' . (int) config('ads.reconcile_interval', 5) . ' * * * *')
        ->withoutOverlapping(10);

    // R11.4 — Ads retention prune. Runs daily at 03:00 to delete ad_leads /
    // ad_metrics / ad_activity_logs / ad_publish_logs rows older than the
    // configured TTL (`config/ads.php` retention.* — set 0 to disable).
    Schedule::command('ads:prune-retention')
        ->name('ads:prune-retention')
        ->dailyAt('03:00')
        ->withoutOverlapping(60);

    // R14 — A/B test winner detection. Hourly sweep over every running
    // test; writes one AdAbTestEvaluationLog row per test (always — that's
    // the audit trail), declares winner + auto-pauses losers when the
    // computed confidence meets the test's threshold.  Cadence is hourly
    // because metric pulls (PullAdMetrics) run every 15min, so an hourly
    // evaluator stays one full data refresh behind the freshest metrics.
    Schedule::job(new App\Jobs\Ads\EvaluateAdAbTests())
        ->name('ads:evaluate-ab-tests')
        ->hourly()
        ->withoutOverlapping(60);

    // R15.1 — Product catalog auto-sync sweep.  Daily fan-out: finds every
    // catalog bound to an ad_platform_id whose source supports auto-refresh
    // (anything except `manual`) and whose last_synced_at is older than
    // `ads.catalog.sweep_min_age_hours` (default 24h), then dispatches one
    // SyncAdProductCatalog job per row.  Sweeper is safe to run with all
    // R15 flags OFF — fan-out jobs do nothing when service guard rejects.
    Schedule::job(new App\Jobs\Ads\SweepProductCatalogSync())
        ->name('ads:sweep-catalog-sync')
        ->dailyAt('04:00')
        ->withoutOverlapping(60);

    $licenseTask = Schedule::call(function () {
        try {
            $license = LicenseHelper::getCurrentLicense();
            if (is_null($license)) {
                throw new Exception(trans('messages.license.error.no_license'));
            }
            LicenseHelper::refreshLicense();
            app(Notifier::class)->clearGroup('verify-license');
        } catch (\Throwable $e) {
            \Log::warning('verify_license failed', ['error' => $e->getMessage()]);
            app(Notifier::class)->shareWithAdmins(new BackendErrorOccurred($e));
        }
    })->name('verify_license');

    if (config('custom.japan')) {
        $licenseTask->everyMinute();
    } else {
        $licenseTask->weeklyOn(rand(1, 6), '10:'.rand(10, 59)); // randomly from Mon to Sat, at 10:10 - 10:59
    }

    // Rerun "sending" campaigns that are stuck for too long
    Schedule::command('campaign:rerun')->everyTenMinutes();

    // AI observability schedules (`ai:obs:retention` / `ai:obs:rollup-refresh`
    // / `ai:obs:classify-sentiment`) are registered by the acelle/ai
    // plugin's ServiceProvider — see `Acelle\Ai\ServiceProvider::registerSchedules()`.
    // When the plugin is removed the schedules disappear with it.

    // Launch more processes for priority campaigns
    Schedule::command('queue:adjust')->everyMinute();

    /*
    // Update list/user cache every 30 minutes
    // @important: potential performance issue here
    Schedule::call(function() {
        $customers = Customer::all();

        foreach($customers as $customer) {
            if (is_null($customer->getCurrentActiveSubscription())) {
                continue;
            }

            $lists = $customer->local()->lists;

            foreach ($lists as $list) {
                dispatch(new \App\Jobs\UpdateMailListJob($list));
            }
            dispatch(new \App\Jobs\UpdateUserJob($customer));
        }
    })->name('update_list_stats')->daily();
    */

    // Queued import/export/campaign
    // Allow overlapping: max 10 proccess as a given time (if cronjob interval is every minute)
    // Job is killed after timeout
    // Notice that the following queue must be exected on master (involved in local filesystem on the same web server)
    // + default
    // + import
    //
    if (!config('custom.distributed_worker')) {
        Schedule::command('queue:work --queue=import,default,high,batch,single,automation-dispatch,automation --tries=1 --max-time=180')->everyMinute();
    }
}