Bellum
Bellum

Reputation: 175

Symfony2: How to use INSERT DELAYED with doctrine or create a non-blocking database operation?

For performance reasons I would like to persist a log object using mysql's INSERT DELAYED query.

Do you have any ideas how that could be performed using doctrine?

Upvotes: 3

Views: 1121

Answers (1)

Nicolai Fröhlich
Nicolai Fröhlich

Reputation: 52483

Why you probably shouldn't use INSERT DELAYED:

As of MySQL 5.6.6, INSERT DELAYED is deprecated, and will be removed in a future release. Use INSERT (without DELAYED) instead.

(official documentation)

The symfony2 solution:

With symfony2 you can perform a non-blocking database-operation by creating a listener/subscriber for the kernel.terminate event and executing it in there.

This event is fired after the response has been sent. It's being used by monolog in the production environment for example.

Create a listener class first:

namespace Acme\Your;

use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\HttpKernel\Event\KernelEvent;

class LongOperationLogger
{
    protected $om;
    protected $data;

    public function __construct(ObjectManager $om)
    {
        $this->om = $om;
    }

    public function setData($data)
    {
        $this->data = $data;
    }

    public function onKernelTerminate(KernelEvent $event)
    {
        // don't do anything if there is not data
        if ( null !== $this->data ) {
            return;
        }

        $logEntry = new LogEntry('I will not block the response.', $this->data);

        $this->om->persist($logEntry);
        $this->om->flush();
    }
}

Then define it as a service and inject your object-manager:

# app/config/config.yml

services:
    long_operation.logger:
        class: Acme\Your\LongOperationLogger
        tags:
            - { name: kernel.event_listener, event: kernel.terminate }
        arguments: [ "@doctrine.orm.entity_manager" ]

Finally, you can add data to the logger from inside a controller or some service which in turn activates and executes the database-operation in a non-blocking way after the response has been sent.

public function someAction()
{
    // some condition
    // if (...) {
    //     ...
    // }

    $this->get('long_operation.logger')->setData($whatever)
}

Upvotes: 5

Related Questions