DEV Community

Wisdom Ebong
Wisdom Ebong

Posted on

Execute an action after Laravel returns response

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)

Collapse
 
dkroft profile image
dkroft

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.