How to make Inspector work on Laravel Vapor – Verifarma.com case study

Valerio Barbera
Laravel Vapor implementation

In this article I’ll show you the code implementation to make Inspector work when your Laravel application is deployed on the AWS serverless environment using Vapor.

The launch of Vapor was a big news for the whole PHP/Laravel ecosystem. It allows developers to deploy Laravel applications on AWS Lambda environment, the serverless infrastructure of AWS, without the need to be an expert DevOps, or cloud engineer.

With the aim of eliminating the problem of servers scalability, it brings some complexities that you need to deal with. Serverless execution environment isn’t the same of classic server, furthermore it’s not so easy to customize if you need some additional configuration.

Verifarma.com platform is built on top of Laravel and deployed in the AWS serverless platform using Vapor. They are leader and specialist in traceability and product identification, to improve efficiency throughout the distribution chain. The company today, track and trace leaders in the region and with rapidly growth in Europe, present in 23 countries.

They are one of our best customers that monitor Code Execution Flow in their application with Inspector.

Martín Lejman, lead developer in Verifarma, wrote me about two issues using Inspector when the application is deployed through Vapor in AWS Lambda.

  1. “async” transport doesn’t work. Nothing appears in the dashboard, so they should be use “sync” transport, but it’s suitable for debugging pourpose not for production environment.
  2. Jobs are not monitored at all. They doesn’t appears in the the processes list regardless of the data transmission method.

Since the beginning Inspector has been appreciated by developers mainly due to its really powerful Laravel package. I’m really gratefull to the community for the support and feedbacks they provided me over time so work with Martin to make Inspector work on Vapor was a really important challenge for me to continue to guarantee a perfect code monitoring experience to all Laravel developers.

The problem with AWS Lambda

As opposed to a normal LAMP server, AWS Lambda execution environment has default settings that you need to adapt to.

Related to Inspector, after data collection the package sends data packets to the remote API asynchronously using two natives PHP functions behind the scenes (proc_open, proc_close).

Thanks to these functions Inspector start a process at OS level that will send monitoring data to our API silently in background, with zero impact on your application performance.

AWS Lambda have these two functions disabled by default.

In a normal server environment they can be enabled/disbaled using a php.ini property:

disable_functions=exec,passthru,shell_exec,system,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source,proc_open,proc_close

It could be for security reasons or something else, anyway in Lambda they seams disabled. Furthermore Vapor currently doesn’t provide a way to overwrite this configuration during deployment, so we can’t unlock proc_open, proc_close to be used by the Inspector package.

Martin has also opened a ticket to the Vapor team to give their users this option, but we have no guarantees that it will be implemented.

Since the beginning of its implementation, I designed the Inspector Laravel package trying to decoupling the data collection functionality from how these data should be transferred to our API.

But I had not yet thought about the possibility of using a custom transport implementation injected from outside the package.

Set a custom transport

I changed the package design to allows developers to inject their custom transport at runtime. In the boot method of your ApplicationServiceProvider you can use the code below:

$this->app->inspector->setTransport(function ($configuration) {
    return new MyCustomTransport($configuration);
});

The callback will receive an instance of the Inspector “Configuration” class, that contains the Ingestion Key, the URL of our remote API, and all other information needed to build the appropriate HTTP call.

Verifarma QueueTransport Implementation

Martin and his team thought to implement a transport that simply schedule a job in AWS SQS to send data to the Inspector API and achieve the same behavior of the default “async” transport.

The package ships with an interface TransportInterface that you can implement in order to provide a new way of how to send monitoring data to the remote platform.

interface TransportInterface
{
    /**
     * Add an Arrayable entity in the queue.
     *
     * @param \Inspector\Models\Arrayable $entry
     * @return mixed
     */
    public function addEntry(Arrayable $entry);

    /**
     * Send data to Inspector.
     *
     * This method is invoked after your application has sent
     * the response to the client.
     *
     * So this is the right place to perform the data transfer.
     *
     * @return mixed
     */
    public function flush();
}

To keep the data sending process “asynchronously”, Martin has developed a custom transport that simply schedule a job to send monitoring data in background:

