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

Laravel Database Backup Laravel Package

jpbgomes/laravel-database-backup

A Laravel package for backing up your application database, with configurable storage destinations and Artisan commands you can schedule for automatic, recurring backups.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and confirm the version matrix first. v1.2.0 only widens the declared support window (Laravel 13 + Symfony Process 8, previous versions kept), so there is no migration work — but it is the moment to verify your own constraint set resolves cleanly:

composer require your-vendor/package:^1.2
composer why symfony/process
php artisan about

Check composer.lock afterwards: on PHP 8.4+ Composer will now happily pull symfony/process:^8.0, while a PHP 8.2/8.3 host stays on 7.x. Both are supported, but your CI matrix should exercise whichever one production actually resolves to (see Gotchas).

Where to look first, in order:

  1. config/<package>.php after php artisan vendor:publish --tag=<package>-config — timeout, working directory, binary paths, and any allow/deny list of runnable commands live here.
  2. The service provider — it tells you whether the runner is a singleton, how it's bound, and which facades/macros are registered.
  3. The result object returned by a run (exitCode(), output(), errorOutput(), successful()) — this is the object you will type-hint and assert against in 90% of your code.

First use case: replace an ad-hoc exec()/shell_exec() call with the package's runner so you get a typed result, a timeout, and a fakeable boundary for tests.

use YourVendor\Package\Facades\Process;

$result = Process::path(base_path())
    ->timeout(120)
    ->run(['php', 'artisan', 'migrate', '--force']);

if ($result->failed()) {
    report(new RuntimeException($result->errorOutput()));
}

Note the array form: passing an array bypasses the shell entirely, which is both the safer and the more portable option. Reach for a string command only when you genuinely need shell features (pipes, globbing, env expansion).

Implementation Patterns

Inject the runner, don't reach for the facade inside domain code. The facade is fine in Artisan commands, jobs, and controllers; anything you want to unit-test in isolation should take the manager via constructor injection (or a small RunsProcesses interface you bind in a service provider). That keeps the package swappable and lets you drop in a stub without touching Laravel's container.

Wrap every invocation in a value object. Long-lived codebases end up with dozens of process calls; centralising them means one place to change timeouts, binaries, and logging.

final class BackupDatabase
{
    public function __construct(private ProcessManager $process) {}

    public function __invoke(): ProcessResult
    {
        return $this->process
            ->path(config('backup.workdir'))
            ->env(['PGPASSWORD' => config('backup.password')])
            ->timeout(900)
            ->idleTimeout(60)   // kill if nothing is printed for 60s
            ->run(['pg_dump', '-Fc', '-f', $this->target()]);
    }
}

Stream output instead of buffering it. For long jobs (deploys, importers, npm ci) pass a callback so output goes to your log or a broadcast event as it arrives rather than sitting in memory until exit:

$result = Process::timeout(0)
    ->run($command, function (string $type, string $buffer) {
        Log::channel('deploy')->info($buffer);
    });

A timeout(0) disables the timeout entirely — acceptable only when something else (a queue worker's --timeout, Horizon's maxTime) is the real guard.

Push anything over a few seconds into a queued job. Combine with WithoutOverlapping middleware and a job-level timeout that is slightly larger than the process timeout, so the process is killed and its exit code recorded before the worker is SIGKILLed. Log both exit code and stderr on failure; a bare "job failed" is the most common debugging dead end with process execution.

Use the package's fake in tests and turn on stray-process prevention.

Process::fake([
    'php artisan migrate*' => Process::result(output: 'ok', exitCode: 0),
    '*' => Process::result(exitCode: 1, errorOutput: 'unexpected'),
]);

Process::preventStrayProcesses(); // fails the test on any unmatched call

preventStrayProcesses() is the highest-value line you can add: it stops a test from silently shelling out to a real git or rsync on a CI runner.

Integration tip — pair it with Laravel's scheduler and events. Emit a domain event when a result is failed(), and let a listener decide whether to retry, alert, or halt a pipeline. This keeps the calling code linear and testable.

Multi-step workflows: run steps sequentially, breaking out on the first failure, and pass state (artifacts, temp paths) between steps via a small context array rather than environment variables — env is inherited by children and is hard to reason about once you have three levels of nesting.

Gotchas and Tips

  • The v1.2.0 support declaration is a claim, not a guarantee of your runtime. Laravel 13 / Symfony Process 8 typically implies a newer PHP floor than 7.x did. Verify composer why symfony/process on the deployment image, not just locally; a dev machine on 8.4 and a container on 8.2 will resolve different majors, and Process 8 internals (options array shape, exception classes) can differ subtly from 7.x. Add a CI job pinned to each supported major if you support both.
  • proc_open can be disabled. Shared hosts and hardened php.ini files (disable_functions = proc_open,exec,shell_exec) break the package in a way that surfaces as a confusing exception at runtime, not at boot. Fail fast: assert availability in a health check or service provider boot on non-local environments.
  • PATH differs between FPM and CLI. node, git, and php resolve on your terminal and mysteriously 127 in a queued worker. Use absolute paths in config, or call PHP_BINARY for artisan invocations.
  • Exit code 0 with scary stderr is normal. Never treat non-empty errorOutput() as failure — check successful()/exitCode() first, and log stderr as context only.
  • Timeouts throw, they don't return. Catch ProcessTimedOutException (distinguishing general from idle timeouts); an uncaught one inside a job burns a retry you may not want.
  • Signal semantics differ on Windows. Anything relying on SIGTERM/SIGKILL, timeout semantics, or POSIX paths needs a Windows-skipped test or an explicit "not supported" note in your README.
  • Escape, or better, avoid the shell. If you must build a command string, run every interpolated fragment through escapeshellarg(); a user-supplied branch name in a git checkout string is a live injection vector.
  • Don't run interactive commands. Anything that prompts for input will hang until the timeout. Pass --no-interaction / -y flags everywhere, and set stdin to a closed or empty stream if the package exposes it.
  • Environment leakage: env([...]) in this package is typically additive to the inherited environment. If you need isolation, build the child env explicitly rather than assuming you've replaced it.
  • Extension points worth knowing: custom process factories and macros let you register your own preconfigured runners (Process::macro('forBackup', ...)) or swap the underlying Symfony Process subclass for one that pre-sets options. Bind them in a dedicated service provider rather than in AppServiceProvider.
  • Pin the minor for critical automation. Given a release whose only change is a support-window widening, keep composer.json at ^1.2 but commit the lockfile for deploy tooling; a silent major bump of symfony/process under you is the most likely way this package breaks a pipeline without a code change.
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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager