juststeveking/workflow
A Laravel package for defining and running workflows in your applications. Model states, transitions, and actions so complex multi-step processes stay organized and predictable, with a clean, testable API for managing every stage of the flow.
This is a 0.0.1 initial release, so treat the first hour as reconnaissance rather than integration. The package ships one capability — author workflow files and execute them — and that is exactly where to start.
"vendor/package": "0.0.1") rather than ^0.0.1. You want upgrades to be a deliberate act, not a composer update surprise in CI.mergeConfigFrom, publishes, and any commands([...]) call — those three lines define your entire integration surface.First real use case: pick one short, idempotent, non-critical internal job — a nightly cache warm, a data sync that already has a manual trigger, a report generator. Workflows are orchestrators; if step one fails you want a job where re-running is harmless and the blast radius is a log line.
Define workflows as versioned artifacts. Whatever the file format, keep workflow files in the repository under a dedicated directory and treat them as code: reviewed in PRs, covered by the same linting as the rest of the app. A workflow file that lives outside version control is a production incident waiting for a maintainer to retire.
Wrap execution in your own service, don't call the package directly. Create a thin WorkflowRunner (or similarly named) class that depends on the package's entry point and exposes only the two or three operations you actually use:
final class WorkflowRunner
{
public function __construct(private WorkflowManager $workflows) {}
public function run(string $name, array $context = []): WorkflowResult
{
return $this->workflows->run($name, $context);
}
}
This costs you twenty minutes now and buys you a single seam to patch when 0.0.2 renames a method. Bind the package's class to an interface in a service provider and inject the interface everywhere else.
Drive it from the scheduler, not from controllers. The natural Laravel integration for "run a workflow" is $schedule->command('workflow:run nightly-sync') in routes/console.php or Kernel::schedule(). Use withoutOverlapping() and onOneServer() — a workflow orchestrator invoked twice concurrently is a genuinely bad afternoon. If the package doesn't ship a run command, wrap the facade call in a custom artisan command; that's five lines and gives you scheduler, artisan tinker, and manual ops access for free.
Queue long workflows and keep the web request thin. If execution is synchronous, never trigger it from an HTTP request path. Dispatch a job:
dispatch(new RunWorkflowJob('invoice-export', $context));
Pass small context payloads — IDs, not Eloquent models — because anything the workflow serializes or logs may outlive the request. If the package supports queued steps internally, prefer that over queueing the whole workflow; you get per-step retry instead of all-or-nothing.
Make steps observable. Whatever logging channel the package uses, ensure each step emits something you can grep: a start line, an end line, and a failure line with the step name. If the package is silent, wrap each step's callable with your own timing/logging decorator. In a 0.0.1 release you should assume observability is your job.
Test by asserting on outcomes, not internals. Write feature tests that place a fixture workflow file in a temp directory, run it, and assert on the side effects (a row exists, a fake was called). Avoid asserting on the package's return object shape — that's the part most likely to change between 0.0.x releases.
Pin hard and audit every 0.0.x bump. Semver says nothing below 1.0 is stable, and maintainers of young packages use patch numbers for breaking changes routinely. Read the diff, not the changelog. Budget an hour per upgrade until 0.1.0.
File discovery will bite you first. Symptoms: "workflow not found" despite the file existing. Causes to check in order — wrong directory, case sensitivity (Linux CI vs macOS local), file extension mismatch, config cached. If you hit config:cache-related weirdness, php artisan config:clear should be your reflex, and make sure the workflow path is resolved at runtime rather than baked into a cached config value using base_path() in a way that survives deployment path changes.
Check the autoloader boundary. If workflow files are PHP that return closures or classes, they may need to be excluded from composer dump-autoload -o optimization or included in it — verify which, because an optimized autoloader in production can change behaviour versus local dev. If workflows are declarative (YAML/JSON), check for a schema or validation command and run it in CI.
Failure semantics are undefined in 0.0.1. Test explicitly: what happens when step 2 of 4 throws? Does the run halt, continue, roll back, or swallow the exception? Does the failure propagate to the caller or only to a log? Do not assume. Write a workflow with a deliberately failing step in a test and assert the behaviour, then document it in your own README, because you'll be the one explaining it at 3am.
No transaction guarantees between steps. Workflow orchestrators generally do not wrap steps in a DB transaction, and they shouldn't. Design steps to be idempotent and independently retryable. If you need compensation logic (undo step 1 when step 3 fails), you will have to build it yourself in this version.
Extension points to look for. In rough order of usefulness: a configurable storage/path, an injectable logger or event dispatcher, a way to register custom step types, and lifecycle events (WorkflowStarted, StepFailed). If the package fires events, hook them for alerting rather than forking the package. If it doesn't, that's your first feature request — and until then, wrap the runner.
Don't build critical infrastructure on 0.0.1. This is fine for internal tooling, reports, and scheduled maintenance. It is not yet the place for payment flows, customer-facing async operations, or anything with a compliance story. Revisit that judgment at 0.1.0 or when the package has a release with a documented upgrade path between versions — that, more than any feature, is the signal that it's safe to depend on.
How can I help you explore Laravel packages today?