namespace Verifarma\Inspector\Transports;


use Exception;
use Inspector\Transports\AbstractApiTransport;
use Inspector\Transports\TransportInterface;
use Verifarma\Inspector\Jobs\SendInspectorChunkJob;

class QueueTransport extends AbstractApiTransport implements TransportInterface
{
    /**
     * @param string $data
     * @throws Exception
     */
    protected function sendChunk($data)
    {
        dispatch(new SendInspectorChunkJob($this->config, $data));
    }
}

SendInspectorChunkJob receives the data in its constructor to be sent when the job is scheduled for execution. Here is the implementation of the Job class:

class SendInspectorChunkJob implements ShouldQueue
{
    use Queueable, InteractsWithQueue;

    /**
     * Monitoring Data
     * 
     * @var string
     */
    protected $data;

    /**
     * Inspector configuration.
     * 
     * @var Configuration 
     */
    protected $configuration;

    /**
     * SendInspectorChunkJob constructor.
     *
     * @param Configuration $configuration
     * @param string $data
     */
    public function __construct(Configuration $configuration, string $data)
    {
        $this->data = $data;
        $this->configuration = $configuration;
    }

    /**
     * Use the original CurlTransport.
     * 
     * @param \Inspector\Configuration $configuration
     * @throws \Inspector\Exceptions\InspectorException
     */
    public function handle()
    {
        $transport = new \Inspector\Transports\CurlTransport($this->configuration);

        $transport->sendChunk($this->data);
    }
}

The job will be executed asynchronously without forcing your application to wait until Curl has transferred the data.

Finally we need to inform Inspector to use this new transport. In the boot method of the AppServiceProvider paste the code below:

$this->app->inspector->setTransport(function ($configuration) {
    return new QueueTransport($configuration);
});

The issue with AWS Lambda has been resolved.

The problem with Laravel Vapor

Checking the vapor-core repository it seems that a daemon runs the jobs with the laravel/vapor-core/src/Queue/VaporWorker.php worker. It never fires the standard Queue::looping() event, which is basically used inside the Inspector package to detect when a Job is picked from the queue.

That’s why Jobs aren’t monitored at all. We needed to change the package implementation to listen something else. The challenge was to find a strategy compatible with all use cases by default without forcing developers to add custom configuration for every environment.

And we did it. Now Jobs are detected regardless if you use Laravel Vapor or a normal server environment.

We detect the end of the jobs using three events: JobProcessed, JobFailed or JobExceptionOcurred to fire the flush() method inside the transport.

Conclusion

I’d like to thank Martin and his team for their commitment to have Inspector as main monitoring system behind their platform.

The lesson I learned is that isn’t about a library or a tool, the success of a collaboration is more about people and their passion to build software that leads to real business outcomes.

Thank you for reading it, if you have any question about Inspector drop in live chat, I’m here to help.

Related Posts

Twilio SMS Notification Channel

Hi, I’m Valerio software engineer from Italy, and CTO at Inspector. I am really happy to announce the general availability of our brand new “Twilio – SMS” notification channel. If you are a busy developer you now have one more option to intelligently forward your application monitoring notificiations directly in your smartphone, stay informed about

Node Js Code Execution Monitoring

NodeJs Real-Time Execution Monitoring with Inspector

Have you ever desired to watch your code running, instead of just imagining it? Hi, I’m Valerio software engineer from Italy and CTO at Inspector. As product owner I learned on my skin how an application issue can be so hard to fix, creating a negative impact on the users experience, or block new potential

MySQL performance optimizations

How to accelerate application performance with smart SQL queries.

Why so many performance issues are caused by the database? We often forget that each request is not independent of other requests. If one request is slow, it’s unlikely to affect the others… right? Database is a shared resource used by all processes that runs in your application. Even just one poorly designed access can

Stop losing customers and money
due to technical problems in your applications

Monitor performance of your code execution in real-time and identify bugs and bottlenecks before your users do.
Simple Code Execution Monitoring, built for developers
2020 © Inspector S.R.L - VAT: 09552901218