Skip to content

Clear entity-manager after each task to ensure clean environment #34

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 18, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@ public function getConfigTreeBuilder()
$treeBuilder->root('task')
->children()
->enumNode('storage')->values(['array', 'doctrine'])->defaultValue('doctrine')->end()
->arrayNode('adapters')
->addDefaultsIfNotSet()
->children()
->arrayNode('doctrine')
->addDefaultsIfNotSet()
->children()
->booleanNode('clear')->defaultTrue()->end()
->end()
->end()
->end()
->end()
->arrayNode('run')
->addDefaultsIfNotSet()
->children()
Expand Down
31 changes: 25 additions & 6 deletions src/DependencyInjection/TaskExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,13 @@

use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Task\Event\Events;
use Task\TaskBundle\EventListener\DoctrineTaskExecutionListener;

/**
* Container extension for php-task library.
Expand All @@ -40,12 +44,27 @@ public function load(array $configs, ContainerBuilder $container)
$loader->load('listener.xml');
}

if ('doctrine' === $config['storage']) {
// FIXME move to compiler pass
$container->getDefinition('task.command.schedule_task')
->addArgument(new Reference('doctrine.orm.entity_manager'));
$container->getDefinition('task.command.run')
->addArgument(new Reference('doctrine.orm.entity_manager'));
$this->loadDoctrineAdapter($config['adapters']['doctrine'], $container);
}

/**
* Load doctrine adapter.
*
* @param array $config
* @param ContainerBuilder $container
*/
private function loadDoctrineAdapter(array $config, ContainerBuilder $container)
{
if ($config['clear']) {
$definition = new Definition(
DoctrineTaskExecutionListener::class,
[new Reference('doctrine.orm.entity_manager', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)]
);
$definition->addTag(
'kernel.event_listener',
['event' => Events::TASK_AFTER, 'method' => 'clearEntityManagerAfterTask']
);
$container->setDefinition('task.adapter.doctrine.execution_listener', $definition);
}
}
}
16 changes: 16 additions & 0 deletions src/Entity/TaskExecutionRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,22 @@ public function findPending(TaskInterface $task)
}
}

/**
* {@inheritdoc}
*/
public function findByUuid($uuid)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

couldnt you use the doctrine internal findOneByUuid function?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tbh i dont like this "magic" internal methods.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same opinion as @wachterjohannes. This way it will be easier to optimize if there come up performance problem at some time.

{
try {
return $this->createQueryBuilder('e')
->where('e.uuid = :uuid')
->setParameter('uuid', $uuid)
->getQuery()
->getSingleResult();
} catch (NoResultException $e) {
return;
}
}

/**
* {@inheritdoc}
*/
Expand Down
48 changes: 48 additions & 0 deletions src/EventListener/DoctrineTaskExecutionListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

/*
* This file is part of php-task library.
*
* (c) php-task
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace Task\TaskBundle\EventListener;

use Doctrine\ORM\EntityManagerInterface;
use Task\Event\TaskExecutionEvent;

/**
* Listens on task-execution events.
*/
class DoctrineTaskExecutionListener
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry to mention that again, but I missed it the last time... Wouldn't it be better to make it a subscriber? Then it could handle all the doctrine specific settings, which might be added later. Otherwise this would have to be renamed to something to include clear.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also like this we could handle everything for doctrine - i dont see the difference

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not if you have to do some doctrine specific tasks on different events.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thats configuration you can use multiple tags for different events.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, that's true, but I think it is a little bit hidden in the configuration... And since this class is already bound to an event I would also not fear implementing the EventSubscriberInterface... But well, I think that's just personal preference. It's also ok for me this way.

{
/**
* @var EntityManagerInterface
*/
private $entityManager;

/**
* @param EntityManagerInterface $entityManager
*/
public function __construct(EntityManagerInterface $entityManager = null)
{
$this->entityManager = $entityManager;
}

/**
* This method clears the entity-manager after each task to ensure clean state before next task.
*
* @param TaskExecutionEvent $event
*/
public function clearEntityManagerAfterTask(TaskExecutionEvent $event)
{
if (!$this->entityManager) {
return;
}

$this->entityManager->clear();
}
}
1 change: 1 addition & 0 deletions src/Resources/config/task_event_listener.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<parameter key="task.events.create" type="constant">Task\Event\Events::TASK_CREATE</parameter>
<parameter key="task.events.create_execution" type="constant">Task\Event\Events::TASK_EXECUTION_CREATE</parameter>
<parameter key="task.events.before" type="constant">Task\Event\Events::TASK_BEFORE</parameter>
<parameter key="task.events.after" type="constant">Task\Event\Events::TASK_AFTER</parameter>
<parameter key="task.events.finished" type="constant">Task\Event\Events::TASK_FINISHED</parameter>
<parameter key="task.events.passed" type="constant">Task\Event\Events::TASK_PASSED</parameter>
<parameter key="task.events.failed" type="constant">Task\Event\Events::TASK_FAILED</parameter>
Expand Down
66 changes: 36 additions & 30 deletions tests/Functional/Command/RunCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,21 +42,24 @@ public function testExecute()
]
);

$this->assertEquals(TaskStatus::COMPLETED, $executions[0]->getStatus());
$this->assertEquals(strrev('Test workload 1'), $executions[0]->getResult());
$this->assertGreaterThan(0, $executions[0]->getDuration());
$this->assertGreaterThanOrEqual($executions[0]->getStartTime(), $executions[0]->getEndTime());

