DEV Community

marius-ciclistu
marius-ciclistu

Posted on • Originally published at marius-ciclistu.Medium on

Dispatch to Queue After Commit In Maravel and Lumen


Maravel-Framework

While migrating a Lumen project to Maravel, I was under the impression that Lumen does not support dispatch to queue after commit. I was wrong. It did support it but, I was convinced by the community info that Lumen does not support it. Also I found a bug in Maravel-Framework that I patched in version 10.71.4 with this occasion.

I asked Gemini to summarize the investigation:

Stop Saying afterCommit Doesn’t Work in Maravel/Lumen: You’re Just Using it Wrong

There is a persistent myth in the PHP community that Maravel (and by extension, Lumen) is a “crippled” version of Maravelith (Laravel). One of the most cited “proofs” of this is the supposedly missing afterCommit() functionality for queued jobs.

I recently went on a deep-dive through the framework kernel with a collaborator to track down a supposed “bug” in the dispatcher. What we found wasn’t a broken feature — it was a masterclass in how understanding the PHP object lifecycle can make you a better engineer than any documentation ever could.

The Misconception: Syntactic Sugar vs. Core Logic

The standard Maravelith way to ensure a job only fires after a database transaction is to chain a method:

\dispatch($job)->afterCommit();
Enter fullscreen mode Exit fullscreen mode

In Maravel, this throws a fatal error. Why? Because the PendingDispatch wrapper in Maravel is stripped of that specific method.

The “Lumen is broken” crowd stops here. They see a missing method and conclude the feature doesn’t exist. They are wrong. They are confusing the Syntactic Sugar (the method call) with the Core Engine (the Dispatcher).

The Secret: The __destruct Handoff

If you open the Maravel kernel and look at Laravel\Lumen\Bus\PendingDispatch, you’ll see the exact same __destruct() method found in full-stack Maravelith. More or less is valid for Lumen/Laravel.

When you call dispatch($job), you aren't actually sending the job to the queue yet. You are creating a temporary object. When that object dies (the second the line of code ends), the __destruct() method fires. It takes your raw Job object and hands it to the core Dispatcher.

Here is the secret: The core Dispatcher in Maravel is just as smart as the one in Maravelith. It doesn’t need a wrapper method to tell it what to do. It reads your Job class directly.

If you know how to use the framework, you don’t chain the method:

\dispatch($job->afterCommit());

// or

class ProcessTransactionJob implements ShouldQueue
{
    // The core engine reads this directly during the __destruct handoff.
    public bool $afterCommit = true; 
}

// or for array callables from Maravel (Lumen does not have them)
new \Laravel\Lumen\Bus\PendingCallableDispatch(
    \Illuminate\Queue\CallQueuedCallable::create([Class::class, 'function'])->afterCommit()
)
Enter fullscreen mode Exit fullscreen mode

It doesn’t fail. It works perfectly. It always has.

The Professional Polish: Patch 10.71.4

While the afterCommit "issue" is actually just a know-how gap, our deep-dive did surface a real architectural leak in how the framework handles array callables and closures.

Even when you know how to use the dispatcher correctly, the Maravel kernel was still trying to reach out to the Illuminate\Foundation namespace for its PendingCallableDispatch logic—a toxic dependency for a decoupled microservice.

In Patch 10.71.4 , we surgically removed this. We introduced a local PendingCallableDispatch that:

  • Severed the Foundation Dependency: Keeping the microservice truly independent.
  • Strictly Typed Callbacks: By typing the catch() handler strictly to array, we enforced a unified paradigm that prevents closure serialization bloat and secures the queue against object injection vulnerabilities.
// The v10.71.4 Maravel Solution: Clean, local, and decoupled.
if (\is_array($job)) {
    return new \Laravel\Lumen\Bus\PendingCallableDispatch(
        \Illuminate\Queue\CallQueuedCallable::create($job)
    );
}
Enter fullscreen mode Exit fullscreen mode

The Verdict

Maravel isn’t “missing” features; it’s missing fluff.

The next time you hear a developer complain that a core Maravelith/Laravel feature “doesn’t work” in a microservice environment, remember: they are likely looking for a method that doesn’t exist to trigger a feature that does.

Stop trusting the magic, start reading the __destruct methods, and learn to talk to the engine directly.

Note

The Maravel documentation has been updated.

Same applies to delay and other methods.

Top comments (0)