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

Docker Jobs Bundle Laravel Package

ibra-akv/docker-jobs-bundle

Docker Jobs Bundle simplifies running containerized background jobs from PHP applications, letting you define and execute isolated Docker tasks, queue workers, and scheduled processes with minimal configuration.

View on GitHub
Deep Wiki
Context7

Getting Started

Reality check before you composer require: despite the GitHub description, this is a Symfony bundle, not a Laravel package. It ships a Bundle subclass and expects config/bundles.php, the Symfony DI container, and bin/console. Dropping it into a Laravel app will pull in symfony/http-kernel, symfony/dependency-injection, and friends, and you'll be wiring the container by hand. Realistically you have two viable paths:

  1. Standalone Symfony "job runner" app — a small Symfony skeleton whose only job is to accept dispatch calls (HTTP or Redis/DB queue) from your Laravel app and run the containers. Laravel stays clean; the bundle lives where it belongs.
  2. Framework-agnostic fallback — if you only want "run a container per job," a 60-line wrapper around symfony/process or the Docker SDK will be more predictable than an unmaintained 19-star bundle. Evaluate this seriously before committing.

If you're going with option 1, the minimal path:

composer require ibra-akv/docker-jobs-bundle
// config/bundles.php — add the bundle's FQCN the installer printed
return [
    // ...
    Ibra\DockerJobsBundle\DockerJobsBundle::class => ['all' => true],
];

Then, in order:

  • Look at DependencyInjection/Configuration.php first. That file is the source of truth for every YAML key — the README for a bundle this size is usually thinner than the config tree. Generate a reference with bin/console config:dump-reference <alias> and bin/console debug:config <alias>.
  • Scan Command/. Bundles of this shape almost always expose a console command (a worker/consumer). bin/console list | grep -i docker tells you the entrypoint in five seconds.
  • Check composer.json require constraints. Last release was 2022-08-21; expect php: ^7.4|^8.0 and Symfony 5.x/6.0 ceilings. On PHP 8.3 / Symfony 7 you will likely need --ignore-platform-reqs and a fork.
  • Verify Docker access. The bundle needs the daemon socket (/var/run/docker.sock) or a DOCKER_HOST. Test outside the bundle first: docker run --rm hello-world.

First use case: pick one job with zero shared state — "render a PDF report," "transcode an upload," "run a scraper" — where the container takes an input path/env var and writes an output. Skip anything that needs to talk back to your Laravel DB mid-run. Get one job green end-to-end before defining a second job type; the failure modes (socket perms, networking, log capture) are all in the plumbing, not the job code.

Implementation Patterns

One image per job type, not one image for everything. The bundle's value is isolation: a Python scraper, a Node renderer, and a PHP worker should be three images. Tag them immutably (registry/app-report:2024-11-01-a) rather than :latest — a rolling tag makes a "works on my machine" bug into a "worked yesterday" bug.

Dispatch-and-poll is the default shape. The typical flow:

// Symfony side
$jobId = $this->jobDispatcher->dispatch('report', [
    'input'  => '/data/in/42.csv',
    'format' => 'pdf',
]);
// persist $jobId somewhere the caller can read

Then expose a status endpoint the Laravel app polls. Don't block the HTTP request waiting for the container — even a 10-second job will blow past PHP-FPM timeouts and tie up a worker.

Keep a worker alive under a supervisor. If the bundle provides a consume/run command, it belongs in systemd or Supervisor, not cron:

[program:docker-jobs]
command=php /app/bin/console docker-jobs:consume --time-limit=3600
autostart=true
autorestart=true
numprocs=2
stopwaitsecs=300

Add --time-limit (or the bundle's equivalent) so the worker recycles — long-lived PHP processes leak memory, and a worker that dies silently is the single most common cause of "jobs stopped processing."

Move data via a shared volume or object store, never bind-mount host paths in production. In dev, -v $(pwd)/var/jobs:/data is fine. In prod, bind mounts couple the container to a specific host and break the moment you scale. Use S3/GCS or a named volume the worker and the job container both see.

Network to the app explicitly. localhost inside the container is the container, not your host. Use host.docker.internal (Docker Desktop) or a shared user-defined bridge network with service names on Linux:

services:
  jobs-worker:
    networks: [appnet]
  report-job:
    networks: [appnet]   # reaches "db" and "redis" by name
networks:
  appnet:
    external: true

Treat jobs as idempotent and retryable. Containers get OOM-killed and nodes get drained. Design the handler so a duplicate run overwrites rather than appends, and carry a job_id into the container as an env var so its logs are greppable across the Docker daemon and your app.

Test by faking the dispatcher. Unit tests should never touch the Docker socket. Bind a fake/in-memory implementation of the dispatch interface in config/services_test.yaml and assert on the payload. Reserve real-container tests for one or two smoke tests in CI, and gate them behind an env check so they skip on laptops.

Gotchas and Tips

This is effectively unmaintained. 19 stars, 0 dependents, no release since August 2022. That means: pin the exact version in composer.json, commit composer.lock, and budget for a fork. Before adopting, read the issue tracker for unanswered PHP 8.1+ / Symfony 6 deprecation reports — those are the ones that will bite during a framework upgrade. If you fork, keep the fork under your org namespace so composer update doesn't silently swap it back.

Mounting /var/run/docker.sock is root on the host. Any code path that can influence the container spec (image name, volume mounts, env vars) is remote code execution as root. Never interpolate user input into an image name or volume path. If that's unacceptable, point the bundle at a rootless Docker daemon or a socket proxy (e.g. Tecnativa's docker-socket-proxy) and restrict the API surface.

Container leaks are the #1 operational problem. A crashed worker leaves orphaned containers and volumes. Always pass --rm (or the bundle's auto-remove flag), label every container (app=jobs, job_id=...), and run a nightly reaper:

docker ps -aq --filter "label=app=jobs" --filter "status=exited" | xargs -r docker rm

Exit codes carry the diagnosis. Don't collapse them into "job failed":

  • 0 success
  • 1 application error (the container ran and chose to fail)
  • 125 the Docker daemon itself rejected the run — bad flags, missing image
  • 126/127 entrypoint not executable / command not found — almost always a bad CMD or missing shebang
  • 137 SIGKILL — OOM. Check docker inspect <id> --format '{{.State.OOMKilled}}' and raise the memory limit
  • 143 SIGTERM — timeout or shutdown; make sure your handler traps it and flushes partial output

Log the raw exit code and the last 100 lines of container output on every failure, or you'll be debugging blind.

Capture stdout/stderr or lose it. Container logs vanish when the container is removed. Either attach to the stream and pipe into your app's logger, or docker logs <id> before the cleanup step. The bundle may or may not do this — verify with a job that deliberately writes to stderr.

Symfony prod config caching hides YAML mistakes. After editing the bundle config, run bin/console cache:clear and bin/console debug:config <alias> — otherwise you'll chase a stale cache for an hour. In Docker images, bake the cache warmup into the build stage, not container start.

Check the bundle's service IDs before decorating. The intended extension points are almost always (a) replacing the job handler via a tagged service or (b) subscribing to dispatch/complete events. bin/console debug:container --tag=<bundle-tag> and debug:event-dispatcher will show you what's actually wired — faster than reading the source. Decorate rather than edit: services.yaml with decorates: <service_id> keeps you upgrade-safe.

Timezone and locale drift. The job container's clock and locale are not your app's. Pass TZ and LANG explicitly, and always store timestamps in UTC on both sides. A date() in a container defaulting to UTC versus an app on Europe/Paris produces off-by-one-day bugs in reports that nobody notices for weeks.

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.
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core