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

Workflow Engine Core Laravel Package

solution-forest/workflow-engine-core

A framework-agnostic PHP 8.3+ workflow engine for defining, executing, and tracking workflows with state management, retries, timeouts, and conditions. Extensible and type-safe, with no framework dependencies.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Release reviewed: v2.0.0 (breaking; follows v1.0.0 by hours). Net verdict: the risk profile improved materially, but the integration plan changes — two prior blockers were cleared (no out-of-box storage adapter; resume() unusable on failure), one prior "strength" was downgraded (condition/state rigor was not actually enforced), and the timeout/retry gap is now confirmed permanent rather than pending.

Architecture Fit

  • Strengths:

    • Runs out of the box: Storage\InMemoryStorage now ships in the package (previously in tests/ under autoload-dev, so the library could not execute a workflow on install). This removes a real adoption blocker and makes the pilot phase single-day rather than single-sprint.
    • Condition engine is now real: boolean operators, parentheses, negated groups, and parse-time rejection of malformed expressions. This is a genuine capability upgrade — the previous evaluator silently string-compared and returned true for a 500-dollar order against 'order.total > 1000 && order.vip === true'.
    • Recoverable failure: FAILED is no longer terminal; FAILED → RUNNING is legal and resume() retries the failed step. This aligns far better with human-in-the-loop and remediation flows than an immutable failed state.
    • Blocked ≠ running: unmet prerequisites now park in WAITING, distinguishable from an executing workflow. This is an operational-correctness win, not a cosmetic one.
    • Event system and plugin/action extensibility: unchanged and still the right seam for Laravel Event, Queue, and Mail.
    • Honest documentation: built-in actions table corrected, and the docs no longer claim retries/timeouts the engine does not perform.
  • Challenges (revised):

    • Timeout and retry are not "unimplemented but planned" — they are out of scope. The release explicitly removed documentation claiming retries/timeouts. Treat both as work we own, not work we wait for.
    • Silent-success was a systemic defect class, not a one-off: wrong compound-condition branch, dropped multi-root branch reported as completed at 66.67%, resume() masking its own error, start() overwriting an existing instance, DelayAction(hours: 2) pausing one second. All are fixed with regression coverage, but the pattern tells us engine-reported status cannot be trusted as a business-outcome signal without our own assertions.
    • API instability: two majors in one day. Semver is being applied correctly, but the cadence signals a pre-stabilisation API. Pin exact tags.
    • Breaking surface for us: EmailAction → FakeEmailAction, WorkflowBuilder::email() → fakeEmail(), ConditionAction drops on_true/on_false, condition grammar moves from =/is to ===/==/!=, and FAILED is no longer terminal.
    • Framework-agnostic claim: Support\Arr::has() is new, suggesting internal helper consolidation, but removal of data_get()/data_set() is not stated in the release notes. Verify before relying on any non-Laravel execution path.

