mcfedr/periodic-queue-driver-bundle
Symfony bundle adding a periodic queue driver so queued jobs run on a fixed schedule through your existing queue. Set intervals per job, let workers pick up due tasks automatically, and avoid separate cron entries for recurring work.
This bundle is a plugin for mcfedr/queue-manager-bundle, not a standalone queue system. You cannot adopt it in isolation — get the base Queue Manager bundle installed, configured, and successfully running a job before you add this driver. If that foundation isn't already in your project, this is probably the wrong tool (see Gotchas).
Minimal steps:
composer require mcfedr/queue-manager-bundle
composer require mcfedr/periodic-queue-driver-bundle
app/AppKernel.php (this predates Symfony Flex, so there is no recipe — you must add it by hand, after the Queue Manager bundle):
new McFedr\QueueManagerBundle\McFedrQueueManagerBundle(),
new McFedr\PeriodicQueueDriverBundle\McFedrPeriodicQueueDriverBundle(),
app/config/config.yml). The exact key names are not documented; verify them against the bundle's DependencyInjection/Configuration.php before trusting any example, including this one:
mcfedr_queue_manager:
driver: periodic # name must match the service the bundle registers
bin/console cache:clear && bin/console debug:container | grep -i periodic.Where to look first: the bundle is tiny, so read it top to bottom in this order — DependencyInjection/ (what config keys and service ids it actually exposes), then the class implementing the Queue Manager driver interface (that's the whole feature), then Resources/config/services.yml. There is no meaningful README coverage of configuration, so the source is the documentation.
First use case: a recurring housekeeping or polling task — e.g. "check an external API every five minutes and enqueue a follow-up job", or "send a digest every hour". Instead of scheduling that in cron and booting a full Symfony kernel each time, you run one long-lived consumer process and let the driver tick jobs on its interval.
Treat it as an in-process scheduler, not a message queue. The driver's value is that it decouples when a job fires from what the job does: your job classes stay plain services, and the timing lives in configuration. The canonical pattern is a single supervised console process:
# supervisor / systemd, numprocs=1
bin/console mcfedr:queue:run --env=prod -vv
Keep job classes small, idempotent, and time-bounded. Since jobs fire on a wall-clock interval inside a resident process, a job that takes longer than its period will either overlap or silently shift the schedule. Design every job to be safe to run twice (upserts, INSERT ... ON DUPLICATE KEY, "last run" markers) and to bail out early if it detects a previous run still in flight.
One driver configuration per concern. If the bundle lets you register multiple periodic driver instances (check the extension), give slow pollers and fast pollers separate processes so a slow job can't starve a fast one. If it only supports one, put the lowest-frequency job in this driver and push everything else to a normal worker queue.
Pair every job with an "enqueue" path. The strongest pattern is: the periodic job produces work onto a regular Queue Manager queue, and normal workers consume it. That way the periodic process stays short-lived and cheap, and you get retries, backoff, and failure isolation from the standard worker infrastructure instead of implementing them yourself.
Testing. Unit-test the job services directly — they should be constructible with mocks and callable from a test. For integration, bound the runtime: run the consumer command with whatever time-limit / single-run flag the base bundle offers (typically --time-limit or --max-jobs) inside a test, assert side effects, then kill it. Never let a periodic consumer run unbounded in CI.
Logging. Route Queue Manager's logger channel to its own handler in Monolog, and log at the start and end of every job with a correlation id. In a resident process, unlabelled log lines become impossible to attribute once two jobs interleave.
AppKernel-era constraints), no Flex recipe, no PHP 8 compatibility, and no one to answer questions on Stack Overflow. Budget for either pinning the whole app to an old Symfony or forking the bundle.bin/console debug:config mcfedr_queue_manager (if available on your Symfony version) and debug:container --show-private to confirm the driver service id and its tags. Guessing key names is the #1 time sink here.numprocs > 1, or a forgotten & in a shell, will double-run every job. Use numprocs=1 and, defensively, a flock or advisory lock inside the job itself.$em->clear() after each tick to prevent the identity map from growing unbounded. Catch \Exception inside the job and log it — an uncaught throwable may otherwise take down the whole consumer, so make the outer loop's error handling explicit rather than assumed.kill -TERM <pid> while a job is running and confirm the process exits cleanly.symfony/scheduler (or plain cron + a console command) — both are maintained, documented, and supported. If you're only here because you inherited this bundle, the practical move is to reimplement the one or two periodic jobs as commands and delete the dependency; the surface area is small enough that this is usually a day's work and removes an abandonment risk from your stack.How can I help you explore Laravel packages today?