In this article, we want to explore the various ways we can execute small tasks or actions in laravel after a response is sent. You will see how these tasks are processed after the application responds to an incoming request.
Let’s take a peep at the entry point for all requests to a Laravel application, which is the public/index.php
file. We’re only interested in the part where the request is handled through the kernel and a response is sent back to the client (e.g browser).
// public/index.php
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);
$response->send();
$kernel->terminate($request, $response);
An Http kernel instance is resolved from the laravel container and is used to handle the incoming request, and then returns a response. This response is sent back to the client, by calling the $response→send()
method on the response variable gotten from handling the request. The send
method outputs the content and sends defined headers for the response, it then tries to close the output buffering by ending the open connection with the client. In a case PHP FPM is used, the fastcgi_finish_request
is used to close the connection.
The
fastcgi_finish_request
function flushes all response data to the client and finishes the request. This allows for time-consuming tasks to be performed without leaving the connection to the client open. Read more here
Just after the $response→send()
line, we have the $kernel→terminate($request, $response)
line next. We know the former sends a response, but what about that of the later. The latter expression seems self-explaining, indicating the application Http kernel is terminating the request and response.
After a response has been sent and the client connection closed, the PHP process is still alive to continue execution. In this case, the application Http kernel terminate
method can be used to run little tasks. To run such little task or action, we can achieve them using:
- Terminable Middleware
- Terminating Callbacks
// vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php
public function terminate($request, $response)
{
$this->terminateMiddleware($request, $response);
$this->app->terminate();
}
The above code snippet happens to be the content of the kernel terminate
method. The first line calls the method terminateMiddleware
on the application Http kernel, and the second calls the terminate
method on the application container, which runs through all the terminating callbacks and execute them.
Terminable Middlewares
In laravel, we can define middlewares to intercept incoming requests and perform little tasks before reaching the main controller logic. This middleware class usually have a handle
method to run the task. We can also define a terminate
method on this middleware class, this method will perform little tasks after the response has been sent to the client. A middleware class with the terminate
method can be described as a Terminable Middleware.
<?php
namespace App\Http\Middleware;
use Closure;
class AfterResponseMiddleware
{
public function handle($request, Closure $next)
{
return $next($request);
}
public function terminate($request, $response)
{
// Perform tasks after response as been sent to the client
}
}
Remember the method terminateMiddleware
we found being used in the application Http kernel terminate
method. This method is what calls the terminate method on any terminable middleware.
So in what case would one need to use a terminable middleware: Activity logging, Request logging and Session tracking.
Terminating Callbacks
Terminating callbacks are executed just after all terminable middlewares have been executed. These callbacks are functions registered to the laravel application. The snippet below, shows how to register a terminating callback:
App::terminating(function () {
});
app()->terminating(function () {
});
From the above code block, we can observe the use of a terminating
method to register the callback function. This terminating method
also exists in the application container. When the terminate
method is called after the terminable middleware execution, all the terminating callbacks are then executed.
foreach ($this->terminatingCallbacks as $terminating) {
$this->call($terminating);
}
A pretty much use case for a terminating callback is reporting on guzzle requests made during an Http request in laravel. Also, Mohamed Said contributed a new method that allows a job to dispatch after the response is sent back to the client, he wrote about this on his blog here. This is needed to dispatch a short job instantly instead of sending it to the regular queue system.
ShortInstantJob::dispatchAfterResponse();
The dispatchAfterResponse
attaches the Job class as a terminating callback to the laravel application which is then executed when the application terminate
is called.
Conclusion
Right here, we have seen the possible ways there is to execute actions after a response is sent in laravel and how this is achieved. Note that the kind of actions or tasks we want to execute after returning a response are meant to be a short-lived process.
Top comments (1)
What are some of the trade-offs, gotchas, or FYIs when using this approach?
It looks interesting, but I feel anxious about what happens during the cleanup phase.