›
›
›
  1. docs
  2. ›
  3. byrcsc/laravel-assignment
1.x
Browse documentationOpenClose

Getting started

  • Introduction
  • Installation and setup
  • Quick start

Core concepts

  • Assignments and slots
  • Assigning and offering
  • Selection policies
  • Scopes and rotation
  • Profiles
  • The queue
  • Offer cascades

Operations

  • Expiry and scheduling
  • Reading assignments
  • Notifications
  • Events and listeners
  • Concurrency guarantees

Reference

  • Configuration
  • API reference
  • Console commands
  • Exceptions
  • Testing
  • Troubleshooting

Getting started

  • Introduction
  • Installation and setup
  • Quick start

Core concepts

  • Assignments and slots
  • Assigning and offering
  • Selection policies
  • Scopes and rotation
  • Profiles
  • The queue
  • Offer cascades

Operations

  • Expiry and scheduling
  • Reading assignments
  • Notifications
  • Events and listeners
  • Concurrency guarantees

Reference

  • Configuration
  • API reference
  • Console commands
  • Exceptions
  • Testing
  • Troubleshooting

byrcsc/laravel-assignment · 1.x

Events and listeners.

Nine events cover every transition, and all of them wait for the surrounding transaction to commit.

Every transition dispatches an event. None of them ship with an application listener, so nothing happens until you add one. Anything the package deliberately leaves out, a manager alert, a dashboard, an escalation, is a listener on one of these.

The nine events

use ByRcsc\LaravelAssignment\Events\AssignableQueued;
use ByRcsc\LaravelAssignment\Events\Assigned;
use ByRcsc\LaravelAssignment\Events\AssignmentAccepted;
use ByRcsc\LaravelAssignment\Events\AssignmentDeclined;
use ByRcsc\LaravelAssignment\Events\AssignmentOffered;
use ByRcsc\LaravelAssignment\Events\OfferExpired;
use ByRcsc\LaravelAssignment\Events\OffersExhausted;
use ByRcsc\LaravelAssignment\Events\Reassigned;
use ByRcsc\LaravelAssignment\Events\Unassigned;
EventDispatched whenPayload
AssignedAn assignment becomes active, by assign() or acceptance$assignment
AssignmentOfferedAn offer is created$assignment
AssignmentAcceptedThe assignee accepts an offer$assignment
AssignmentDeclinedThe assignee declines an offer$assignment
OfferExpiredAn overdue offer is ended by the tick or a job$assignment
UnassignedAn active assignment ends by unassign() or reassignment$assignment
ReassignedA reassignment replaces one assignee with another$oldAssignment, $newAssignment
AssignableQueuedAn assignable enters the queue$entry
OffersExhaustedA cascade runs out of candidates$lastOffer

Every payload property is public and readonly.

Which events fire together

Some transitions dispatch more than one, in a fixed order.

Accepting an offer dispatches AssignmentAccepted and then Assigned. A listener that cares about work becoming active can listen only to Assigned and catch both routes.

Reassigning dispatches Unassigned for the old row, Assigned for the new one, and then Reassigned carrying both. A listener on Unassigned that should ignore reassignment checks the reason:

use ByRcsc\LaravelAssignment\Enums\EndReason;

public function handle(Unassigned $event): void
{
    if ($event->assignment->ended_reason === EndReason::Reassigned) {
        return;
    }

    // a real removal
}

A declined offer that cascades dispatches AssignmentDeclined, then AssignmentOffered for the next candidate, in the same request.

Completing dispatches nothing. complete() ends the row with reason completed and is silent, so a completion hook belongs in your own code around the call.

Events wait for the transaction

Every event implements ShouldDispatchAfterCommit. Inside a transaction that rolls back, nothing is dispatched:

DB::transaction(function () use ($enquiry, $tradie) {
    $enquiry->assign($tradie);

    throw new PaymentFailed;   // no Assigned event reaches any listener
});

That is what makes it safe for a listener to assume the row it receives exists. It also means a listener does not run until the outermost transaction commits, so an assignment made inside a long transaction notifies late.

Listeners run inline

None of the events implement ShouldQueue, so listeners run synchronously inside the call that caused the transition. A listener that calls a slow API slows down assign(), and inside a cascade it slows down every step.

Queue the listener, not the event:

namespace App\Listeners;

use ByRcsc\LaravelAssignment\Events\OffersExhausted;
use Illuminate\Contracts\Queue\ShouldQueue;

final class EscalateUntakenWork implements ShouldQueue
{
    public string $queue = 'notifications';

    public function handle(OffersExhausted $event): void
    {
        $assignable = $event->lastOffer->assignable;

        // page the dispatcher, open a ticket, post to Slack ...
    }
}

Register it as you would any listener. The events serialize their models, so a queued listener reloads the row and sees its committed state.

Useful listeners

Flush the queue when somebody becomes available. More responsive than waiting for the next tick:

public function handle(CrewBecameAvailable $event): void
{
    Assignment::flushQueue(Callout::class);
}

Alert on exhaustion. OffersExhausted is the signal that nobody would take the work, which no notification covers.

Watch the backlog. AssignableQueued fires once per entry created, so a counter or a threshold alert belongs here.

Track handling time. Assigned and the row's ended_at bracket the work. Write your own metrics from the pair rather than querying the table later.

What it does not do

  • Carry the actor. The model that performed the action is on the assignment as assignedBy, not on the event.
  • Fire for reads. Nothing dispatches when you call assignee() or workload().
  • Fire for completion. See above.
  • Provide a single catch-all event. Listen to the transitions you care about.

What to read next

  • Notifications for what the package sends without a listener.
  • Offer cascades for the sequence a decline sets off.
  • Reading assignments for what each payload row carries.
PreviousNotificationsNextConcurrency guarantees
View source

On this page

  1. The nine events
  2. Which events fire together
  3. Events wait for the transaction
  4. Listeners run inline
  5. Useful listeners
  6. What it does not do
  7. What to read next