Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Sansdaemon Laravel Package

arxeiss/sansdaemon

Sansdaemon lets Laravel apps process queued jobs without a long-running worker daemon. Trigger the worker from cron or the scheduler instead of Supervisor, making queue processing simpler on shared hosting and small deployments.

View on GitHub
Deep Wiki
Context7

Getting Started

arxeiss/sansdaemon solves a narrow, real problem: running Laravel queue workers on hosts where you cannot keep a long-lived queue:work process alive (no Supervisor, no systemd, shared hosting, small single-box deployments). Instead of a daemon, the package gives you an artisan command that drains the queue and exits, so it can be driven by the scheduler / cron.

Minimal path to a first working setup:

  1. composer require arxeiss/sansdaemon
  2. Publish the config (php artisan vendor:publish --tag=sansdaemon-config or the tag listed in the README — check the README, tags vary by version).
  3. Add the worker command to your scheduler in routes/console.php / app/Console/Kernel.php:
Schedule::command('sansdaemon:work')
    ->everyMinute()
    ->withoutOverlapping()
    ->runInBackground();
  1. Make sure the host actually runs php artisan schedule:run every minute (cron entry or Schedule::command('schedule:run')->everyMinute() equivalent on the platform).
  2. Dispatch a trivial job and confirm it is processed within ~60s.

Where to look first: the package's console command signature (php artisan list | grep -i sans) and the published config file. Those two tell you the connection/queue selection options, the max-runtime knob, and whether it wraps queue:work --stop-when-empty or implements its own loop. Read those before the README, which is thin.

First real use case: a low-to-moderate volume app (mail, webhooks, PDF generation a few thousand times a day) on a single box, where a per-minute drain is indistinguishable from a daemon but survives deploys and OOM kills without Supervisor babysitting.

Implementation Patterns

Scheduler-driven drain (the default pattern). One scheduled entry per queue/connection you care about. Keep withoutOverlapping() always — a slow drain plus a one-minute cron is exactly how you get two workers on the same queue and duplicated side effects on non-idempotent jobs.

Schedule::command('sansdaemon:work --queue=default')
    ->everyMinute()->withoutOverlapping()->runInBackground();

Schedule::command('sansdaemon:work --queue=emails,webhooks')
    ->everyMinute()->withoutOverlapping(10)->runInBackground();

Multi-queue priority. Pass a comma-separated queue list so low-priority work (reports) only runs after high-priority work (password resets) is drained. Order is priority order; it is not round-robin.

Environment split. Typical pattern is daemon-less in staging/shared hosting, real queue:work under Supervisor in production:

if (app()->environment('production') === false) {
    Schedule::command('sansdaemon:work')->everyMinute()->withoutOverlapping();
}

Keep the condition explicit rather than hiding it in config, so nobody wonders why production queues behave differently.

Deploy integration. Short-lived workers pick up new code on the next tick automatically — you do not need queue:restart for these. Do keep php artisan config:cache/route:cache out of a half-deployed state, and avoid long-running jobs that straddle a deploy. If you do also run a Supervisor daemon, queue:restart is still required for that one.

Bounding the run. Treat the scheduler interval as your hard budget. If ticks are every 60s, configure the worker's max runtime to ~50s (config key or --max-time, whatever the command exposes) so a backlog cannot cause overlapping invocations that withoutOverlapping will then silently skip.

Pairing with onOneServer() when you have more than one app server: without it, every box drains the same queue. Either use onOneServer() (needs a shared cache driver — Redis/database, not array/file) or run the worker on exactly one designated host.

Local dev. Don't schedule it locally; just run the command in a terminal loop while developing so you see output immediately. Reserve the scheduled form for environments that mimic production cron.

Gotchas and Tips

  • Latency floor is your cron interval. A one-minute schedule means up to 60 seconds of queue latency. For user-facing notifications that's often unacceptable. Lower the interval only if the platform allows it, and remember each tick boots the full framework — at 10s intervals on a busy box you are paying real bootstrap overhead per tick.
  • Long jobs and --max-time/timeout collide. A job that runs longer than the worker budget gets terminated mid-flight; depending on the timeout configuration it is released back and retried, which can look like a duplicate or a mystery MaxAttemptsExceededException. Set $timeout on the job and keep it comfortably under the worker budget, and prefer chunked/self-requeueing jobs over monoliths.
  • --stop-when-empty semantics. If the command wraps this flag, a burst that arrives one second after the worker exits waits a full interval. That is expected, not a bug — but it makes the tool unsuitable for latency-sensitive pipelines.
  • withoutOverlapping needs a cache lock that actually persists. With CACHE_STORE=array or a per-process store, the mutex is useless and you get concurrent drains. Same story for onOneServer(). Verify with Redis, database, or memcached.
  • Silent skipping. withoutOverlapping logs nothing by default when it skips. If queues appear "stuck," check whether the previous tick is still running (ps aux | grep sans) before assuming the package is broken.
  • runInBackground() requires proc_open. Disabled on some hardened shared hosts; the schedule will fail with an opaque error. Test the exact production PHP binary, not your local one, and remember the scheduler uses the PHP binary it was invoked with.
  • Working directory and env. Background scheduler tasks run from the app root with whatever env the cron user has. Config that reads $_ENV or shell variables can behave differently under cron than in an SSH session — always config:cache and read via config().
  • Duplicated side effects. Because the drain model retries aggressively at low intervals, idempotency matters more than with a daemon. Use ShouldBeUnique, WithoutOverlapping middleware, or database uniqueness constraints on jobs dispatched from user actions.
  • Debugging. Run the command synchronously in the foreground with -v; check storage/logs/laravel.log for the scheduler's own output, and remember background task output is not echoed to your terminal. php artisan schedule:list confirms the entry exists with the expected expression.
  • Extension points. Publish the config rather than editing vendor files; if you need custom behavior (multiple connections, pre-flight checks), subclass the command or write a thin wrapper command that calls it, so upgrades stay cheap. Config is cached — always php artisan config:clear after changes in non-production.
  • Version note (v1.3.2). This release only adds Laravel 13 support and a README badge — no breaking changes, no new behavior. If you are on Laravel 11/12, upgrading is a no-op; on Laravel 13 it removes the need for a --ignore-platform-req hack or a fork. Pin ^1.3.2 if you are moving to Laravel 13, and re-check the published config after minor bumps in case new keys were added (unpublished defaults still apply, but explicit config files drift).
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib