Skip to content

Scheduler runs artisan schedule:run every 60s even when the app has no scheduled tasks, with no way to disable it #147

Description

@melvinmihaylovnulabg

What were you trying to do?

Ship a Laravel 13 + Filament 5 desktop app to users on low-end Windows machines, and account for everything the app does while idle.

The app schedules nothing — routes/console.php is untouched, there is no withSchedule() anywhere — but it still pays for the scheduler on every machine, for the whole session.

What happened?

NativePHP.bootstrap() calls startScheduler() unconditionally, which spawns a fresh php artisan schedule:run process every 60 seconds for the lifetime of the app:

Each tick is a new process, so an in-memory opcache never applies to it. It is a full Laravel boot, performed and discarded, 1440 times a day.

Measured on an Apple M3 Pro (macOS 26.6), with config:cache, route:cache and event:cache already applied — a machine far faster than the ones we ship to:

PHP files included per bootstrapped console kernel 1410
Wall time per artisan schedule:run ~240 ms (~190 ms user CPU)
Times per day 1440
Scheduled tasks in the app 0

(That file count is for our app — Laravel 13 + Filament 5. A vanilla app would be lower, but it is still a complete framework boot either way.)

On Windows this is worse in kind rather than just degree: every one of those file reads goes through Defender's real-time scanner, which is the mechanism identified as the root cause in #12. That issue is about the cost being paid on first load; this is the same cost paid again every single minute, in the background, on a machine the user believes is idle.

There is no way to turn it off. I grepped the whole package — no config key, no env var, no hook. The only route today is patching the vendored TypeScript, which is what we now do.

How to reproduce the bug

  1. Create a NativePHP desktop app with no scheduled tasks at all (a fresh install qualifies).
  2. php artisan native:run, or launch a built app.
  3. The console logs Running scheduler... every 60 seconds.
  4. A new php process appears in the process list on each of those ticks.

There is nothing to configure to stop it.

Debug Output

{
    "Environment": {
        "PHP": { "Version": "8.4.24" },
        "Laravel": { "Version": "13.29.0", "ConfigCached": false, "RoutesCached": false, "DebugEnabled": true },
        "Node": { "Version": "v20.19.0" },
        "NPM": { "Version": "10.8.2" },
        "OperatingSystem": "Darwin",
        "ElectronRoot": "vendor/nativephp/desktop/resources/electron"
    },
    "NativePHP": {
        "Versions": { "nativephp/desktop": "2.2.1.0", "nativephp/php-bin": "1.2.0.0" },
        "Configuration": {
            "Provider": "App\\Providers\\NativeAppServiceProvider",
            "BuildHooks": { "Pre": [], "Post": [] },
            "NotarizationEnabled": false,
            "AzureTrustedSigningEnabled": true,
            "CustomPHPBinary": false
        }
    }
}

Confirmed still present on main at 8ba6171 — the file has only had formatting changes since #69.

Which operating systems have you seen this occur on?

macOS, Windows

Notes

Two ways to fix it, and either works for us:

  1. A config toggle. Something like 'scheduler' => ['enabled' => env('NATIVEPHP_SCHEDULER_ENABLED', true)] in config/nativephp.php, checked before startScheduler(). Explicit, and nothing changes for anyone who does not set it.
  2. Detect it at boot. Run artisan schedule:list once at startup and skip the interval when it comes back empty. No config at all, but it would surprise an app that registers schedules conditionally at runtime — so (1) looks safer to me.

Happy to open a PR for whichever you would prefer.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions