›
›
›
  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.

Every transition dispatches an event, and each event waits 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. The package leaves out manager alerts, dashboards, and escalations on purpose. Build each of them as a listener on one of these events.

Event list

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 ends by the tick, a job, or a new write$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 event, 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 dispatches no event. Put completion logic 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
});

A listener can therefore assume that the row it receives exists. A listener also 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. The listener assigns waiting work sooner than the next tick does:

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

Alert on exhaustion. OffersExhausted means that nobody took the work. No notification covers that case.

Watch the backlog. AssignableQueued fires once per entry created, so put a counter or a threshold alert in its listener.

Track handling time. Assigned marks the start of the work, and the row's ended_at marks the end. 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. Event list
  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