Integration Feasibility

  • Laravel Compatibility:
    • High for core orchestration, now with a working in-memory adapter for local/dev/test.
    • Still ours to build: QueueExecutor/QueuedWorkflowExecutor, DatabaseStorageAdapter, a real mail action, and any timeout/retry middleware.
    • Runtime check required: HttpAction now reports missing ext-curl as a step failure rather than a fatal error — confirm curl is present in our base images so we fail cleanly rather than at step level.
  • Migration Path (add a Phase 0 before the prior plan):
    • Phase 0 — Breaking-change audit (2–3 days): grep for EmailAction, email(, on_true/on_false, and condition strings using =/is; identify handlers and dashboards that assert FAILED is terminal; identify any workflow whose passing result depended on the old silent string-comparison behaviour (these will now throw at parse time — desirable, but they surface as deploy-day failures).
    • Phase 1 — Pilot (now ~1 week, was 1–2): InMemoryStorage + SimpleWorkflow for sync, non-critical flows; replace data_get() if we need framework independence; add acceptance tests asserting business outcomes, not engine status.
    • Phase 2 — Production (2–4 weeks): DatabaseStorageAdapter, QueuedWorkflowExecutor, in-house timeout/retry middleware, WAITING-aware status mapping, Laravel Event wiring for failure notification.
    • Phase 3 — Optimisation: CacheStorageAdapter, real MailAction via Laravel Mail/Notification.
  • Compatibility:
    • Pros: green on PHP 8.3/8.4/8.5 (8.5 in matrix is useful runway); 161 tests / 363 assertions, regression coverage per fixed defect; Pint, PHPStan L6, composer validate --strict clean.
    • Cons: no stated Laravel-version compatibility matrix; Illuminate helper usage unresolved; breaking renames require a coordinated code change across our codebase.
  • Sequencing:
    1. Audit + pin exact tag (2.0.0, not ^2.0).
    2. Migrate breaking renames and condition grammar; re-run existing workflow definitions through the parser in CI to catch rejections early.
    3. Bind WorkflowEngine in a service provider; add InMemoryStorage for tests.
    4. DatabaseStorageAdapter → QueuedWorkflowExecutor.
    5. Timeout/retry middleware (ours), then observability (WorkflowFailedEvent → alerting), then WAITING-aware dashboards.

Technical Risk

  • Reduced risk (v2.0.0):
    • Silent wrong-branch conditions, dropped multi-root branches, misleading resume() errors, instance overwrite on start(), and mutual-reachability/cyclic definitions (now rejected at parse time) are all closed with tests.
    • Relational comparison against a missing key is now false (previously null → 0 made missing.key < 1000 true) — removes a class of false-positive approvals.
    • FakeEmailAction naming removes the worst kind of defect: an action that reported 'status' => 'sent' and sent nothing.
  • Residual risk (unchanged or new):
    • No timeout enforcement — hung workflows and stuck queue workers remain a production hazard we must bound externally (job timeouts, supervisor kill policies).
    • No retry semantics — transient HTTP/DB failures require our own wrapper; do not assume engine-level resilience.
    • CI history: PRs previously merged via dependabot auto-merge without the suite running against the merge result. Now fixed, but it explains how the v1.0.0 defects reached a stable tag; weight early-adoption confidence accordingly.
    • FAILED is now mutable — any code, report, or alert asserting failed workflows are immutable will silently misreport.
    • DelayAction now actually sleeps the documented duration — a delay(hours: 2) that previously returned in one second now blocks for two hours. Any delay used inside a synchronous/web request path becomes a hang.
  • Mitigation: pin the tag; wrap the engine in an anti-corruption layer that maps engine status to our domain status; assert business outcomes in tests; enforce timeouts at the queue/job layer, not the engine.

Key Questions

  1. Do any of our definitions use compound conditions that previously evaluated true because of the string-comparison bug? (Impact: correct answers now — and previously green workflows will throw at parse time; plan a staged rollout.)
  2. Do we use EmailAction/email() anywhere, and what is our real mail path? (Impact: must implement a WorkflowAction on Laravel Mail.)
  3. Does anything assert FAILED is terminal (handlers, dashboards, alert rules)? (Impact: FAILED → RUNNING is now legal.)
  4. Do our status mappings and on-call runbooks handle WAITING? (Impact: unmapped state reads as stuck or as running.)
  5. Has data_get()/data_set() actually been replaced by Support\Arr? (Impact: determines whether we can ever run core outside Laravel.)
  6. Do we accept a vendor that shipped two majors in a day, and will we pin/fork? (Impact: maintenance budget and upgrade cadence.)
  7. Is ext-curl guaranteed in every runtime image? (Impact: step failures vs fatals.)
  8. Where do we enforce timeouts — queue worker limits, supervisor, or our own middleware?

Integration Approach

Stack Fit

Component Laravel Equivalent Strategy (post-2.0.0)
Storage Database, Cache, Redis InMemoryStorage ships for dev/test; build DatabaseStorageAdapter for prod
Async execution Queue Build QueuedWorkflowExecutor; bound timeouts at the job layer
Retry / timeout Queue retries, retry(), job $timeout Own it — engine explicitly does not perform these
Events Event / Broadcasting Dispatch on WAITING, FAILED, and FAILED → RUNNING recovery
Mail Mail / Notification Replace FakeEmailAction with a real action
Logging Log facade LaravelLoggerAdapter
Config config() / .env Bind engine in a service provider
Testing Pest, DatabaseMigrations InMemoryStorage for unit; DB adapter for integration; outcome assertions

Migration Path

  • Pilot (≈1 week): pin 2.0.0; execute the breaking-change audit; stand up InMemoryStorage; ship one non-critical sync workflow end to end with outcome assertions.
  • Production (2–4 weeks): DatabaseStorageAdapter; QueuedWorkflowExecutor; timeout/retry middleware; failure alerting via events; WAITING-aware operational views.
  • Optimisation (ongoing): cache-backed storage, native Laravel actions (NotifyAction), removal of any remaining Illuminate helper coupling.

Compatibility

  • Pros: PHP 8.3–8.5 verified; strict typing retained; Support\Arr suggests reduced framework coupling; SECURITY.md now provides a disclosure path for vendor risk review.
  • Cons: breaking renames and grammar change require coordinated edits; no published Laravel version support matrix; data_get() status unconfirmed.

Sequencing

  1. Pin tag + breaking-change audit (blocker to any deploy).
  2. Condition-grammar regression pass over all existing definitions in CI.
  3. Service provider binding + InMemoryStorage in test suite.
  4. DatabaseStorageAdapter.
  5. QueuedWorkflowExecutor + job-level timeout/retry.
  6. Event-based observability and WAITING handling.

Operational Impact

Maintenance

  • Pros: excellent changelog discipline — every breaking change ships with a migration row; regression tests added per defect; CI now runs on PRs and the merge result, closing the gap that let v1.0.0 ship unstable.
  • Cons: high release cadence (two majors in a day) means upgrade work is recurring, not one-off; custom adapters (queue, database, mail, timeout/retry) remain our maintenance burden; no upstream commitment to retry/timeout.

Support

  • Strengths: WAITING gives support a truthful "blocked on prerequisite" signal; getStatusSummary() plus rich events support triage; FakeEmailAction removes a class of "we told the user it was sent" incidents; SECURITY.md gives a defined disclosure path.
  • Challenges: FAILED being recoverable means support scripts and runbooks must change; failures previously hidden by the engine's own error handler now surface (good, but expect a transient ticket bump during rollout); no Laravel integration guides upstream.

Scaling

  • Synchronous InMemoryStorage remains fine for admin/CLI paths only; durable throughput still requires our DatabaseStorageAdapter + QueuedWorkflowExecutor.
  • Without engine timeouts, horizontal scaling is bounded by our queue worker timeout configuration — a hung step occupies a worker indefinitely.
  • DelayAction now genuinely sleeps; any long delay in a synchronous path is a scaling hazard and must move to queued execution.

Failure Modes

  • Largely closed: silent wrong-branch evaluation, dropped multi-root branches reported complete, resume masking the real cause, start() overwriting state/history, cycles accepted, missing-key comparisons coercing to true, delay silently collapsing to one second, missing ext-curl as a fatal.
  • Still open: hung workflows (no timeout), transient failures never retried, and any consumer that assumes FAILED is terminal or that only knows PENDING/RUNNING/COMPLETED.
  • New: DelayAction honouring real durations can block request threads; unmapped WAITING can read as "stuck" in monitoring.

Ramp-up

  • Faster than before: the package executes out of the box, so a single engineer can produce a working spike in hours.
  • Budget roughly one week for the breaking-change audit and migration (renames, condition grammar, FAILED semantics) before feature work.
  • Engineering the missing runtime guarantees (timeout, retry, queue executor, DB adapter, real mail) remains the dominant effort and should be scoped as our workstream, not a dependency on upstream.
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.
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log