$this->assertEquals(TaskStatus::PLANNED, $executions[1]->getStatus());
$this->assertNull($executions[1]->getResult());
$this->assertNull($executions[1]->getDuration());
$this->assertNull($executions[1]->getStartTime());
$this->assertNull($executions[1]->getEndTime());

$this->assertEquals(TaskStatus::COMPLETED, $executions[2]->getStatus());
$this->assertEquals(strrev('Test workload 3'), $executions[2]->getResult());
$this->assertGreaterThan(0, $executions[2]->getDuration());
$this->assertGreaterThanOrEqual($executions[2]->getStartTime(), $executions[2]->getEndTime());
$execution = $this->taskExecutionRepository->findByUuid($executions[0]->getUuid());
$this->assertEquals(TaskStatus::COMPLETED, $execution->getStatus());
$this->assertEquals(strrev('Test workload 1'), $execution->getResult());
$this->assertGreaterThan(0, $execution->getDuration());
$this->assertGreaterThanOrEqual($execution->getStartTime(), $execution->getEndTime());

$execution = $this->taskExecutionRepository->findByUuid($executions[1]->getUuid());
$this->assertEquals(TaskStatus::PLANNED, $execution->getStatus());
$this->assertNull($execution->getResult());
$this->assertNull($execution->getDuration());
$this->assertNull($execution->getStartTime());
$this->assertNull($execution->getEndTime());

$execution = $this->taskExecutionRepository->findByUuid($executions[2]->getUuid());
$this->assertEquals(TaskStatus::COMPLETED, $execution->getStatus());
$this->assertEquals(strrev('Test workload 3'), $execution->getResult());
$this->assertGreaterThan(0, $execution->getDuration());
$this->assertGreaterThanOrEqual($execution->getStartTime(), $execution->getEndTime());

$result = $this->taskExecutionRepository->findAll(2, 3);
$this->assertCount(1, $result);
Expand Down Expand Up @@ -86,21 +89,24 @@ public function testExecuteWithFail()
]
);

$this->assertEquals(TaskStatus::FAILED, $executions[0]->getStatus());
$this->assertNull($executions[0]->getResult());
$this->assertGreaterThan(0, $executions[0]->getDuration());
$this->assertGreaterThanOrEqual($executions[0]->getStartTime(), $executions[0]->getEndTime());

$this->assertEquals(TaskStatus::PLANNED, $executions[1]->getStatus());
$this->assertNull($executions[1]->getResult());
$this->assertNull($executions[1]->getDuration());
$this->assertNull($executions[1]->getStartTime());
$this->assertNull($executions[1]->getEndTime());

$this->assertEquals(TaskStatus::FAILED, $executions[2]->getStatus());
$this->assertNull($executions[2]->getResult());
$this->assertGreaterThan(0, $executions[2]->getDuration());
$this->assertGreaterThanOrEqual($executions[2]->getStartTime(), $executions[2]->getEndTime());
$execution = $this->taskExecutionRepository->findByUuid($executions[0]->getUuid());
$this->assertEquals(TaskStatus::FAILED, $execution->getStatus());
$this->assertNull($execution->getResult());
$this->assertGreaterThan(0, $execution->getDuration());
$this->assertGreaterThanOrEqual($execution->getStartTime(), $execution->getEndTime());

$execution = $this->taskExecutionRepository->findByUuid($executions[1]->getUuid());
$this->assertEquals(TaskStatus::PLANNED, $execution->getStatus());
$this->assertNull($execution->getResult());
$this->assertNull($execution->getDuration());
$this->assertNull($execution->getStartTime());
$this->assertNull($execution->getEndTime());

$execution = $this->taskExecutionRepository->findByUuid($executions[2]->getUuid());
$this->assertEquals(TaskStatus::FAILED, $execution->getStatus());
$this->assertNull($execution->getResult());
$this->assertGreaterThan(0, $execution->getDuration());
$this->assertGreaterThanOrEqual($execution->getStartTime(), $execution->getEndTime());

$result = $this->taskExecutionRepository->findAll(2, 3);
$this->assertCount(1, $result);
Expand Down
2 changes: 1 addition & 1 deletion tests/Functional/Command/ScheduleTaskCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ public function testExecuteWithExecutionDate()
$this->assertCount(1, $executions);

$this->assertEquals(TestHandler::class, $executions[0]->getHandlerClass());
$this->assertEquals($date, $executions[0]->getScheduleTime());
$this->assertEquals($date, $executions[0]->getScheduleTime(), '', 2);
}

/**
Expand Down
32 changes: 32 additions & 0 deletions tests/Unit/EventListener/TaskExecutionListenerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

/*
* This file is part of php-task library.
*
* (c) php-task
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace Task\TaskBundle\Tests\Unit\EventListener;

use Doctrine\ORM\EntityManagerInterface;
use Task\Event\TaskExecutionEvent;
use Task\TaskBundle\EventListener\DoctrineTaskExecutionListener;

/**
* Tests for class TaskExecutionListener.
*/
class TaskExecutionListenerTest extends \PHPUnit_Framework_TestCase
{
public function testClearEntityManagerAfterTask()
{
$entityManager = $this->prophesize(EntityManagerInterface::class);

$listener = new DoctrineTaskExecutionListener($entityManager->reveal());
$listener->clearEntityManagerAfterTask($this->prophesize(TaskExecutionEvent::class)->reveal());

$entityManager->clear()->shouldBeCalled();
}
}