Job middleware, and the rate limit that is not in the handler

A job that must not run more than once per minute per customer had that logic at the top of handle(), mixed with the work, and repeated in three other jobs.

final class RateLimited
{
    public function handle($job, $next)
    {
        Redis::throttle('customer:' . $job->customerId)
            ->allow(1)->every(60)
            ->then(function () use ($job, $next) {
                $next($job);
            }, function () use ($job) {
                $job->release(10);
            });
    }
}

// on the job
public function middleware()
{
    return [new RateLimited(), new PreventOverlapping()];
}

6.0 added this and it is the same shape as HTTP middleware, which makes it immediately legible. The release-on-rejection is the part to get right: a throttled job that returns without releasing is a job that is silently dropped. Throttling in middleware rather than in the handler also means the handler stays testable without Redis, which is worth more than the deduplication.