├── .gitignore
├── Tests
├── Fixtures
│ ├── App
│ │ ├── app
│ │ │ └── config
│ │ │ │ ├── routing.yml
│ │ │ │ ├── config_validate_rest.yml
│ │ │ │ ├── config_bernard.yml
│ │ │ │ ├── services.yml
│ │ │ │ └── config_test.yml
│ │ └── Bundle
│ │ │ └── TestBundle
│ │ │ ├── TestBundle.php
│ │ │ ├── DependencyInjection
│ │ │ ├── Configuration.php
│ │ │ └── TestExtension.php
│ │ │ └── Entity
│ │ │ └── Entity.php
│ ├── Job
│ │ ├── TestResponse.php
│ │ ├── ProcessControl
│ │ │ └── DoStopController.php
│ │ ├── LoggerAwareJob.php
│ │ ├── ControllerAwareJob.php
│ │ ├── JobAwareJob.php
│ │ └── ManagerAwareJob.php
│ └── Annotation
│ │ └── AnnotatedJob.php
├── bootstrap.php
├── Functional
│ ├── Adapter
│ │ └── BernardTest.php
│ ├── Controller
│ │ └── JobTypeControllerTest.php
│ ├── Job
│ │ ├── Mailer
│ │ │ └── MailerTest.php
│ │ └── ConnectionTest.php
│ └── Doctrine
│ │ └── LogManagerTest.php
├── Validator
│ ├── Job
│ │ └── AbstractConstraintProviderTest.php
│ └── Constraints
│ │ └── JobTest.php
├── Job
│ ├── JobTypeNotFoundExceptionTest.php
│ ├── Exception
│ │ └── TicketNotFoundExceptionTest.php
│ ├── ScheduleBuilderTest.php
│ ├── Queue
│ │ └── QueueConfigTest.php
│ ├── StatusTest.php
│ └── ExceptionResponseTest.php
├── Event
│ ├── TerminationEventTest.php
│ └── ExecutionEventTest.php
├── Model
│ ├── LogTest.php
│ ├── ScheduleTest.php
│ └── JobTest.php
├── Entity
│ ├── ScheduleTest.php
│ └── JobTest.php
├── Locker
│ └── NullLockerTest.php
├── Adapter
│ ├── Sonata
│ │ └── Fixtures
│ │ │ └── TestIterator.php
│ └── Bernard
│ │ └── ConsumerAdapterTest.php
└── Logger
│ └── Handler
│ ├── StreamHandlerFactoryTest.php
│ ├── OrmHandlerFactoryTest.php
│ └── BaseHandlerFactoryTest.php
├── Resources
├── views
│ ├── Demo
│ │ └── index.html.twig
│ └── layout.html.twig
├── docs
│ ├── todo.md
│ ├── rest-api.md
│ ├── clustered-environment.md
│ ├── scheduled-jobs.md
│ ├── process-control.md
│ ├── message-consuming.md
│ ├── cancel-jobs.md
│ ├── serialization.md
│ └── logging.md
└── config
│ ├── routing
│ ├── rest-all.xml
│ ├── rest-job-type.xml
│ └── rest-job.xml
│ ├── services
│ ├── commands.xml
│ ├── locker.xml
│ ├── logger_stream.xml
│ ├── validator.xml
│ ├── scheduler.xml
│ ├── logger_storage_file.xml
│ ├── default_jobs.xml
│ ├── logger.xml
│ ├── listener.xml
│ ├── logger_storage_orm.xml
│ ├── serializer.xml
│ ├── adapter_bernard.xml
│ ├── orm.xml
│ ├── registry.xml
│ └── adapter_sonata.xml
│ ├── doctrine-mapping
│ └── Log.orm.xml
│ └── doctrine
│ ├── Schedule.orm.xml
│ └── Job.orm.xml
├── CHANGELOG.md
├── Serializer
├── SerializationContext.php
├── DeserializationContext.php
├── SerializerInterface.php
├── Serializer.php
└── EventDispatcher
│ └── JobDeserializationSubscriber.php
├── Job
├── JobAwareInterface.php
├── ManagerAwareInterface.php
├── JobParameterArray.php
├── Queue
│ ├── ConsumerInterface.php
│ ├── ProducerInterface.php
│ ├── QueueConfigInterface.php
│ ├── Message.php
│ └── QueueConfig.php
├── ScheduleBuilder.php
├── LogManagerInterface.php
├── ProcessControl
│ └── FactoryInterface.php
├── JobTypeNotFoundException.php
├── Exception
│ ├── TicketNotFoundException.php
│ └── ValidationFailedException.php
├── Context
│ ├── Exception
│ │ └── ParameterNotFoundException.php
│ ├── ContextInterface.php
│ └── Context.php
├── ExceptionResponse.php
├── Parameter
│ └── DefaultJobsConstraintProvider.php
├── Sleeper.php
├── JobBuilder.php
└── Mailer
│ └── Mailer.php
├── Model
├── AbstractListInterface.php
├── JobList.php
├── ScheduleManagerInterface.php
├── ScheduleInterface.php
├── AbstractList.php
├── JobManager.php
├── JobInterface.php
├── LogManagerInterface.php
├── LogManager.php
└── LogInterface.php
├── Logger
├── Entity
│ └── Log.php
├── LoggerFactoryInterface.php
└── Handler
│ ├── OrmHandlerFactory.php
│ ├── HandlerFactoryInterface.php
│ ├── JobAwareOrmHandler.php
│ ├── HandlerFactoryRegistry.php
│ ├── StreamHandlerFactory.php
│ ├── BaseHandlerFactory.php
│ └── OrmHandler.php
├── Validator
├── Constraints
│ ├── Status.php
│ ├── JobType.php
│ ├── Parameters.php
│ ├── Job.php
│ ├── StatusValidator.php
│ ├── JobTypeValidator.php
│ └── JobValidator.php
└── Job
│ ├── AbstractConstraintProvider.php
│ └── ConstraintProviderInterface.php
├── Annotation
├── ReturnType.php
└── ParamType.php
├── Test
├── MockHelper.php
├── WebTestCase.php
├── AdapterTest.php
└── DatabaseWebTestCase.php
├── Locker
└── NullLocker.php
├── Event
├── TerminationEvent.php
├── ExecutionEvent.php
└── JobEvents.php
├── Entity
├── DetachingJobManager.php
├── Log.php
├── Job.php
├── LogManager.php
└── Schedule.php
├── LICENSE
├── DependencyInjection
└── Compiler
│ ├── RegisterEventListenersPass.php
│ ├── ConfigurationCheckPass.php
│ ├── RegisterDoctrineListenerPass.php
│ ├── LockerConfigurationPass.php
│ ├── ControllerConfigurationPass.php
│ └── RegisterConstraintProvidersPass.php
├── Api
├── ParameterConstraintViolation.php
└── BadRequestResponse.php
├── Controller
├── JobTypeController.php
└── BaseController.php
├── Adapter
└── Bernard
│ ├── ConsumerAdapter.php
│ └── ControlledConsumer.php
├── .travis.yml
├── phpunit.xml.dist
├── Doctrine
└── ScheduleManager.php
├── composer.json
├── Listener
├── JobListener.php
└── ScheduleListener.php
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/*
2 | build/*
3 | composer.lock
4 | phpunit.xml
5 | /Tests/Fixtures/App/app/config/parameters.yml
6 | vendor/*
--------------------------------------------------------------------------------
/Tests/Fixtures/App/app/config/routing.yml:
--------------------------------------------------------------------------------
1 | abc-rest-all:
2 | resource: "@AbcJobBundle/Resources/config/routing/rest-all.xml"
3 | prefix: /api
--------------------------------------------------------------------------------
/Tests/Fixtures/App/app/config/config_validate_rest.yml:
--------------------------------------------------------------------------------
1 | imports:
2 | - { resource: config_test.yml }
3 |
4 | abc_job:
5 | rest:
6 | validate: true
--------------------------------------------------------------------------------
/Resources/views/Demo/index.html.twig:
--------------------------------------------------------------------------------
1 | {% extends "AbcJobBundle::layout.html.twig" %}
2 |
3 | {% block title %}Job Bundle{% endblock title %}
4 |
5 | {% block content %}
6 | {{ form(form) }}
7 | {% endblock %}
--------------------------------------------------------------------------------
/Resources/docs/todo.md:
--------------------------------------------------------------------------------
1 | ### Planned Features
2 |
3 | - Add support for CouchDB, MongoDB
4 | - Add support for [qpush-bundle](https://www.google.de/webhp?q=qpushbundle)
5 | - Integrate https://github.com/beberlei/metrics
6 | - Utilize stopwatch
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | CHANGELOG
2 | =========
3 |
4 | 2016-10-15
5 | ----------
6 | * Removed custom Doctrine type abc.job.status
7 | * Removed dependency to AbcEnumSerializerBundle
8 |
9 |
10 | 2018-02-17
11 | ----------
12 | * Updated PHP to >7.0
13 | * Updated unit tests
--------------------------------------------------------------------------------
/Tests/Fixtures/App/app/config/config_bernard.yml:
--------------------------------------------------------------------------------
1 | imports:
2 | - { resource: config_test.yml }
3 |
4 | framework:
5 | test: ~
6 | session:
7 | storage_id: session.storage.mock_file
8 | profiler:
9 | collect: false
10 |
11 | abc_job:
12 | adapter: bernard
--------------------------------------------------------------------------------
/Tests/bootstrap.php:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/Resources/views/layout.html.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | {% block content %}
11 | {% endblock content %}
12 |
13 |
14 |
--------------------------------------------------------------------------------
/Tests/Fixtures/App/Bundle/TestBundle/TestBundle.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Fixtures\App\Bundle\TestBundle;
12 |
13 | use Symfony\Component\HttpKernel\Bundle\Bundle;
14 |
15 | /**
16 | * @author Hannes Schulz
17 | */
18 | class TestBundle extends Bundle
19 | {
20 | }
--------------------------------------------------------------------------------
/Serializer/SerializationContext.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Serializer;
12 |
13 | use JMS\Serializer\SerializationContext as BaseSerializationContext;
14 |
15 | /**
16 | * @author Hannes Schulz
17 | */
18 | class SerializationContext extends BaseSerializationContext
19 | {
20 | }
--------------------------------------------------------------------------------
/Job/JobAwareInterface.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Job;
12 |
13 | /**
14 | * @author Hannes Schulz
15 | */
16 | interface JobAwareInterface
17 | {
18 | /**
19 | * @param JobInterface $job
20 | * @return void
21 | */
22 | public function setJob(JobInterface $job);
23 | }
--------------------------------------------------------------------------------
/Serializer/DeserializationContext.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Serializer;
12 |
13 | use JMS\Serializer\DeserializationContext as BaseDeserializationContext;
14 |
15 | /**
16 | * @author Hannes Schulz
17 | */
18 | class DeserializationContext extends BaseDeserializationContext
19 | {
20 | }
--------------------------------------------------------------------------------
/Resources/config/routing/rest-job-type.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 | AbcJobBundle:JobType:list
9 | json
10 | json
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Job/ManagerAwareInterface.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Job;
12 |
13 | /**
14 | * @author Hannes Schulz
15 | */
16 | interface ManagerAwareInterface
17 | {
18 | /**
19 | * @param ManagerInterface $manager
20 | * @return void
21 | */
22 | public function setManager(ManagerInterface $manager);
23 | }
--------------------------------------------------------------------------------
/Model/AbstractListInterface.php:
--------------------------------------------------------------------------------
1 |
7 | */
8 | interface AbstractListInterface
9 | {
10 | /**
11 | * @return \ArrayAccess
12 | */
13 | public function getItems();
14 |
15 | /**
16 | * @param \ArrayAccess $items
17 | */
18 | public function setItems($items);
19 |
20 | /**
21 | * @return int
22 | */
23 | public function getTotalCount();
24 |
25 | /**
26 | * @param int $totalCount
27 | */
28 | public function setTotalCount($totalCount);
29 | }
--------------------------------------------------------------------------------
/Logger/Entity/Log.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Logger\Entity;
12 |
13 | use Abc\Bundle\JobBundle\Entity\Log as BaseLog;
14 |
15 | /**
16 | * Only reason this class is defined here is on order to register the mapping (Doctrine, MongodDB, CouchDB) optionally
17 | *
18 | * @author Hannes Schulz
19 | */
20 | class Log extends BaseLog
21 | {
22 | }
--------------------------------------------------------------------------------
/Tests/Functional/Adapter/BernardTest.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Functional\Adapter;
12 |
13 | use Abc\Bundle\JobBundle\Test\AdapterTest;
14 |
15 | /**
16 | * @author Hannes Schulz
17 | */
18 | class BernardTest extends AdapterTest
19 | {
20 | public function getEnvironment()
21 | {
22 | return 'bernard';
23 | }
24 | }
--------------------------------------------------------------------------------
/Model/JobList.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Model;
12 |
13 | use Abc\Bundle\JobBundle\Model\AbstractList;
14 | use JMS\Serializer\Annotation\Type;
15 |
16 | /**
17 | * @author Hannes Schulz
18 | */
19 | class JobList extends AbstractList
20 | {
21 | /**
22 | * @Type("array")
23 | */
24 | protected $items;
25 | }
--------------------------------------------------------------------------------
/Resources/config/services/commands.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Validator/Constraints/Status.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Validator\Constraints;
12 |
13 | use Symfony\Component\Validator\Constraint;
14 |
15 | /**
16 | * @Annotation
17 | * @Target({"PROPERTY"})
18 | *
19 | * @author Hannes Schulz
20 | */
21 | class Status extends Constraint
22 | {
23 | public $message = 'The value "{{string}}" is not status.';
24 | }
--------------------------------------------------------------------------------
/Validator/Job/AbstractConstraintProvider.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Validator\Job;
12 |
13 | /**
14 | * @author Hannes Schulz
15 | */
16 | abstract class AbstractConstraintProvider implements ConstraintProviderInterface
17 | {
18 | /**
19 | * {@inheritdoc}
20 | */
21 | public function getPriority()
22 | {
23 | return -1;
24 | }
25 | }
--------------------------------------------------------------------------------
/Validator/Constraints/JobType.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Validator\Constraints;
12 |
13 | use Symfony\Component\Validator\Constraint;
14 |
15 | /**
16 | * @Annotation
17 | * @Target({"PROPERTY"})
18 | *
19 | * @author Hannes Schulz
20 | */
21 | class JobType extends Constraint
22 | {
23 | public $message = 'The value "{{string}}" is not valid job type.';
24 | }
25 |
--------------------------------------------------------------------------------
/Annotation/ReturnType.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Annotation;
12 |
13 | /**
14 | * @Annotation
15 | * @Target({"METHOD"})
16 | * @author Hannes Schulz
17 | */
18 | class ReturnType
19 | {
20 | /**
21 | * @Required
22 | * @var string
23 | */
24 | public $type;
25 |
26 | /**
27 | * @var array
28 | */
29 | public $options = array();
30 | }
--------------------------------------------------------------------------------
/Validator/Constraints/Parameters.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Validator\Constraints;
12 |
13 | use Symfony\Component\Validator\Constraint;
14 |
15 | /**
16 | * @Annotation
17 | * @Target({"PROPERTY"})
18 | *
19 | * @author Hannes Schulz
20 | */
21 | class Parameters extends Constraint
22 | {
23 | public $type;
24 | public $message = 'The value must be an array.';
25 | }
--------------------------------------------------------------------------------
/Job/JobParameterArray.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Job;
12 |
13 | /**
14 | * JobParameterArray
15 | *
16 | * This class for now only acts as a type identifier for the serializer in order to serialize/deserialize the parameters of a job.
17 | *
18 | * @author Hannes Schulz
19 | * @see \Abc\Bundle\JobBundle\Serializer\Handler\JobParameterArrayHandler
20 | */
21 | class JobParameterArray
22 | {
23 | }
--------------------------------------------------------------------------------
/Test/MockHelper.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Test;
12 |
13 | /**
14 | * @author Hannes Schulz
15 | */
16 | class MockHelper
17 | {
18 | /**
19 | * @param $class
20 | * @return string
21 | */
22 | public static function getNamespace($class) {
23 | $pieces = explode("\\", $class);
24 | array_pop($pieces);
25 | return implode("\\", $pieces);
26 | }
27 | }
--------------------------------------------------------------------------------
/Job/Queue/ConsumerInterface.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Job\Queue;
12 |
13 | /**
14 | * @author Hannes Schulz
15 | */
16 | interface ConsumerInterface
17 | {
18 | /**
19 | * Consumes messages from the queue.
20 | *
21 | * @param string $queue The name of the queue
22 | * @param array $options
23 | * @return void
24 | */
25 | public function consume($queue, array $options = []);
26 | }
--------------------------------------------------------------------------------
/Resources/docs/rest-api.md:
--------------------------------------------------------------------------------
1 | REST-API
2 | ========
3 |
4 | The AbcJobBundle ships with a JSON REST-API. To use this you need to make sure the following bundles are installed and configured:
5 |
6 | * [NelmioApiDocBundle](https://github.com/nelmio/NelmioApiDocBundle)
7 |
8 | Next you need to make sure that the routing files are imported:
9 |
10 | ```yaml
11 | # app/config/routing.yml
12 | abc-rest-job:
13 | type: rest
14 | resource: "@AbcJobBundle/Resources/config/routing/rest-all.xml"
15 | prefix: /api
16 | ```
17 |
18 | You can now see an overview of all available API methods using API documentation provided by the [NelmioApiDocBundle](https://github.com/nelmio/NelmioApiDocBundle).
19 |
20 | Back to [index](../../README.md)
--------------------------------------------------------------------------------
/Resources/config/services/locker.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 | %abc.resource_lock.model.resource_lock.class%
12 | abc-job-lock
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Logger/LoggerFactoryInterface.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Logger;
12 |
13 | use Abc\Bundle\JobBundle\Job\JobInterface;
14 | use Psr\Log\LoggerInterface;
15 |
16 | /**
17 | * Factory for loggers and logs for jobs.
18 | *
19 | * @author Hannes Schulz
20 | */
21 | interface LoggerFactoryInterface
22 | {
23 | /**
24 | * @param JobInterface $job
25 | * @return LoggerInterface
26 | */
27 | public function create(JobInterface $job);
28 | }
--------------------------------------------------------------------------------
/Tests/Validator/Job/AbstractConstraintProviderTest.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Validator\Job;
12 |
13 |
14 | use Abc\Bundle\JobBundle\Validator\Job\AbstractConstraintProvider;
15 | use PHPUnit\Framework\TestCase;
16 |
17 | class AbstractConstraintProviderTest extends TestCase
18 | {
19 | public function testGetPriority()
20 | {
21 | $subject = $this->getMockForAbstractClass(AbstractConstraintProvider::class);
22 | $this->assertEquals(-1, $subject->getPriority());
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Annotation/ParamType.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Annotation;
12 |
13 | /**
14 | * @Annotation
15 | * @Target({"METHOD"})
16 | * @author Hannes Schulz
17 | */
18 | final class ParamType
19 | {
20 | /**
21 | * @Required
22 | * @var string
23 | */
24 | public $name;
25 |
26 | /**
27 | * @Required
28 | * @var string
29 | */
30 | public $type;
31 |
32 | /**
33 | * @var array
34 | */
35 | public $options = array();
36 | }
37 |
--------------------------------------------------------------------------------
/Tests/Job/JobTypeNotFoundExceptionTest.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Job;
12 |
13 | use Abc\Bundle\JobBundle\Job\JobTypeNotFoundException;
14 | use PHPUnit\Framework\TestCase;
15 |
16 | /**
17 | * @author Hannes Schulz
18 | */
19 | class JobTypeNotFoundExceptionTest extends TestCase
20 | {
21 | public function testGetType()
22 | {
23 | $subject = new JobTypeNotFoundException('foobar');
24 | $this->assertEquals('foobar', $subject->getType());
25 | }
26 | }
--------------------------------------------------------------------------------
/Job/Queue/ProducerInterface.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Job\Queue;
12 |
13 | use Abc\Bundle\JobBundle\Job\ManagerAwareInterface;
14 |
15 | /**
16 | * @author Hannes Schulz
17 | */
18 | interface ProducerInterface extends ManagerAwareInterface
19 | {
20 | /**
21 | * Sends a message to the queue.
22 | *
23 | * @param Message $message
24 | * @return void
25 | * @throws \RuntimeException If publishing fails
26 | */
27 | public function produce(Message $message);
28 | }
--------------------------------------------------------------------------------
/Job/ScheduleBuilder.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Job;
12 |
13 | use Abc\Bundle\JobBundle\Model\Schedule;
14 | use Abc\Bundle\JobBundle\Model\ScheduleInterface;
15 |
16 | /**
17 | * @author Hannes Schulz
18 | */
19 | class ScheduleBuilder
20 | {
21 | /**
22 | * @param $type
23 | * @param $expression
24 | * @return ScheduleInterface
25 | */
26 | public static function create($type, $expression)
27 | {
28 | return new Schedule($type, $expression);
29 | }
30 | }
--------------------------------------------------------------------------------
/Validator/Constraints/Job.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Validator\Constraints;
12 |
13 | use Symfony\Component\Validator\Constraint;
14 |
15 | /**
16 | * @Annotation
17 | * @Target({"CLASS", "PROPERTY", "METHOD", "ANNOTATION"})
18 | *
19 | * @author Hannes Schulz
20 | */
21 | class Job extends Constraint
22 | {
23 | /**
24 | * {@inheritdoc}
25 | */
26 | public function getTargets()
27 | {
28 | return [self::CLASS_CONSTRAINT, self::PROPERTY_CONSTRAINT];
29 | }
30 | }
--------------------------------------------------------------------------------
/Job/Queue/QueueConfigInterface.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Job\Queue;
12 |
13 | /**
14 | * @author Hannes Schulz
15 | */
16 | interface QueueConfigInterface
17 | {
18 | /**
19 | * @return string The name of the default queue
20 | */
21 | public function getDefaultQueue();
22 |
23 | /**
24 | * Returns the name of a queue of a job.
25 | *
26 | * @param string $type The job type
27 | * @return string The queue name
28 | */
29 | public function getQueue($type);
30 | }
--------------------------------------------------------------------------------
/Tests/Event/TerminationEventTest.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Event;
12 |
13 | use Abc\Bundle\JobBundle\Event\TerminationEvent;
14 | use Abc\Bundle\JobBundle\Model\Job;
15 | use PHPUnit\Framework\TestCase;
16 |
17 | /**
18 | * @author Hannes Schulz
19 | */
20 | class TerminationEventTest extends TestCase
21 | {
22 | public function testGetJob()
23 | {
24 | $job = new Job();
25 | $event = new TerminationEvent($job);
26 |
27 | $this->assertSame($job, $event->getJob());
28 | }
29 | }
--------------------------------------------------------------------------------
/Tests/Job/Exception/TicketNotFoundExceptionTest.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Job\Exception;
12 |
13 | use Abc\Bundle\JobBundle\Job\Exception\TicketNotFoundException;
14 | use PHPUnit\Framework\TestCase;
15 |
16 | /**
17 | * @author Hannes Schulz
18 | */
19 | class TicketNotFoundExceptionTest extends TestCase
20 | {
21 | public function testGetTicket()
22 | {
23 | $exception = new TicketNotFoundException('ticket');
24 | $this->assertEquals('ticket', $exception->getTicket());
25 | }
26 | }
--------------------------------------------------------------------------------
/Job/LogManagerInterface.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Job;
12 |
13 | /**
14 | * @author Hannes Schulz
15 | */
16 | interface LogManagerInterface
17 | {
18 | /**
19 | * @param JobInterface $job
20 | * @return array The log records of a job
21 | */
22 | public function findByJob(JobInterface $job);
23 |
24 | /**
25 | * @param JobInterface $job
26 | * @return void
27 | * @throws \RuntimeException If deletion fails
28 | */
29 | public function deleteByJob(JobInterface $job);
30 | }
--------------------------------------------------------------------------------
/Resources/docs/clustered-environment.md:
--------------------------------------------------------------------------------
1 | Clustered Environment
2 | =====================
3 |
4 | If you want to use AbcJobBundle for a setup where you have multiple job processing nodes you have to make sure, that the same job cannot be processed concurrently by different nodes. This can happen if a longer running job is configured with schedules. To ensure that this cannot happen the AbcJobBundle integrates concept of a [resource lock](https://github.com/aboutcoders/resource-lock-bundle). Whenever a message is consumed from the queue the [job manager](./job-management.md) checks if the job is currently processed by another node and skips execution if this is the case.
5 |
6 | This feature is disabled by default. In order to enable it you have to install the [AbcResourceLockBundle](https://github.com/aboutcoders/resource-lock-bundle).
7 |
8 | Back to [index](../../README.md)
--------------------------------------------------------------------------------
/Tests/Job/ScheduleBuilderTest.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Job;
12 |
13 | use Abc\Bundle\JobBundle\Job\ScheduleBuilder;
14 | use PHPUnit\Framework\TestCase;
15 |
16 | /**
17 | * @author Hannes Schulz
18 | */
19 | class ScheduleBuilderTest extends TestCase
20 | {
21 | public function testCreate()
22 | {
23 | $schedule = ScheduleBuilder::create('cron', '* * * * *');
24 |
25 | $this->assertEquals('cron', $schedule->getType());
26 | $this->assertEquals('* * * * *', $schedule->getExpression());
27 | }
28 | }
--------------------------------------------------------------------------------
/Tests/Model/LogTest.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Model;
12 |
13 | use Abc\Bundle\JobBundle\Model\Log;
14 | use PHPUnit\Framework\TestCase;
15 |
16 | /**
17 | * @author Hannes Schulz
18 | */
19 | class LogTest extends TestCase
20 | {
21 | public function testGetContext()
22 | {
23 | $subject = new Log();
24 | $this->assertTrue(is_array($subject->getContext()));
25 | }
26 |
27 | public function testGetExtra()
28 | {
29 | $subject = new Log();
30 | $this->assertTrue(is_array($subject->getExtra()));
31 | }
32 | }
--------------------------------------------------------------------------------
/Job/ProcessControl/FactoryInterface.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Job\ProcessControl;
12 |
13 | use Abc\Bundle\JobBundle\Job\JobAwareInterface;
14 | use Abc\Bundle\JobBundle\Job\JobInterface;
15 | use Abc\ProcessControl\ControllerInterface;
16 |
17 | /**
18 | * @author Hannes Schulz
19 | */
20 | interface FactoryInterface
21 | {
22 | /**
23 | * Creates the controller passed to a job implementing the
24 | *
25 | * @param JobInterface $job
26 | * @return ControllerInterface
27 | * @see JobAwareInterface
28 | */
29 | public function create(JobInterface $job);
30 | }
--------------------------------------------------------------------------------
/Tests/Validator/Constraints/JobTest.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Validator\Constraints;
12 |
13 | use Abc\Bundle\JobBundle\Validator\Constraints\Job;
14 | use PHPUnit\Framework\TestCase;
15 | use Symfony\Component\Validator\Constraint;
16 |
17 | /**
18 | * @author Hannes Schulz
19 | */
20 | class JobTest extends TestCase
21 | {
22 | public function testGetTargets()
23 | {
24 | $subject = new Job();
25 | $this->assertContains(Constraint::CLASS_CONSTRAINT, $subject->getTargets());
26 | $this->assertContains(Constraint::PROPERTY_CONSTRAINT, $subject->getTargets());
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Locker/NullLocker.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Locker;
12 |
13 | use Abc\Bundle\ResourceLockBundle\Model\LockInterface;
14 |
15 | /**
16 | * @author Hannes Schulz
17 | */
18 | class NullLocker implements LockInterface
19 | {
20 | /**
21 | * {@inheritdoc}
22 | */
23 | public function lock($name)
24 | {
25 | }
26 |
27 | /**
28 | * {@inheritdoc}
29 | */
30 | public function isLocked($name, int $autoReleaseTime = 0)
31 | {
32 | return false;
33 | }
34 |
35 | /**
36 | * {@inheritdoc}
37 | */
38 | public function release($name)
39 | {
40 | }
41 | }
--------------------------------------------------------------------------------
/Event/TerminationEvent.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Event;
12 |
13 | use Abc\Bundle\JobBundle\Job\JobInterface;
14 | use Symfony\Component\EventDispatcher\Event;
15 |
16 | /**
17 | * @author Hannes Schulz
18 | */
19 | class TerminationEvent extends Event
20 | {
21 | /** @var JobInterface */
22 | protected $job;
23 |
24 | /**
25 | * @param JobInterface $job
26 | */
27 | function __construct(JobInterface $job)
28 | {
29 | $this->job = $job;
30 | }
31 |
32 | /**
33 | * @return JobInterface
34 | */
35 | public function getJob()
36 | {
37 | return $this->job;
38 | }
39 | }
--------------------------------------------------------------------------------
/Resources/config/services/logger_stream.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 | %abc.job.logger.stream.level%
11 | %abc.job.logger.stream.bubble%
12 | %abc.job.logger.stream.path%
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Resources/config/services/validator.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Tests/Event/ExecutionEventTest.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Event;
12 |
13 | use Abc\Bundle\JobBundle\Event\ExecutionEvent;
14 | use Abc\Bundle\JobBundle\Job\Context\Context;
15 | use Abc\Bundle\JobBundle\Model\Job;
16 |
17 | /**
18 | * @author Hannes Schulz
19 | */
20 | class ExecutionEventTest extends TerminationEventTest
21 | {
22 | public function testGetContext()
23 | {
24 | $job = new Job();
25 | $context = new Context();
26 |
27 | $event = new ExecutionEvent($job, $context);
28 |
29 | $this->assertSame($job, $event->getJob());
30 | $this->assertSame($context, $event->getContext());
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Job/JobTypeNotFoundException.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Job;
12 |
13 | /**
14 | * @author Hannes Schulz
15 | */
16 | class JobTypeNotFoundException extends \Exception
17 | {
18 | const CODE = 404;
19 |
20 | /** @var string */
21 | private $type;
22 |
23 | /**
24 | * @param string $type
25 | */
26 | public function __construct($type)
27 | {
28 | parent::__construct(sprintf('Definition "%s" not found', $type), self::CODE);
29 |
30 | $this->type = $type;
31 | }
32 |
33 | /**
34 | * @return string
35 | */
36 | public function getType()
37 | {
38 | return $this->type;
39 | }
40 | }
--------------------------------------------------------------------------------
/Tests/Fixtures/Job/TestResponse.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Fixtures\Job;
12 |
13 | use JMS\Serializer\Annotation\Type;
14 |
15 | class TestResponse
16 | {
17 | /**
18 | * @var string
19 | * @Type("string")
20 | */
21 | protected $message;
22 |
23 | function __construct($message)
24 | {
25 | $this->message = $message;
26 | }
27 |
28 | /**
29 | * @param string $message
30 | */
31 | public function setMessage($message)
32 | {
33 | $this->message = $message;
34 | }
35 |
36 | /**
37 | * @return string
38 | */
39 | public function getMessage()
40 | {
41 | return $this->message;
42 | }
43 | }
--------------------------------------------------------------------------------
/Tests/Fixtures/App/Bundle/TestBundle/DependencyInjection/Configuration.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Fixtures\App\Bundle\TestBundle\DependencyInjection;
12 |
13 | use Symfony\Component\Config\Definition\Builder\TreeBuilder;
14 | use Symfony\Component\Config\Definition\ConfigurationInterface;
15 |
16 | /**
17 | * @author Hannes Schulz
18 | */
19 | class Configuration implements ConfigurationInterface
20 | {
21 | /**
22 | * {@inheritDoc}
23 | */
24 | public function getConfigTreeBuilder()
25 | {
26 | $treeBuilder = new TreeBuilder();
27 | $rootNode = $treeBuilder->root('abc_test');
28 |
29 | return $treeBuilder;
30 | }
31 | }
--------------------------------------------------------------------------------
/Job/Exception/TicketNotFoundException.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Job\Exception;
12 |
13 | /**
14 | * @author Hannes Schulz
15 | */
16 | class TicketNotFoundException extends \Exception
17 | {
18 | const CODE = 404;
19 |
20 | /** @var string */
21 | private $ticket;
22 |
23 | /**
24 | * @param string $ticket
25 | */
26 | public function __construct($ticket)
27 | {
28 | parent::__construct(sprintf('Ticket "%s" not found', $ticket), self::CODE);
29 |
30 | $this->ticket = $ticket;
31 | }
32 |
33 | /**
34 | * @return string
35 | */
36 | public function getTicket()
37 | {
38 | return $this->ticket;
39 | }
40 | }
--------------------------------------------------------------------------------
/Tests/Fixtures/Job/ProcessControl/DoStopController.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Fixtures\Job\ProcessControl;
12 |
13 | use Abc\ProcessControl\ControllerInterface;
14 |
15 | /**
16 | * @author Hannes Schulz
17 | */
18 | class DoStopController implements ControllerInterface
19 | {
20 | /**
21 | * @return true
22 | */
23 | public function doExit()
24 | {
25 | return true;
26 | }
27 |
28 | /**
29 | * @return true
30 | */
31 | public function doStop()
32 | {
33 | return true;
34 | }
35 |
36 | /**
37 | * @return false
38 | */
39 | public function doPause()
40 | {
41 | return false;
42 | }
43 | }
--------------------------------------------------------------------------------
/Job/Context/Exception/ParameterNotFoundException.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Job\Context\Exception;
12 |
13 | /**
14 | * @author Hannes Schulz
15 | */
16 | class ParameterNotFoundException extends \InvalidArgumentException
17 | {
18 |
19 | /** @var string */
20 | protected $name;
21 |
22 | /**
23 | * @param string $name The parameter name
24 | */
25 | public function __construct($name)
26 | {
27 | parent::__construct(sprintf('A parameter with the name "%s" does not exist', $name));
28 |
29 | $this->name = $name;
30 | }
31 |
32 | /**
33 | * @return string
34 | */
35 | public function getName()
36 | {
37 | return $this->name;
38 | }
39 | }
--------------------------------------------------------------------------------
/Resources/config/services/scheduler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Tests/Model/ScheduleTest.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Model;
12 |
13 | use Abc\Bundle\JobBundle\Model\Schedule;
14 | use PHPUnit\Framework\TestCase;
15 |
16 | /**
17 | * @author Hannes Schulz
18 | */
19 | class ScheduleTest extends TestCase
20 | {
21 | public function testClone()
22 | {
23 | $schedule = new Schedule();
24 | $schedule->setCreatedAt(new \DateTime);
25 | $schedule->setUpdatedAt(new \DateTime);
26 | $schedule->setScheduledAt(new \DateTime);
27 |
28 | $clone = clone $schedule;
29 |
30 | $this->assertNull($clone->getScheduledAt());
31 | $this->assertNull($clone->getUpdatedAt());
32 | $this->assertNull($clone->getCreatedAt());
33 | }
34 | }
--------------------------------------------------------------------------------
/Model/ScheduleManagerInterface.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Model;
12 |
13 | use Abc\Bundle\SchedulerBundle\Model\ScheduleManagerInterface as BaseScheduleManagerInterface;
14 |
15 | /**
16 | * @author Hannes Schulz
17 | */
18 | interface ScheduleManagerInterface extends BaseScheduleManagerInterface
19 | {
20 | /**
21 | * @param string|null $type
22 | * @param string|null $expression
23 | * @param bool $active true by default
24 | * @return ScheduleInterface
25 | */
26 | public function create($type = null, $expression = null, $active = true);
27 |
28 | /**
29 | * @param ScheduleInterface $schedule
30 | * @return void
31 | */
32 | public function delete(ScheduleInterface $schedule);
33 | }
--------------------------------------------------------------------------------
/Resources/config/services/logger_storage_file.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 | %abc.job.logger.storage.path%
11 | json
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | %abc.job.logger.storage.path%
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/Serializer/SerializerInterface.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Serializer;
12 |
13 | /**
14 | * @author Hannes Schulz
15 | */
16 | interface SerializerInterface
17 | {
18 | /**
19 | * @param mixed $data
20 | * @param string $format
21 | * @param SerializationContext|null $context
22 | *
23 | * @return string
24 | */
25 | public function serialize($data, $format, SerializationContext $context = null);
26 |
27 | /**
28 | * @param string $data
29 | * @param string $type
30 | * @param string $format
31 | * @param DeserializationContext|null $context
32 | *
33 | * @return mixed
34 | */
35 | public function deserialize($data, $type, $format, DeserializationContext $context = null);
36 | }
--------------------------------------------------------------------------------
/Resources/config/services/default_jobs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/Entity/DetachingJobManager.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Entity;
12 |
13 | use Abc\Bundle\JobBundle\Model\JobInterface;
14 |
15 | /**
16 | * @author Hannes Schulz
17 | */
18 | class DetatchingJobManager extends JobManager
19 | {
20 | /**
21 | * @var JobInterface
22 | */
23 | private $current;
24 |
25 | /**
26 | * @inheritdoc
27 | */
28 | public function save(JobInterface $job, $andFlush = true)
29 | {
30 | $this->objectManager->persist($job);
31 | if ($andFlush) {
32 | $this->objectManager->flush();
33 | if ($this->current != null && $this->current !== $job) {
34 | $this->objectManager->detach($this->current);
35 | }
36 | $this->current = $job;
37 | }
38 | }
39 | }
--------------------------------------------------------------------------------
/Job/Exception/ValidationFailedException.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Job\Exception;
12 |
13 | use Symfony\Component\Validator\ConstraintViolationListInterface;
14 |
15 | /**
16 | * @author Hannes Schulz
17 | */
18 | class ValidationFailedException extends \RuntimeException
19 | {
20 | /**
21 | * @var ConstraintViolationListInterface
22 | */
23 | private $list;
24 |
25 | public function __construct(ConstraintViolationListInterface $list)
26 | {
27 | parent::__construct(sprintf('Validation failed with %d error(s).', count($list)));
28 |
29 | $this->list = $list;
30 | }
31 |
32 | /**
33 | * @return ConstraintViolationListInterface
34 | */
35 | public function getConstraintViolationList()
36 | {
37 | return $this->list;
38 | }
39 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2016 Hannes Schulz
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is furnished
8 | to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
--------------------------------------------------------------------------------
/Tests/Entity/ScheduleTest.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Entity;
12 |
13 | use Abc\Bundle\JobBundle\Entity\Schedule;
14 | use PHPUnit\Framework\TestCase;
15 |
16 | /**
17 | * @author Hannes Schulz
18 | */
19 | class ScheduleTest extends TestCase
20 | {
21 | public function testClone()
22 | {
23 | $schedule = new Schedule();
24 | $schedule->setCreatedAt(new \DateTime);
25 | $schedule->setUpdatedAt(new \DateTime);
26 | $schedule->setScheduledAt(new \DateTime);
27 |
28 | $ref = new \ReflectionClass($schedule);
29 | $property = $ref->getProperty('id');
30 | $property->setAccessible(true);
31 | $property->setValue($schedule, 1);
32 |
33 | $clone = clone $schedule;
34 |
35 | $this->assertNull($clone->getId());
36 | }
37 | }
--------------------------------------------------------------------------------
/Validator/Constraints/StatusValidator.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Validator\Constraints;
12 |
13 | use Symfony\Component\Validator\Constraint;
14 | use Symfony\Component\Validator\ConstraintValidator;
15 | use Abc\Bundle\JobBundle\Job\Status as JobStatus;
16 |
17 | /**
18 | * @author Hannes Schulz
19 | */
20 | class StatusValidator extends ConstraintValidator
21 | {
22 | /**
23 | * {@inheritdoc}
24 | */
25 | public function validate($value, Constraint $constraint)
26 | {
27 | if(null === $value) {
28 | return;
29 | }
30 |
31 | if(!in_array($value, JobStatus::values())){
32 | $this->context->buildViolation($constraint->message)
33 | ->setParameter('{{string}}', $value)
34 | ->addViolation();
35 | }
36 | }
37 | }
--------------------------------------------------------------------------------
/Event/ExecutionEvent.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Event;
12 |
13 | use Abc\Bundle\JobBundle\Job\Context\ContextInterface;
14 | use Abc\Bundle\JobBundle\Job\JobInterface;
15 |
16 | /**
17 | * @author Hannes Schulz
18 | */
19 | class ExecutionEvent extends TerminationEvent
20 | {
21 | /**
22 | * @var ContextInterface
23 | */
24 | protected $context;
25 |
26 | /**
27 | * @param JobInterface $job
28 | * @param ContextInterface $context
29 | */
30 | function __construct(JobInterface $job, ContextInterface $context)
31 | {
32 | parent::__construct($job);
33 |
34 | $this->context = $context;
35 | }
36 |
37 | /**
38 | * @return ContextInterface
39 | */
40 | public function getContext()
41 | {
42 | return $this->context;
43 | }
44 | }
--------------------------------------------------------------------------------
/Entity/Log.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Entity;
12 |
13 | use Abc\Bundle\JobBundle\Model\Log as BaseLog;
14 |
15 | /**
16 | * @author Hannes Schulz
17 | */
18 | class Log extends BaseLog
19 | {
20 | /**
21 | * @var mixed
22 | */
23 | protected $id;
24 |
25 | /**
26 | * @var string
27 | */
28 | protected $jobTicket;
29 |
30 | /**
31 | * @return integer
32 | */
33 | public function getId()
34 | {
35 | return $this->id;
36 | }
37 |
38 | /**
39 | * @return string
40 | */
41 | public function getJobTicket()
42 | {
43 | return $this->jobTicket;
44 | }
45 |
46 | /**
47 | * @param string $jobTicket
48 | */
49 | public function setJobTicket($jobTicket)
50 | {
51 | $this->jobTicket = $jobTicket;
52 | }
53 | }
--------------------------------------------------------------------------------
/Resources/config/services/logger.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | %abc.job.logger.storage.level%
13 | %abc.job.logger.storage.bubble%
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/Tests/Fixtures/Job/LoggerAwareJob.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Fixtures\Job;
12 |
13 | use Psr\Log\LoggerAwareInterface;
14 | use Psr\Log\LoggerInterface;
15 |
16 | /**
17 | * @author Hannes Schulz
18 | */
19 | class LoggerAwareJob implements LoggerAwareInterface
20 | {
21 | /**
22 | * @var LoggerInterface
23 | */
24 | private $logger;
25 |
26 | /**
27 | * @return LoggerInterface
28 | */
29 | public function getLogger()
30 | {
31 | return $this->logger;
32 | }
33 |
34 | /**
35 | * {@inheritdoc}
36 | */
37 | public function setLogger(LoggerInterface $logger)
38 | {
39 | $this->logger = $logger;
40 | }
41 |
42 | /**
43 | * @return string Returns the string 'foobar'
44 | */
45 | public function execute()
46 | {
47 | return 'foobar';
48 | }
49 | }
--------------------------------------------------------------------------------
/Tests/Entity/JobTest.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Entity;
12 |
13 | use Abc\Bundle\JobBundle\Entity\Job;
14 | use Abc\Bundle\JobBundle\Entity\Schedule;
15 | use PHPUnit\Framework\TestCase;
16 |
17 | /**
18 | * @author Hannes Schulz
19 | */
20 | class JobTest extends TestCase
21 | {
22 | public function testCreateSchedule()
23 | {
24 | $subject = new Job();
25 | $schedule = $subject->createSchedule('foo', 'bar');
26 |
27 | $this->assertInstanceOf(Schedule::class, $schedule);
28 | $this->assertEquals('foo', $schedule->getType());
29 | $this->assertEquals('bar', $schedule->getExpression());
30 | }
31 |
32 | public function testClone()
33 | {
34 | $job = new Job;
35 | $job->setTicket('ticket');
36 |
37 | $clone = clone $job;
38 |
39 | $this->assertTrue($job !== $clone);
40 | }
41 | }
--------------------------------------------------------------------------------
/Tests/Locker/NullLockerTest.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Locker;
12 |
13 | use Abc\Bundle\JobBundle\Locker\NullLocker;
14 | use Abc\Bundle\ResourceLockBundle\Model\LockInterface;
15 | use PHPUnit\Framework\TestCase;
16 |
17 | /**
18 | * @author Hannes Schulz
19 | */
20 | class NullLockerTest extends TestCase
21 | {
22 | /**
23 | * @var NullLocker
24 | */
25 | private $subject;
26 |
27 | /**
28 | * {@inheritdoc}
29 | */
30 | public function setUp()
31 | {
32 | $this->subject = new NullLocker();
33 | }
34 |
35 | public function testNullLockerDoesNothing()
36 | {
37 | $this->assertInstanceOf(LockInterface::class, $this->subject);
38 | $this->assertFalse($this->subject->isLocked('foobar'));
39 | $this->subject->release('barfoo');
40 | $this->subject->lock('foobar');
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/DependencyInjection/Compiler/RegisterEventListenersPass.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\DependencyInjection\Compiler;
12 |
13 | use \Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass as BaseRegisterListenersPass;
14 |
15 | /**
16 | * @author Hannes Schulz
17 | */
18 | class RegisterEventListenersPass extends BaseRegisterListenersPass
19 | {
20 | /**
21 | * @param string $dispatcherService Service name of the event dispatcher in processed container
22 | * @param string $listenerTag Tag name used for listener
23 | * @param string $subscriberTag Tag name used for subscribers
24 | */
25 | public function __construct($dispatcherService = 'event_dispatcher', $listenerTag = 'abc.job.event_listener', $subscriberTag = 'abc.job.event_subscriber')
26 | {
27 | parent::__construct($dispatcherService, $listenerTag, $subscriberTag);
28 | }
29 | }
--------------------------------------------------------------------------------
/Model/ScheduleInterface.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Model;
12 |
13 | use Abc\Bundle\SchedulerBundle\Model\ScheduleInterface as BaseScheduleInterface;
14 |
15 | /**
16 | * @author Hannes Schulz
17 | */
18 | interface ScheduleInterface extends BaseScheduleInterface
19 | {
20 | /**
21 | * @param boolean $isActive
22 | */
23 | public function setIsActive($isActive);
24 |
25 | /**
26 | * @return boolean
27 | */
28 | public function getIsActive();
29 |
30 | /**
31 | * @param JobInterface $job
32 | */
33 | public function setJob(JobInterface $job);
34 |
35 | /**
36 | * @return JobInterface
37 | */
38 | public function getJob();
39 |
40 | /**
41 | * @return \DateTime
42 | */
43 | public function getUpdatedAt();
44 |
45 | /**
46 | * @return \DateTime
47 | */
48 | public function getCreatedAt();
49 | }
--------------------------------------------------------------------------------
/Tests/Functional/Controller/JobTypeControllerTest.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Functional\Controller;
12 |
13 | use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
14 |
15 | /**
16 | * @author Hannes Schulz
17 | */
18 | class JobTypeControllerTest extends WebTestCase
19 | {
20 | public function testCgetAction()
21 | {
22 | $client = static::createClient();
23 |
24 | $url = '/api/job-types';
25 |
26 | $client->request(
27 | 'GET',
28 | $url,
29 | array(),
30 | array(),
31 | array('CONTENT_TYPE' => 'application/json'),
32 | null,
33 | 'json'
34 | );
35 |
36 | $this->assertEquals(200, $client->getResponse()->getStatusCode());
37 |
38 | $data = $client->getResponse()->getContent();
39 |
40 | $this->assertContains('abc.mailer', $data);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Job/Queue/Message.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Job\Queue;
12 |
13 | /**
14 | * Message to be exchanged between a queue engine and the job manager
15 | *
16 | * @author Hannes Schulz
17 | */
18 | class Message {
19 |
20 | /**
21 | * @var string
22 | */
23 | protected $type;
24 |
25 | /**
26 | * @var string
27 | */
28 | protected $ticket;
29 |
30 | /**
31 | * @param string $type
32 | * @param string $ticket
33 | */
34 | function __construct($type, $ticket)
35 | {
36 | $this->type = $type;
37 | $this->ticket = $ticket;
38 | }
39 |
40 | /**
41 | * @return string
42 | */
43 | public function getType()
44 | {
45 | return $this->type;
46 | }
47 |
48 | /**
49 | * @return string
50 | */
51 | public function getTicket()
52 | {
53 | return $this->ticket;
54 | }
55 | }
--------------------------------------------------------------------------------
/Logger/Handler/OrmHandlerFactory.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Logger\Handler;
12 |
13 | use Abc\Bundle\JobBundle\Job\JobInterface;
14 | use Abc\Bundle\JobBundle\Model\LogManagerInterface;
15 |
16 | /**
17 | * @author Hannes Schulz
18 | */
19 | class OrmHandlerFactory extends BaseHandlerFactory
20 | {
21 | /**
22 | * @var LogManagerInterface
23 | */
24 | protected $manager;
25 |
26 | /**
27 | * @param LogManagerInterface $manager
28 | */
29 | public function __construct(LogManagerInterface $manager)
30 | {
31 | $this->manager = $manager;
32 | }
33 |
34 | /**
35 | * {@inheritdoc}
36 | */
37 | public function createHandler(JobInterface $job, $level, $bubble)
38 | {
39 | $handler = new JobAwareOrmHandler($this->manager, $level, $bubble);
40 | $handler->setJob($job);
41 |
42 | return $this->initHandler($handler);
43 | }
44 | }
--------------------------------------------------------------------------------
/Tests/Fixtures/Annotation/AnnotatedJob.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Fixtures\Annotation;
12 |
13 | use Abc\Bundle\JobBundle\Annotation\ParamType;
14 | use Abc\Bundle\JobBundle\Annotation\ReturnType;
15 |
16 | /**
17 | * @author Hannes Schulz
18 | */
19 | class AnnotatedJob
20 | {
21 | /**
22 | * @ParamType("param", type="string")
23 | * @param $param
24 | */
25 | public function methodWithSingleParameters($param)
26 | {
27 | }
28 |
29 | /**
30 | * @ParamType("param1", type="string", options={})
31 | * @ParamType("param2", type="boolean", options={"groups"={"group1"}})
32 | * @param $param1
33 | * @param $param2
34 | */
35 | public function methodWithMultipleParameters($param1, $param2)
36 | {
37 | }
38 |
39 | /**
40 | * @ReturnType("string", options={})
41 | */
42 | public function methodWithResponse()
43 | {
44 | }
45 | }
--------------------------------------------------------------------------------
/Tests/Fixtures/Job/ControllerAwareJob.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Fixtures\Job;
12 |
13 | use Abc\ProcessControl\ControllerAwareInterface;
14 | use Abc\ProcessControl\ControllerInterface;
15 |
16 | /**
17 | * @author Hannes Schulz
18 | */
19 | class ControllerAwareJob implements ControllerAwareInterface
20 | {
21 | /**
22 | * @var ControllerInterface
23 | */
24 | private $controller;
25 |
26 | /**
27 | * {@inheritdoc}
28 | */
29 | public function setController(ControllerInterface $controller)
30 | {
31 | $this->controller = $controller;
32 | }
33 |
34 | /**
35 | * @return ControllerInterface
36 | */
37 | public function getController()
38 | {
39 | return $this->controller;
40 | }
41 |
42 | /**
43 | * @return string
44 | */
45 | public function execute()
46 | {
47 | return 'foobar';
48 | }
49 | }
--------------------------------------------------------------------------------
/DependencyInjection/Compiler/ConfigurationCheckPass.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\DependencyInjection\Compiler;
12 |
13 | use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
14 | use Symfony\Component\DependencyInjection\ContainerBuilder;
15 |
16 | /**
17 | * Checks if dependent bundles are properly configured.
18 | *
19 | * @author Hannes Schulz
20 | */
21 | final class ConfigurationCheckPass implements CompilerPassInterface
22 | {
23 | public function process(ContainerBuilder $container)
24 | {
25 | // DoctrineBundle
26 | if(!$container->has('doctrine')) {
27 | throw new \RuntimeException('You need to enable the DoctrineBundle');
28 | }
29 |
30 | // AbcSchedulerBundle
31 | if(!$container->has('abc.scheduler.scheduler')) {
32 | throw new \RuntimeException('You need to enable the AbcSchedulerBundle');
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/Tests/Fixtures/App/Bundle/TestBundle/DependencyInjection/TestExtension.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Fixtures\App\Bundle\TestBundle\DependencyInjection;
12 |
13 | use Symfony\Component\Config\FileLocator;
14 | use Symfony\Component\DependencyInjection\ContainerBuilder;
15 | use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
16 | use Symfony\Component\HttpKernel\DependencyInjection\Extension;
17 |
18 | /**
19 | * @author Hannes Schulz
20 | */
21 | class TestExtension extends Extension
22 | {
23 | /**
24 | * {@inheritDoc}
25 | */
26 | public function load(array $configs, ContainerBuilder $container)
27 | {
28 | $configuration = new Configuration();
29 | $config = $this->processConfiguration($configuration, $configs);
30 |
31 | /*$loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
32 | $loader->load('services.xml');*/
33 | }
34 | }
--------------------------------------------------------------------------------
/Tests/Fixtures/App/app/config/services.yml:
--------------------------------------------------------------------------------
1 | services:
2 |
3 | abc.job.callable:
4 | class: Abc\Bundle\JobBundle\Tests\Fixtures\Job\TestJob
5 | calls:
6 | - [ setContainer, [ '@service_container' ] ]
7 | tags:
8 | - { name: abc.job, type: log, method: log }
9 | - { name: abc.job, type: throw_exception, method: throwException }
10 | - { name: abc.job, type: set_response, method: setResponse }
11 | - { name: abc.job, type: schedule, method: schedule }
12 | - { name: abc.job, type: create_schedule, method: createSchedule }
13 | - { name: abc.job, type: remove_schedule, method: removeSchedule }
14 | - { name: abc.job, type: update_schedule, method: updateSchedule }
15 | - { name: abc.job, type: manage_job, method: manageJob }
16 | - { name: abc.job, type: cancel, method: cancel }
17 | - { name: abc.job, type: parameterless, method: parameterless }
18 | - { name: abc.job, type: throw_dbal_exception, method: throwDbalException }
19 |
20 | abc.job.log.processor:
21 | class: Monolog\Processor\PsrLogMessageProcessor
22 | tags:
23 | - { name: monolog.processor, handler: abc_job }
--------------------------------------------------------------------------------
/Tests/Fixtures/Job/JobAwareJob.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Fixtures\Job;
12 |
13 | use Abc\Bundle\JobBundle\Job\Job;
14 | use Abc\Bundle\JobBundle\Job\JobAwareInterface;
15 | use Abc\Bundle\JobBundle\Job\JobInterface;
16 |
17 | /**
18 | * @author Hannes Schulz
19 | */
20 | class JobAwareJob implements JobAwareInterface
21 | {
22 | /** @var JobInterface */
23 | protected $job;
24 |
25 | public static function getMethodName()
26 | {
27 | return 'execute';
28 | }
29 |
30 | /**
31 | * @param mixed $job
32 | */
33 | public function setJob(JobInterface $job)
34 | {
35 | $this->job = $job;
36 | }
37 |
38 | /**
39 | * @return JobInterface
40 | */
41 | public function getJob()
42 | {
43 | return $this->job;
44 | }
45 |
46 | /**
47 | * @return string
48 | */
49 | public function execute()
50 | {
51 | return 'foobar';
52 | }
53 | }
--------------------------------------------------------------------------------
/Api/ParameterConstraintViolation.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Api;
12 |
13 | use JMS\Serializer\Annotation\Type;
14 |
15 | /**
16 | * @author Hannes Schulz
17 | */
18 | class ParameterConstraintViolation
19 | {
20 | /**
21 | * @Type("string")
22 | * @var string
23 | */
24 | protected $name;
25 |
26 | /**
27 | * @Type("string")
28 | * @var string
29 | */
30 | protected $message;
31 |
32 | /**
33 | * @param string $name
34 | * @param string $message
35 | */
36 | public function __construct($name, $message)
37 | {
38 | $this->name = $name;
39 | $this->message = $message;
40 | }
41 |
42 | /**
43 | * @return string
44 | */
45 | public function getName()
46 | {
47 | return $this->name;
48 | }
49 |
50 | /**
51 | * @return string
52 | */
53 | public function getMessage()
54 | {
55 | return $this->message;
56 | }
57 | }
--------------------------------------------------------------------------------
/Logger/Handler/HandlerFactoryInterface.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Logger\Handler;
12 |
13 | use Abc\Bundle\JobBundle\Job\JobInterface;
14 | use Monolog\Formatter\FormatterInterface;
15 | use Monolog\Handler\HandlerInterface;
16 |
17 | /**
18 | * @author Hannes Schulz
19 | */
20 | interface HandlerFactoryInterface
21 | {
22 | /**
23 | * @param JobInterface $job
24 | * @param int $level The minimum logging level at which this handler will be triggered
25 | * @param boolean $bubble
26 | * @return HandlerInterface
27 | */
28 | public function createHandler(JobInterface $job, $level, $bubble);
29 |
30 | /**
31 | * @param FormatterInterface $formatter
32 | * @return void
33 | */
34 | public function setFormatter(FormatterInterface $formatter = null);
35 |
36 | /**
37 | * @param array $processors
38 | * @return void
39 | */
40 | public function setProcessors(array $processors);
41 | }
--------------------------------------------------------------------------------
/Tests/Fixtures/Job/ManagerAwareJob.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Fixtures\Job;
12 |
13 | use Abc\Bundle\JobBundle\Job\ManagerAwareInterface;
14 | use Abc\Bundle\JobBundle\Job\ManagerInterface;
15 | use Psr\Log\LoggerInterface;
16 | use Abc\Bundle\JobBundle\Annotation\ParamType;
17 |
18 | /**
19 | * @author Hannes Schulz
20 | */
21 | class ManagerAwareJob implements ManagerAwareInterface
22 | {
23 | /**
24 | * @var ManagerInterface
25 | */
26 | private $manager;
27 |
28 | /**
29 | * {@inheritdoc}
30 | */
31 | public function setManager(ManagerInterface $manager)
32 | {
33 | $this->manager = $manager;
34 | }
35 |
36 | /**
37 | * @return ManagerInterface
38 | */
39 | public function getManager()
40 | {
41 | return $this->manager;
42 | }
43 |
44 | /**
45 | * @return string
46 | */
47 | public function execute()
48 | {
49 | return 'foobar';
50 | }
51 | }
--------------------------------------------------------------------------------
/Tests/Adapter/Sonata/Fixtures/TestIterator.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Adapter\Sonata\Fixtures;
12 |
13 | use Sonata\NotificationBundle\Iterator\MessageIteratorInterface;
14 |
15 | /**
16 | * @author Hannes Schulz
17 | */
18 | class TestIterator implements MessageIteratorInterface
19 | {
20 | private $position = 0;
21 | private $array;
22 |
23 | public function __construct(array $elements)
24 | {
25 | $this->position = 0;
26 | $this->array = $elements;
27 | }
28 |
29 | function rewind()
30 | {
31 | $this->position = 0;
32 | }
33 |
34 | function current()
35 | {
36 | return $this->array[$this->position];
37 | }
38 |
39 | function key()
40 | {
41 | return $this->position;
42 | }
43 |
44 | function next()
45 | {
46 | ++$this->position;
47 | }
48 |
49 | function valid()
50 | {
51 | return isset($this->array[$this->position]);
52 | }
53 | }
--------------------------------------------------------------------------------
/Logger/Handler/JobAwareOrmHandler.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Logger\Handler;
12 |
13 | use Abc\Bundle\JobBundle\Job\JobAwareInterface;
14 | use Abc\Bundle\JobBundle\Job\JobInterface;
15 |
16 | /**
17 | * @author Hannes Schulz
18 | */
19 | class JobAwareOrmHandler extends OrmHandler implements JobAwareInterface
20 | {
21 | /**
22 | * @var JobInterface
23 | */
24 | protected $job;
25 |
26 | /**
27 | * {@inheritdoc}
28 | */
29 | public function setJob(JobInterface $job)
30 | {
31 | $this->job = $job;
32 | }
33 |
34 | /**
35 | * Sets the job ticket in $record['extra']['job_ticket']
36 | *
37 | * {@inheritdoc}
38 | */
39 | protected function write(array $record)
40 | {
41 | $log = $this->manager->create();
42 |
43 | $record['extra']['job_ticket'] = $this->job->getTicket();
44 |
45 | $this->populateLog($log, $record);
46 |
47 | $this->manager->save($log);
48 | }
49 | }
--------------------------------------------------------------------------------
/Resources/docs/scheduled-jobs.md:
--------------------------------------------------------------------------------
1 | Scheduled Jobs
2 | ==============
3 |
4 | You can define one or more schedules for a job in order to configure repeated execution of a job. The bundle relies on the [AbcSchedulerBundle](https://github.org/aboutcoders/scheduler-bundle) to provide this functionality.
5 |
6 | ## Creating a job with schedules
7 |
8 | If you want to create a job with one or more schedules the recommended way is to use the `JobBuilder`:
9 |
10 | ```php
11 | use Abc\Bundle\JobBundle\Job\JobBuilder;
12 |
13 | $job = JobBuilder::create('my_job')
14 | ->addSchedule('cron', '1 * * * *')
15 | ->addSchedule('cron', '30 * * * *')
16 | ->build();
17 | ```
18 |
19 | ## Creating a schedule
20 |
21 | If you want to create a schedule the recommended way is to use the `ScheduleBuilder`:
22 |
23 | ```php
24 | use Abc\Bundle\JobBundle\Job\ScheduleBuilder;
25 |
26 | $schedule = ScheduleBuilder::create('cron', '1 * * * *');
27 | ```
28 |
29 | ## Removing a schedule
30 |
31 | You can remove previously added schedules from a job:
32 |
33 | ```php
34 | $job->removeSchedule($schedule);
35 | ```
36 |
37 | If you want to add or remove schedules during the execution of the job please refer to the section [Managing a job at runtime](./job-management.md).
38 |
39 | Back to [index](../../README.md)
--------------------------------------------------------------------------------
/Serializer/Serializer.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Serializer;
12 |
13 | use JMS\Serializer\SerializerInterface as JMSSerializerInterface;
14 |
15 | /**
16 | * @author Hannes Schulz
17 | */
18 | class Serializer implements SerializerInterface
19 | {
20 | /**
21 | * @var JMSSerializerInterface
22 | */
23 | private $serializer;
24 |
25 | public function __construct(JMSSerializerInterface $serializer)
26 | {
27 | $this->serializer = $serializer;
28 | }
29 |
30 | /**
31 | * {@inheritdoc}
32 | */
33 | public function serialize($data, $format, SerializationContext $context = null)
34 | {
35 | return $this->serializer->serialize($data, $format, $context);
36 | }
37 |
38 | /**
39 | * {@inheritdoc}
40 | */
41 | public function deserialize($data, $type, $format, DeserializationContext $context = null)
42 | {
43 | return $this->serializer->deserialize($data, $type, $format, $context);
44 | }
45 | }
--------------------------------------------------------------------------------
/Model/AbstractList.php:
--------------------------------------------------------------------------------
1 |
9 | * @author Wojciech Ciolko
10 | */
11 | abstract class AbstractList implements AbstractListInterface
12 | {
13 | /**
14 | * @JMS\Type("array")
15 | * @JMS\SerializedName("items")
16 | * @var array[Entity]
17 | */
18 | protected $items;
19 |
20 | /**
21 | * @JMS\Type("integer")
22 | * @JMS\SerializedName("totalCount")
23 | * @var int
24 | */
25 | protected $totalCount;
26 |
27 | /**
28 | * @return mixed
29 | */
30 | public function getItems()
31 | {
32 | return $this->items;
33 | }
34 |
35 | /**
36 | * @param mixed $items
37 | */
38 | public function setItems($items)
39 | {
40 | $this->items = $items;
41 | }
42 |
43 | /**
44 | * @return int
45 | */
46 | public function getTotalCount()
47 | {
48 | return $this->totalCount;
49 | }
50 |
51 | /**
52 | * @param int $totalTotalCount
53 | */
54 | public function setTotalCount($totalTotalCount)
55 | {
56 | $this->totalCount = $totalTotalCount;
57 | }
58 | }
--------------------------------------------------------------------------------
/Resources/config/services/listener.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Resources/config/services/logger_storage_orm.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 | Abc\Bundle\JobBundle\Logger\Entity\Log
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | %abc.job.model.log.class%
20 |
21 |
22 |
23 |
24 | %abc.job.model_manager_name%
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/Job/ExceptionResponse.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Job;
12 |
13 | use JMS\Serializer\Annotation\Type;
14 |
15 | /**
16 | * Response of a job if an exception was thrown during job execution.
17 | *
18 | * @author Hannes Schulz
19 | */
20 | class ExceptionResponse
21 | {
22 | /**
23 | * @Type("integer")
24 | * @var int
25 | */
26 | protected $code;
27 |
28 | /**
29 | * @Type("string")
30 | * @var string
31 | */
32 | protected $message;
33 |
34 | /**
35 | * @param \Exception $e
36 | */
37 | function __construct(\Exception $e)
38 | {
39 | $this->code = $e->getCode();
40 | $this->message = $e->getMessage();
41 | }
42 |
43 | /**
44 | * @return int The exception code
45 | */
46 | public function getCode()
47 | {
48 | return $this->code;
49 | }
50 |
51 | /**
52 | * @return string The exception message
53 | */
54 | public function getMessage()
55 | {
56 | return $this->message;
57 | }
58 | }
--------------------------------------------------------------------------------
/Tests/Job/Queue/QueueConfigTest.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Job\Queue;
12 |
13 | use Abc\Bundle\JobBundle\Job\Queue\QueueConfig;
14 | use PHPUnit\Framework\TestCase;
15 |
16 | /**
17 | * @author Hannes Schulz
18 | */
19 | class QueueConfigTest extends TestCase
20 | {
21 |
22 | public function testWithDefaultConstructor() {
23 | $subject = new QueueConfig();
24 |
25 | $this->assertEquals('default', $subject->getDefaultQueue());
26 | $this->assertEquals('default', $subject->getQueue('foobar'));
27 | }
28 |
29 | public function testWithConfig() {
30 | $subject = new QueueConfig([
31 | 'queueA' => ['typeA'],
32 | 'queueB' => ['typeB']
33 | ], 'custom');
34 |
35 | $this->assertEquals('custom', $subject->getDefaultQueue());
36 | $this->assertEquals('queueA', $subject->getQueue('typeA'));
37 | $this->assertEquals('queueB', $subject->getQueue('typeB'));
38 | $this->assertEquals('custom', $subject->getQueue('foobar'));
39 | }
40 | }
--------------------------------------------------------------------------------
/Controller/JobTypeController.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Controller;
12 |
13 | use Nelmio\ApiDocBundle\Annotation\Operation;
14 | use Nelmio\ApiDocBundle\Annotation\Model;
15 | use Swagger\Annotations as SWG;
16 | use Symfony\Component\HttpFoundation\Response;
17 |
18 | /**
19 | * @author Hannes Schulz
20 | */
21 | class JobTypeController extends BaseController
22 | {
23 | /**
24 | * @Operation(
25 | * tags={"AbcJobBundle"},
26 | * summary="Returns a collection of job types",
27 | * @SWG\Response(
28 | * response="200",
29 | * description="Returned when successful",
30 | * @SWG\Schema(
31 | * type="array",
32 | * @SWG\Items(
33 | * type="string"
34 | * )
35 | * )
36 | * )
37 | * )
38 | * @return Response
39 | */
40 | public function listAction()
41 | {
42 | return $this->serialize($this->getRegistry()->getTypeChoices());
43 | }
44 |
45 | }
--------------------------------------------------------------------------------
/Test/WebTestCase.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Test;
12 |
13 | use Symfony\Component\HttpKernel\KernelInterface;
14 | use Symfony\Bundle\FrameworkBundle\Test\WebTestCase as BaseWebTestCase;
15 |
16 | /**
17 | * @author Hannes Schulz
18 | */
19 | abstract class WebTestCase extends BaseWebTestCase
20 | {
21 | /**
22 | * Replaces services with mock instances
23 | *
24 | * @param array $services An associative array with the service id as key and the service instance as value
25 | * @see http://blog.lyrixx.info/2013/04/12/symfony2-how-to-mock-services-during-functional-tests.html
26 | */
27 | protected function mockServices(array $services)
28 | {
29 | /**
30 | * @ignore
31 | */
32 | static::$kernel->setKernelModifier(
33 | function (KernelInterface $kernel) use ($services) {
34 | foreach ($services as $id => $service) {
35 | $kernel->getContainer()->set($id, $service);
36 | }
37 | }
38 | );
39 | }
40 | }
--------------------------------------------------------------------------------
/Adapter/Bernard/ConsumerAdapter.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Adapter\Bernard;
12 |
13 | use Abc\Bundle\JobBundle\Job\Queue\ConsumerInterface;
14 | use Bernard\Consumer;
15 | use Bernard\QueueFactory;
16 |
17 | /**
18 | * @author Hannes Schulz
19 | */
20 | class ConsumerAdapter implements ConsumerInterface
21 | {
22 | /**
23 | * @var Consumer
24 | */
25 | private $consumer;
26 |
27 | /**
28 | * @var QueueFactory;
29 | */
30 | private $queueFactory;
31 |
32 | /**
33 | * @param Consumer $consumer
34 | * @param QueueFactory $queueFactory
35 | */
36 | public function __construct(Consumer $consumer, QueueFactory $queueFactory)
37 | {
38 | $this->consumer = $consumer;
39 | $this->queueFactory = $queueFactory;
40 | }
41 |
42 | /**
43 | * {@inheritdoc}
44 | */
45 | public function consume($queue, array $options = [])
46 | {
47 | $queue = $this->queueFactory->create($queue);
48 |
49 | $this->consumer->consume($queue, $options);
50 | }
51 | }
--------------------------------------------------------------------------------
/Resources/docs/process-control.md:
--------------------------------------------------------------------------------
1 | Process Control
2 | ===============
3 |
4 | The AbcJobBundle integrates the [process control](https://github.com/aboutcoders/process-control) library and thereby makes it possible to inform jobs about external events such as process termination signals or [manual cancellation](./cancel-jobs.md) of the job.
5 |
6 | By default jobs are only informed if they have been [cancelled manually](./cancel-jobs.md) by the user. In order to also inform jobs about process signals sent to the long running [consumer commands](./message-consuming.md) you have to install the [AbcProcessControlBundle](https://github.com/aboutcoders/process-control-bundle).
7 |
8 | ## Process Control and SonataNotificationBundle
9 |
10 | If you are using the AbcJobBundle together with the [SonataNotificationBundle](https://github.com/sonata-project/SonataNotificationBundle) as message queue backend we recommend to also install the [AbcNotificationBundle](https://github.com/aboutcoders/notification-bundle). This bundle inherits from the [SonataNotificationBundle](https://github.com/sonata-project/SonataNotificationBundle) and integrates process control more deeply into [SonataNotificationBundle](https://github.com/sonata-project/SonataNotificationBundle) and thereby allows an even better control of [message consuming](./message-consuming.md).
11 |
12 | Back to [index](../../README.md)
--------------------------------------------------------------------------------
/Resources/config/doctrine-mapping/Log.orm.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Tests/Fixtures/App/Bundle/TestBundle/Entity/Entity.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Fixtures\App\Bundle\TestBundle\Entity;
12 |
13 | use Doctrine\ORM\Mapping as ORM;
14 |
15 | /**
16 | * @ORM\Table(name="abc_test_entity")
17 | * @ORM\Entity
18 | * @author Hannes Schulz
19 | */
20 | class Entity
21 | {
22 | /**
23 | * @ORM\Id
24 | * @ORM\Column(type="integer")
25 | * @ORM\GeneratedValue(strategy="AUTO")
26 | * @var integer
27 | */
28 | private $id;
29 |
30 | /**
31 | * @ORM\Column(name="name", type="string", unique=true)
32 | * @var string
33 | */
34 | protected $name;
35 |
36 | /**
37 | * Get id
38 | *
39 | * @return integer
40 | */
41 | public function getId()
42 | {
43 | return $this->id;
44 | }
45 |
46 | /**
47 | * @return string
48 | */
49 | public function getName()
50 | {
51 | return $this->name;
52 | }
53 |
54 | /**
55 | * @param string $name
56 | */
57 | public function setName($name)
58 | {
59 | $this->name = $name;
60 | }
61 | }
--------------------------------------------------------------------------------
/Validator/Constraints/JobTypeValidator.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Validator\Constraints;
12 |
13 | use Abc\Bundle\JobBundle\Job\JobTypeRegistry;
14 | use Symfony\Component\Validator\Constraint;
15 | use Symfony\Component\Validator\ConstraintValidator;
16 |
17 | /**
18 | * @author Hannes Schulz
19 | */
20 | class JobTypeValidator extends ConstraintValidator
21 | {
22 | /**
23 | * @var JobTypeRegistry
24 | */
25 | private $registry;
26 |
27 | /**
28 | * @param JobTypeRegistry $registry
29 | */
30 | public function __construct(JobTypeRegistry $registry)
31 | {
32 | $this->registry = $registry;
33 | }
34 |
35 | /**
36 | * {@inheritdoc}
37 | */
38 | public function validate($value, Constraint $constraint)
39 | {
40 | if (null === $value) {
41 | return;
42 | }
43 |
44 |
45 | if (!$this->registry->has($value)) {
46 | $this->context->buildViolation($constraint->message)
47 | ->setParameter('{{string}}', $value)
48 | ->addViolation();
49 | }
50 | }
51 | }
--------------------------------------------------------------------------------
/Resources/config/doctrine/Schedule.orm.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/Entity/Job.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Entity;
12 |
13 | use Abc\Bundle\JobBundle\Doctrine\Job as BaseJob;
14 | use Abc\Bundle\SchedulerBundle\Model\ScheduleInterface;
15 |
16 | /**
17 | * @author Hannes Schulz
18 | */
19 | class Job extends BaseJob
20 | {
21 | /**
22 | * {@inheritdoc}
23 | */
24 | public function createSchedule($type, $expression)
25 | {
26 | return new Schedule($type, $expression);
27 | }
28 |
29 | /**
30 | * {@inheritdoc}
31 | */
32 | public function addSchedule(ScheduleInterface $schedule)
33 | {
34 | if(!$schedule instanceof Schedule)
35 | {
36 | $schedule = new Schedule($schedule->getType(), $schedule->getExpression());
37 | }
38 |
39 | $schedule->setJob($this);
40 |
41 | parent::addSchedule($schedule);
42 | }
43 |
44 | /**
45 | * {@inheritdoc}
46 | */
47 | public function removeSchedule(ScheduleInterface $schedule)
48 | {
49 | if($schedule instanceof Schedule)
50 | {
51 | $schedule->setJob(null);
52 | }
53 |
54 | parent::removeSchedule($schedule);
55 | }
56 | }
--------------------------------------------------------------------------------
/Job/Parameter/DefaultJobsConstraintProvider.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Job\Parameter;
12 |
13 | use Abc\Bundle\JobBundle\Validator\Job\AbstractConstraintProvider;
14 | use Symfony\Component\Validator\Constraints as Assert;
15 |
16 | /**
17 | * @author Hannes Schulz
18 | */
19 | class DefaultJobsConstraintProvider extends AbstractConstraintProvider
20 | {
21 | /**
22 | * {@inheritdoc}
23 | */
24 | public function getConstraints($type)
25 | {
26 | switch ($type) {
27 | case 'abc.mailer':
28 | return $this->provideMailerConstraints();
29 | break;
30 | case 'abc.sleeper':
31 | return $this->provideSleeperConstraints();
32 | break;
33 | }
34 |
35 | return null;
36 | }
37 |
38 | /**
39 | * @return array
40 | */
41 | protected function provideMailerConstraints()
42 | {
43 | return [new Assert\NotBlank()];
44 | }
45 |
46 | /**
47 | * @return array
48 | */
49 | protected function provideSleeperConstraints()
50 | {
51 | return [new Assert\Range(['min' => 1])];
52 | }
53 | }
--------------------------------------------------------------------------------
/Resources/config/services/serializer.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/Validator/Constraints/JobValidator.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Validator\Constraints;
12 |
13 | use Abc\Bundle\JobBundle\Job\JobInterface;
14 | use Symfony\Component\Validator\Constraint;
15 | use Symfony\Component\Validator\ConstraintValidator;
16 | use Abc\Bundle\JobBundle\Validator\Constraints as AssertJob;
17 |
18 | /**
19 | * @author Hannes Schulz
20 | */
21 | class JobValidator extends ConstraintValidator
22 | {
23 | /**
24 | * {@inheritdoc}
25 | */
26 | public function validate($value, Constraint $constraint)
27 | {
28 | if (null === $value) {
29 | return;
30 | }
31 |
32 | if(!$value instanceof JobInterface) {
33 | throw new \InvalidArgumentException('The value must be an instance of '.JobInterface::class);
34 | }
35 |
36 | if(null == $value->getType()) {
37 | return;
38 | }
39 |
40 | $this->context->getValidator()
41 | ->inContext($this->context)
42 | ->atPath('parameters')
43 | ->validate($value->getParameters(), new AssertJob\Parameters(['type' => $value->getType()]));
44 |
45 | return;
46 | }
47 | }
--------------------------------------------------------------------------------
/Resources/docs/message-consuming.md:
--------------------------------------------------------------------------------
1 | Message Consuming
2 | =================
3 |
4 | There are different ways to consume messages from the queues and process the jobs.
5 |
6 | ## Command Line
7 |
8 | The AbcJobBundle provides the symfony command `abc:job:consumer`. The command requires the name of the queue that messages will be consumed from as argument. The following command will consume messages from the `default` queue.
9 |
10 | ```bash
11 | php bin/console abc:job:consume default
12 | ```
13 |
14 | In order to prevent out of memory errors the command should always be invoked with the option `max-iterations`.
15 |
16 | ```bash
17 | php bin/console abc:job:consume default --max-iterations=250
18 | ```
19 |
20 | ## PHP
21 |
22 | The consumer command uses the underlying service `abc.job.consumer` to do its work. You can also use this service to consume and process jobs from the queue.
23 |
24 | ```php
25 | // retrieve job manager from the container
26 | $consumer = $container->get('abc.job.consumer');
27 |
28 | $consumer->consume('default', [
29 | 'max-iterations' => 250
30 | ])
31 | ```
32 |
33 | ## Supervisor
34 |
35 | In a production environment it is recommended to use a process control system like [supervisor](http://supervisord.org/) to monitor consumers and restart a process as soon as it stopped.
36 |
37 | In case you decided to use [supervisor](http://supervisord.org/) you might consider using the [AbcSupervisorBundle](https://github.com/aboutcoders/supervisor-bundle):
38 |
39 | Next Step: [Job Management](./job-management.md)
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | php:
4 | - 7.0
5 | - 7.1
6 |
7 | matrix:
8 | fast_finish: true
9 | include:
10 | - php: 7.1
11 | env: SYMFONY_VERSION=3.3.*
12 | - php: 7.1
13 | env: SYMFONY_VERSION=3.4.*
14 | allow_failures:
15 | - php: 5.6
16 |
17 | sudo: false
18 |
19 | cache:
20 | directories:
21 | - $HOME/.composer/cache
22 |
23 | before_install:
24 | - composer self-update
25 | - if [ "$SYMFONY_VERSION" != "" ]; then composer require --no-update symfony/symfony:"$SYMFONY_VERSION"; fi
26 | - if [ "$TRAVIS_PHP_VERSION" != "hhvm" ]; then echo "memory_limit=3G" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini; fi;
27 |
28 | install:
29 | - composer update $COMPOSER_FLAGS
30 |
31 | script:
32 | - vendor/bin/phpunit --coverage-clover clover
33 |
34 | notifications:
35 | hipchat:
36 | rooms:
37 | secure: uypSLOcHE2VlVWRlZFR0lwlj+1+I/oG10qAa3QA9LnJT6bIDGO9FBrKDvyhOhd/HmufQD35ytvrn2O3JUh9S25arjqoFEg4Or1MDymeUuSH6X1gV+pftDj/EEPTBZVNzpWOw+fCqASCmUsSFt6B9jd0QfnFMDbYKVaCS3Il+53+rRljvlCP55biFXOkHc4lsQ5FDJlal+5nmm8/SxGAN/IVnIfkHdHB+ljVKeU62F4OBLe0IiYvhmrgWt81D64zp96I5XvltvXT960QndIzVdp4rhB0L7GYxFiamiS9AhMcUVS4avlUwLbDtKQDe8VeKPxx2wsGwHD/zwjcs6QLxoyZfyofSRylhZYpuYLy938Wgl95euoA6gqfV4EtaTOkaVB/s1z6NuoAGPUEfFm8OvKJBxEX0/3hOsMdEsk5272WlTNyNRwNf0g2R2wS1y24OUZjSjroxKMZ3D77vX0xnmjzPecLkxpp5vGmNtBtP/eQ6PKwRPMPLBTUPsAlQzgU/BMQ/1WQKG9lBFHP62DXUlORxyZ6FuLat6gDTLayuPXNHoNFgTgnuCCx34n36MBSja1tQxY5ERglmzlk4tRARCCdww2TF0lFmgB00qesIzF0v3pXw/v84lj2r2XJ/cQFYDhZi3YF4VPLVVqxylOeREClWZ/xjYnDK/fm3JJpAf9M=
--------------------------------------------------------------------------------
/Logger/Handler/HandlerFactoryRegistry.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Logger\Handler;
12 |
13 | use Abc\Bundle\JobBundle\Job\JobInterface;
14 | use Monolog\Handler\HandlerInterface;
15 |
16 | /**
17 | * @author Hannes Schulz
18 | */
19 | class HandlerFactoryRegistry
20 | {
21 | /**
22 | * @var array|BaseHandlerFactory[]
23 | */
24 | private $factories = [];
25 |
26 | /**
27 | * @param HandlerFactoryInterface $factory
28 | */
29 | public function register(HandlerFactoryInterface $factory)
30 | {
31 | $this->factories[] = $factory;
32 | }
33 |
34 | /**
35 | * Returns the handlers created by all registered factories.
36 | *
37 | * @param JobInterface $job
38 | * @param int $level The minimum logging level at which this handler will be triggered
39 | * @param boolean $bubble
40 | * @return array|HandlerInterface[] The created handlers
41 | */
42 | public function createHandlers(JobInterface $job, $level, $bubble)
43 | {
44 | $handlers = [];
45 | foreach ($this->factories as $factory) {
46 | $handlers[] = $factory->createHandler($job, $level, $bubble);
47 | }
48 |
49 | return $handlers;
50 | }
51 | }
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
15 |
16 |
17 | ./Tests
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | ./
28 |
29 | ./build
30 | ./Resources
31 | ./Tests
32 | ./vendor
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/Job/Queue/QueueConfig.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Job\Queue;
12 |
13 | /**
14 | * @author Hannes Schulz
15 | */
16 | class QueueConfig implements QueueConfigInterface
17 | {
18 | /**
19 | * @var array
20 | */
21 | private $map;
22 |
23 | /**
24 | * @var string
25 | */
26 | private $defaultQueue;
27 |
28 | /**
29 | * @param array $queueMapping
30 | * @param string $defaultQueue
31 | */
32 | public function __construct(array $queueMapping = [], $defaultQueue = 'default')
33 | {
34 | $this->defaultQueue = $defaultQueue;
35 | foreach ($queueMapping as $queueName => $jobTypes) {
36 | foreach ($jobTypes as $jobType) {
37 | if(!isset($this->map[$jobType])) {
38 | $this->map[$jobType] = $queueName;
39 | }
40 | }
41 | }
42 | }
43 |
44 | /**
45 | * {@inheritdoc}
46 | */
47 | public function getDefaultQueue()
48 | {
49 | return $this->defaultQueue;
50 | }
51 |
52 | /**
53 | * {@inheritdoc}
54 | */
55 | public function getQueue($type)
56 | {
57 | return isset($this->map[$type]) ? $this->map[$type] : $this->defaultQueue;
58 | }
59 | }
--------------------------------------------------------------------------------
/Tests/Job/StatusTest.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Job;
12 |
13 | use Abc\Bundle\JobBundle\Job\Status;
14 | use PHPUnit\Framework\TestCase;
15 |
16 | /**
17 | * @author Hannes Schulz
18 | */
19 | class StatusTest extends TestCase
20 | {
21 | public function testGetTerminatedStatus()
22 | {
23 | $values = [Status::CANCELLED, Status::PROCESSED, Status::ERROR];
24 | foreach (Status::getTerminatedStatus() as $status) {
25 | /**
26 | * @var Status $status
27 | */
28 | $this->assertContains($status->getValue(), $values);
29 | }
30 | }
31 |
32 | public function testGetUnterminatedStatus()
33 | {
34 | $values = [Status::REQUESTED, Status::PROCESSING, Status::CANCELLING, Status::SLEEPING];
35 | foreach (Status::getUnterminatedStatus() as $status) {
36 | /**
37 | * @var Status $status
38 | */
39 | $this->assertContains($status->getValue(), $values);
40 | }
41 | }
42 |
43 | public function testEquals()
44 | {
45 | $this->assertTrue(Status::PROCESSED()->equals(Status::PROCESSED()));
46 | $this->assertFalse(Status::PROCESSED()->equals(Status::CANCELLED()));
47 | }
48 | }
--------------------------------------------------------------------------------
/Tests/Functional/Job/Mailer/MailerTest.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Functional\Job\Mailer;
12 |
13 | use Abc\Bundle\JobBundle\Job\Mailer\Message;
14 | use Abc\Bundle\JobBundle\Test\JobTestCase;
15 |
16 | /**
17 | * @author Hannes Schulz
18 | */
19 | class MailerTest extends JobTestCase
20 | {
21 | public function testRegistration()
22 | {
23 | $this->assertJobIsRegistered('abc.mailer', 'abc.job.mailer', 'send');
24 | }
25 |
26 | public function testInvocation()
27 | {
28 | $message = new Message('mail@domain.tld', 'to@domain.td', 'Subject', 'MessageBody');
29 |
30 | $this->assertInvokesJob('abc.mailer', [$message]);
31 | }
32 |
33 | public function testValidationSucceeds()
34 | {
35 | $message = new Message('mail@domain.tld', 'to@domain.td', 'Subject', 'MessageBody');
36 |
37 | $this->assertTrue($this->assertValid('abc.mailer', [$message]));
38 | }
39 |
40 | public function testValidationFails()
41 | {
42 | $this->markTestSkipped('Skipped, because validation is not performed (need to investigate)');
43 |
44 | $message = new Message(null, 'to@domain.td', 'Subject', 'MessageBody');
45 |
46 | $this->assertTrue($this->assertNotValid('abc.mailer', [$message]));
47 | }
48 | }
--------------------------------------------------------------------------------
/Logger/Handler/StreamHandlerFactory.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Logger\Handler;
12 |
13 | use Abc\Bundle\JobBundle\Job\JobInterface;
14 | use Monolog\Handler\StreamHandler;
15 |
16 | /**
17 | * @author Hannes Schulz
18 | */
19 | class StreamHandlerFactory extends BaseHandlerFactory
20 | {
21 | /**
22 | * @var string
23 | */
24 | protected $path;
25 |
26 | /**
27 | * @var string
28 | */
29 | protected $extension;
30 |
31 | /**
32 | * @param string $path
33 | * @param string $extension
34 | */
35 | public function __construct($path, $extension = 'log')
36 | {
37 | $this->path = $path;
38 | $this->extension = $extension;
39 | }
40 |
41 | /**
42 | * {@inheritdoc}
43 | */
44 | public function createHandler(JobInterface $job, $level, $bubble)
45 | {
46 | $handler = new StreamHandler($this->buildPath($job->getTicket()), $level, $bubble);
47 |
48 | return $this->initHandler($handler);
49 | }
50 |
51 | /**
52 | * @param string $filename
53 | * @return string The path of the logfile
54 | */
55 | private function buildPath($filename)
56 | {
57 | return $this->path . DIRECTORY_SEPARATOR . $filename . '.' . $this->extension;
58 | }
59 | }
--------------------------------------------------------------------------------
/DependencyInjection/Compiler/RegisterDoctrineListenerPass.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\DependencyInjection\Compiler;
12 |
13 | use Gedmo\Timestampable\TimestampableListener;
14 | use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
15 | use Symfony\Component\DependencyInjection\ContainerBuilder;
16 | use Symfony\Component\DependencyInjection\Reference;
17 |
18 | /**
19 | * @author Hannes Schulz
20 | */
21 | class RegisterDoctrineListenerPass implements CompilerPassInterface
22 | {
23 | public function process(ContainerBuilder $container)
24 | {
25 | if ('orm' == $container->getParameter('abc.job.db_driver')) {
26 |
27 | $connection = $container->getParameter('abc.job.connection');
28 |
29 | $listener = $container->register('gedmo.listener.timestampable', TimestampableListener::class);
30 | $listener->addMethodCall('setAnnotationReader', [new Reference('annotation_reader')]);
31 | $listener->addTag('doctrine.event_subscriber', ['connection' => $connection]);
32 |
33 | $em = $container->getDefinition(sprintf('doctrine.dbal.%s_connection.event_manager', $container->getParameter('abc.job.connection')));
34 | $em->addMethodCall('addEventSubscriber', array($listener));
35 | }
36 | }
37 | }
--------------------------------------------------------------------------------
/Model/JobManager.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Model;
12 |
13 | use Abc\Bundle\JobBundle\Job\JobInterface as BaseJobInterface;
14 | use Abc\Bundle\SchedulerBundle\Model\ScheduleInterface as BaseScheduleInterface;
15 |
16 | /**
17 | * @author Hannes Schulz
18 | */
19 | abstract class JobManager implements JobManagerInterface
20 | {
21 | /**
22 | * {@inheritDoc}
23 | */
24 | public function create($type = null, $parameters = null, BaseScheduleInterface $schedule = null)
25 | {
26 | $class = $this->getClass();
27 |
28 | /** @var JobInterface $job */
29 | $job = new $class;
30 |
31 | $job->setType($type);
32 | $job->setParameters($parameters);
33 |
34 | if(!is_null($schedule))
35 | {
36 | $job->addSchedule($schedule);
37 | }
38 |
39 | return $job;
40 | }
41 |
42 | /**
43 | * {@inheritDoc}
44 | */
45 | public function findByTicket($ticket)
46 | {
47 | $jobs = $this->findBy(array('ticket' => $ticket));
48 |
49 | return count($jobs) > 0 ? $jobs[0] : null;
50 | }
51 |
52 | /**
53 | * {@inheritDoc}
54 | */
55 | public function isManagerOf(BaseJobInterface $job)
56 | {
57 | $class = $this->getClass();
58 |
59 | return ($job instanceof $class);
60 | }
61 | }
--------------------------------------------------------------------------------
/Tests/Model/JobTest.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Model;
12 |
13 | use Abc\Bundle\JobBundle\Model\Job;
14 | use Abc\Bundle\JobBundle\Model\Schedule;
15 | use PHPUnit\Framework\TestCase;
16 |
17 | class JobTest extends TestCase
18 | {
19 | public function testHasSchedule()
20 | {
21 | $job = new Job();
22 |
23 | $this->assertFalse($job->hasSchedules());
24 |
25 | $job->addSchedule(new Schedule());
26 |
27 | $this->assertTrue($job->hasSchedules());
28 | }
29 |
30 | public function testGetExecutionTime()
31 | {
32 | $subject = new Job();
33 | $createdAt = new \DateTime('2010-01-01 00:00:00');
34 | $terminatedAt = new \DateTime('2010-01-01 00:00:01');
35 |
36 | $subject->setCreatedAt($createdAt);
37 | $subject->setTerminatedAt($terminatedAt);
38 |
39 | $expectedProcessingTime = $subject->getTerminatedAt()->format('U') - $subject->getCreatedAt()->format('U');
40 |
41 | $this->assertEquals($expectedProcessingTime, $subject->getExecutionTime());
42 | }
43 |
44 | public function testClone()
45 | {
46 | $job = new Job;
47 | $job->setTicket('ticket');
48 |
49 | $clone = clone $job;
50 |
51 | $this->assertTrue($job !== $clone);
52 | $this->assertNotEquals($job->getTicket(), $clone->getTicket());
53 | }
54 | }
--------------------------------------------------------------------------------
/Job/Sleeper.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Job;
12 |
13 | use Abc\Bundle\JobBundle\Annotation\ParamType;
14 | use Abc\ProcessControl\ControllerAwareInterface;
15 | use Abc\ProcessControl\ControllerInterface;
16 | use Psr\Log\LoggerInterface;
17 |
18 | /**
19 | * A test job to check if jobs can be cancelled at runtime
20 | *
21 | * @author Hannes Schulz
22 | */
23 | class Sleeper implements ControllerAwareInterface
24 | {
25 | /**
26 | * @var ControllerInterface
27 | */
28 | private $controller;
29 |
30 | /**
31 | * {@inheritdoc}
32 | */
33 | public function setController(ControllerInterface $controller)
34 | {
35 | $this->controller = $controller;
36 | }
37 |
38 | /**
39 | * @ParamType("seconds", type="integer")
40 | * @ParamType("logger", type="@abc.logger")
41 | * @param $seconds
42 | * @param LoggerInterface $logger
43 | */
44 | public function sleep($seconds, LoggerInterface $logger)
45 | {
46 | $logger->info('start sleeping for {seconds}', ['seconds' => $seconds]);
47 |
48 | $start = time();
49 | do {
50 |
51 | sleep(1);
52 | $seconds--;
53 |
54 | } while ($seconds > 0 && !$this->controller->doStop());
55 |
56 | $logger->info('stopped sleeping after {seconds}', ['seconds' => time() - $start]);
57 | }
58 | }
--------------------------------------------------------------------------------
/Resources/config/services/adapter_bernard.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/Resources/config/doctrine/Job.orm.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/Event/JobEvents.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Event;
12 |
13 | /**
14 | * @author Hannes Schulz
15 | */
16 | final class JobEvents
17 | {
18 |
19 | /**
20 | * The abc.job.message_consume event is triggered each time a message is consumed from the queue
21 | *
22 | * The event listener receives an event of type Symfony\Component\EventDispatcher\Event
23 | *
24 | * @var string
25 | */
26 | const JOB_MESSAGE_CONSUME = 'abc.job.message_consume';
27 |
28 | /**
29 | * The abc.job.pre_execute event is triggered each time before a job is executed
30 | *
31 | * The event listener receives an event of type Abc\Bundle\JobBundle\Event\ExecutionEvent
32 | *
33 | * @var string
34 | */
35 | const JOB_PRE_EXECUTE = 'abc.job.pre_execute';
36 |
37 | /**
38 | * The abc.job.post_execute event is triggered each time before a job is executed
39 | *
40 | * The event listener receives an event of type Abc\Bundle\JobBundle\Event\ExecutionEvent
41 | *
42 | * @var string
43 | */
44 | const JOB_POST_EXECUTE = 'abc.job.post_execute';
45 |
46 | /**
47 | * The abc.job.terminated event is triggered whenever a root job terminates
48 | *
49 | * The event listener receives an event of type Abc\Bundle\JobBundle\Event\TerminationEvent
50 | *
51 | * @var string
52 | */
53 | const JOB_TERMINATED = 'abc.job.terminated';
54 | }
--------------------------------------------------------------------------------
/Model/JobInterface.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Model;
12 |
13 | use Abc\Bundle\JobBundle\Job\Status;
14 | use Abc\Bundle\JobBundle\Job\JobInterface as BaseJobInterface;
15 |
16 | /**
17 | * Defines API of a (persistable) job entity.
18 | *
19 | * @author Hannes Schulz
20 | */
21 | interface JobInterface extends BaseJobInterface
22 | {
23 | /**
24 | * @param string $ticket
25 | * @return void
26 | */
27 | public function setTicket($ticket);
28 |
29 | /**
30 | * @param string $type
31 | * @return void
32 | */
33 | public function setType($type);
34 |
35 | /**
36 | * @param Status $status
37 | * @return void
38 | */
39 | public function setStatus(Status $status);
40 |
41 | /**
42 | * Sets the response of the root job
43 | *
44 | * @param mixed|null $response The serialized response
45 | */
46 | public function setResponse($response = null);
47 |
48 | /**
49 | * @param integer $milliseconds The processing time in milliseconds
50 | * @return void
51 | */
52 | public function setProcessingTime($milliseconds);
53 |
54 | /**
55 | * @param \DateTime $createdAt
56 | * @return void
57 | */
58 | public function setCreatedAt(\DateTime $createdAt);
59 |
60 | /**
61 | * @param \DateTime $terminatedAt
62 | * @return void
63 | */
64 | public function setTerminatedAt(\DateTime $terminatedAt);
65 | }
--------------------------------------------------------------------------------
/Model/LogManagerInterface.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Model;
12 |
13 | use Abc\Bundle\JobBundle\Job\LogManagerInterface as BaseLogManagerInterface;
14 | use Monolog\Formatter\FormatterInterface;
15 |
16 | /**
17 | * @author Hannes Schulz
18 | */
19 | interface LogManagerInterface extends BaseLogManagerInterface
20 | {
21 | /**
22 | * @return string The fully qualified class name of the entity class.
23 | */
24 | public function getClass();
25 |
26 | /**
27 | * @return LogInterface
28 | */
29 | public function create();
30 |
31 | /**
32 | * @param LogInterface $log
33 | * @param bool $andFlush Whether to flush the changes (default true)
34 | * @return void
35 | */
36 | public function save(LogInterface $log, $andFlush = true);
37 |
38 | /**
39 | * @return LogInterface[]
40 | */
41 | public function findAll();
42 |
43 | /**
44 | *
45 | * @param array $criteria
46 | * @param array|null $orderBy
47 | * @param int|null $limit
48 | * @param int|null $offset
49 | * @throws \UnexpectedValueException
50 | * @return LogInterface[]
51 | */
52 | public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null);
53 |
54 | /**
55 | * @param LogInterface $log
56 | * @return int The number of deleted entities
57 | */
58 | public function delete(LogInterface $log);
59 | }
--------------------------------------------------------------------------------
/Api/BadRequestResponse.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Api;
12 |
13 | use JMS\Serializer\Annotation\Type;
14 |
15 | /**
16 | * @author Hannes Schulz
17 | */
18 | class BadRequestResponse
19 | {
20 | /**
21 | * @Type("string")
22 | * @var string
23 | */
24 | protected $message;
25 |
26 | /**
27 | * @Type("string")
28 | * @var string
29 | */
30 | protected $description;
31 |
32 | /**
33 | * ype("array")
34 | * @var array
35 | */
36 | protected $errors;
37 |
38 | /**
39 | * @param string $message
40 | * @param string $description
41 | */
42 | public function __construct($message, $description)
43 | {
44 | $this->message = $message;
45 | $this->description = $description;
46 | }
47 |
48 | /**
49 | * @return string
50 | */
51 | public function getMessage()
52 | {
53 | return $this->message;
54 | }
55 |
56 | /**
57 | * @return string
58 | */
59 | public function getDescription()
60 | {
61 | return $this->description;
62 | }
63 |
64 | /**
65 | * @return array
66 | */
67 | public function getErrors()
68 | {
69 | return $this->errors;
70 | }
71 |
72 | /**
73 | * @param array $errors
74 | * @return void
75 | */
76 | public function setErrors($errors)
77 | {
78 | $this->errors = $errors;
79 | }
80 | }
--------------------------------------------------------------------------------
/Resources/config/services/orm.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 | Abc\Bundle\JobBundle\Entity\Job
9 | Abc\Bundle\JobBundle\Entity\Schedule
10 | default
11 |
12 |
13 |
14 |
15 |
16 |
17 | %abc.job.model.job.class%
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | %abc.job.model.schedule.class%
26 |
27 |
28 |
29 |
30 | %abc.job.model_manager_name%
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/Serializer/EventDispatcher/JobDeserializationSubscriber.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Serializer\EventDispatcher;
12 |
13 | use Abc\Bundle\JobBundle\Model\Job;
14 | use JMS\Serializer\EventDispatcher\EventSubscriberInterface;
15 | use JMS\Serializer\EventDispatcher\PreDeserializeEvent;
16 |
17 | /**
18 | * @author Hannes Schulz
19 | */
20 | class JobDeserializationSubscriber implements EventSubscriberInterface
21 | {
22 | /**
23 | * {@inheritdoc}
24 | */
25 | public static function getSubscribedEvents()
26 | {
27 | return [
28 | ['event' => 'serializer.pre_deserialize', 'method' => 'onPreDeserialize']
29 | ];
30 | }
31 |
32 | /**
33 | * Appends an array element to the parameters of a job that provides information about the job type.
34 | *
35 | * @param PreDeserializeEvent $event
36 | */
37 | public function onPreDeserialize(PreDeserializeEvent $event)
38 | {
39 | $type = $event->getType();
40 | if (isset($type['name']) && ($type['name'] == Job::class || is_subclass_of($type['name'], Job::class))) {
41 | $data = $event->getData();
42 | if (isset($data['type']) && isset($data['parameters']) && is_array($data['parameters']) && count($data['parameters']) > 0) {
43 | array_push($data['parameters'], ['abc.job.type' => $data['type']]);
44 | $event->setData($data);
45 | }
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/Entity/LogManager.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Entity;
12 |
13 | use Abc\Bundle\JobBundle\Doctrine\LogManager as BaseLogManager;
14 | use Abc\Bundle\JobBundle\Model\LogInterface;
15 | use Doctrine\Common\Proxy\Exception\InvalidArgumentException;
16 | use Doctrine\ORM\EntityManager;
17 |
18 | /**
19 | * @author Hannes Schulz
20 | */
21 | class LogManager extends BaseLogManager
22 | {
23 | /** @var EntityManager */
24 | protected $em;
25 |
26 | /**
27 | * @param EntityManager $em
28 | * @param string $class
29 | */
30 | public function __construct(EntityManager $em, $class)
31 | {
32 | parent::__construct($em, $class);
33 |
34 | $this->em = $em;
35 | }
36 |
37 | /**
38 | * {@inheritdoc}
39 | */
40 | public function save(LogInterface $log, $andFlush = true)
41 | {
42 | if(!$log instanceof $this->class)
43 | {
44 | throw new InvalidArgumentException('1st argument must be an instanceof '.$this->getClass());
45 | }
46 |
47 | $extra = $log->getExtra();
48 | if(is_array($extra) && isset($extra['job_ticket']))
49 | {
50 | /** @var \Abc\Bundle\JobBundle\Entity\Log $log */
51 | $log->setJobTicket($extra['job_ticket']);
52 |
53 | unset($extra['job_ticket']);
54 |
55 | $log->setExtra($extra);
56 | }
57 |
58 | parent::save($log, $andFlush);
59 | }
60 | }
--------------------------------------------------------------------------------
/Doctrine/ScheduleManager.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Doctrine;
12 |
13 | use Abc\Bundle\JobBundle\Model\ScheduleInterface;
14 | use Abc\Bundle\JobBundle\Model\ScheduleManagerInterface;
15 | use Abc\Bundle\SchedulerBundle\Doctrine\ScheduleManager as BaseScheduleManager;
16 |
17 | /**
18 | * Doctrine EntityManager for entities of type Abc\Bundle\JobBundle\Model\ScheduleInterface
19 | *
20 | * @author Hannes Schulz
21 | */
22 | class ScheduleManager extends BaseScheduleManager implements ScheduleManagerInterface
23 | {
24 | /**
25 | * {@inheritDoc}
26 | */
27 | public function create($type = null, $expression = null, $active = true)
28 | {
29 | $class = $this->getClass();
30 |
31 | /** @var ScheduleInterface $schedule */
32 | $schedule = new $class;
33 | $schedule->setType($type);
34 | $schedule->setExpression($expression);
35 | $schedule->setIsActive($active == null ? true : $active);
36 |
37 | return $schedule;
38 | }
39 |
40 | /**
41 | * {@inheritDoc}
42 | */
43 | public function findSchedules($limit = null, $offset = null)
44 | {
45 | return $this->repository->findBy(array('isActive' => true), array(), $limit, $offset);
46 | }
47 |
48 | /**
49 | * {@inheritDoc}
50 | */
51 | public function delete(ScheduleInterface $schedule)
52 | {
53 | $this->objectManager->remove($schedule);
54 | $this->objectManager->flush();
55 | }
56 | }
--------------------------------------------------------------------------------
/Job/Context/ContextInterface.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Job\Context;
12 |
13 | use Abc\Bundle\JobBundle\Job\Context\Exception\ParameterNotFoundException;
14 |
15 | /**
16 | * ContextInterface
17 | *
18 | * @author Hannes Schulz
19 | */
20 | interface ContextInterface
21 | {
22 |
23 | /**
24 | * Gets the context parameters.
25 | *
26 | * @return array An array of parameters
27 | */
28 | public function all();
29 |
30 | /**
31 | * Clears all parameters.
32 | *
33 | * @return void
34 | */
35 | public function clear();
36 |
37 | /**
38 | * Gets a context parameter.
39 | *
40 | * @param string $name The parameter name
41 | * @return mixed The parameter value
42 | * @throws ParameterNotFoundException if the parameter is not defined
43 | */
44 | public function get($name);
45 |
46 | /**
47 | * Sets a context parameter.
48 | *
49 | * @param string $name The parameter name
50 | * @param mixed $value The parameter value
51 | * @return void
52 | */
53 | public function set($name, $value);
54 |
55 | /**
56 | * Returns true if a parameter name is defined.
57 | *
58 | * @param string $name The parameter name
59 | * @return bool Returns true if the parameter name is defined otherwise false
60 | */
61 | public function has($name);
62 |
63 | /**
64 | * @param string $name The parameter name
65 | * @return void
66 | */
67 | public function remove($name);
68 | }
--------------------------------------------------------------------------------
/Model/LogManager.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Model;
12 |
13 | use Abc\Bundle\JobBundle\Job\JobInterface as BaseJobInterface;
14 |
15 | /**
16 | * @author Hannes Schulz
17 | */
18 | abstract class LogManager implements LogManagerInterface
19 | {
20 | /**
21 | * {@inheritDoc}
22 | */
23 | public function create()
24 | {
25 | $class = $this->getClass();
26 |
27 | /**
28 | * @var LogInterface $log
29 | */
30 | return new $class;
31 | }
32 |
33 | /**
34 | * {@inheritdoc}
35 | */
36 | public function findByJob(BaseJobInterface $job)
37 | {
38 | $records = array();
39 | foreach ($this->findBy(['jobTicket' => $job->getTicket()], ['datetime' => 'ASC']) as $log) {
40 | /**
41 | * @var LogInterface $log
42 | */
43 | $records[] = $log->toRecord();
44 | }
45 |
46 | return $records;
47 | }
48 |
49 | /**
50 | * {@inheritdoc}
51 | */
52 | public function deleteByJob(BaseJobInterface $job)
53 | {
54 | return $this->deleteLogs($this->findBy(['jobTicket' => $job->getTicket()]));
55 | }
56 |
57 | /**
58 | * @param LogInterface[] $logs
59 | * @return int the number of delete entries
60 | */
61 | protected function deleteLogs($logs)
62 | {
63 | $i = 0;
64 | foreach ($logs as $log) {
65 | $this->delete($log);
66 | $i++;
67 | }
68 |
69 | return $i;
70 | }
71 | }
--------------------------------------------------------------------------------
/DependencyInjection/Compiler/LockerConfigurationPass.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\DependencyInjection\Compiler;
12 |
13 | use Abc\Bundle\JobBundle\Locker\NullLocker;
14 | use Abc\Bundle\ResourceLockBundle\Model\LockInterface;
15 | use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
16 | use Symfony\Component\DependencyInjection\ContainerBuilder;
17 | use Symfony\Component\DependencyInjection\Definition;
18 |
19 | /**
20 | * @author Hannes Schulz
21 | */
22 | class LockerConfigurationPass implements CompilerPassInterface
23 | {
24 | public function process(ContainerBuilder $container)
25 | {
26 | if($container->getParameter('abc.job.locker_service') == 'abc.job.locker.default')
27 | {
28 | if(!$container->hasParameter('abc.resource_lock.lock_manager.class'))
29 | {
30 | $container->removeDefinition('abc.job.locker.default');
31 | $container->setDefinition('abc.job.locker', new Definition(NullLocker::class));
32 | }
33 | }
34 | else {
35 | $class = $container->getParameterBag()->resolveValue(
36 | $container->findDefinition($container->getParameter('abc.job.locker_service'))->getClass()
37 | );
38 |
39 | if (!in_array(LockInterface::class, class_implements($class))) {
40 | throw new \InvalidArgumentException(sprintf('"abc.job.locker" must implement %s (instance of %s given).', LockInterface::class, $class));
41 | }
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/Tests/Job/ExceptionResponseTest.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Job\Response;
12 |
13 | use Abc\Bundle\JobBundle\Job\ExceptionResponse;
14 | use JMS\Serializer\SerializerBuilder;
15 | use JMS\Serializer\SerializerInterface;
16 | use PHPUnit\Framework\TestCase;
17 |
18 | /**
19 | * @author Hannes Schulz
20 | */
21 | class ExceptionResponseTest extends TestCase
22 | {
23 | /**
24 | * @var SerializerInterface
25 | */
26 | private $serializer;
27 |
28 | /**
29 | * {@inheritdoc}
30 | */
31 | public function setUp()
32 | {
33 | $this->serializer = SerializerBuilder::create()->build();
34 | }
35 |
36 | public function testGetCode()
37 | {
38 | $exception = new \Exception('foobar', 100);
39 | $subject = new ExceptionResponse($exception);
40 |
41 | $this->assertSame(100, $subject->getCode());
42 | }
43 |
44 | public function testGetMessage()
45 | {
46 | $exception = new \Exception('foobar', 100);
47 | $subject = new ExceptionResponse($exception);
48 |
49 | $this->assertSame('foobar', $subject->getMessage());
50 | }
51 |
52 | public function testSerializationToJson()
53 | {
54 | $exception = new \Exception('foobar', 100);
55 | $subject = new ExceptionResponse($exception);
56 |
57 | $data = $this->serializer->serialize($subject, 'json');
58 |
59 | $object = $this->serializer->deserialize($data, ExceptionResponse::class, 'json');
60 |
61 | $this->assertEquals($subject, $object);
62 | }
63 | }
--------------------------------------------------------------------------------
/Test/AdapterTest.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Test;
12 |
13 | use Abc\Bundle\JobBundle\Job\ManagerInterface;
14 | use Abc\Bundle\JobBundle\Job\Queue\ConsumerInterface;
15 | use Abc\Bundle\JobBundle\Job\Status;
16 | use Abc\Bundle\JobBundle\Test\DatabaseKernelTestCase;
17 |
18 | /**
19 | * @author Hannes Schulz
20 | */
21 | abstract class AdapterTest extends DatabaseKernelTestCase
22 | {
23 | public function setUp()
24 | {
25 | $this->setKernelOptions(['environment' => $this->getEnvironment()]);
26 | parent::setUp();
27 | }
28 |
29 | public function testProduceAndConsume()
30 | {
31 | $ticket = $this->getJobManager()->addJob('log', array('message'));
32 |
33 | $this->processJobs();
34 |
35 | $this->assertEquals(Status::PROCESSED(), $this->getJobManager()->get($ticket)->getStatus());
36 | }
37 |
38 | /**
39 | * @return string The name of the environment
40 | */
41 | public abstract function getEnvironment();
42 |
43 | /**
44 | * @return ManagerInterface
45 | */
46 | protected function getJobManager()
47 | {
48 | return $this->getContainer()->get('abc.job.manager');
49 | }
50 |
51 | /**
52 | * @return void
53 | */
54 | protected function processJobs()
55 | {
56 | /**
57 | * @var ConsumerInterface $consumer
58 | */
59 | $consumer = $this->getContainer()->get('abc.job.consumer');
60 | $consumer->consume('default', [
61 | 'stop-when-empty' => true
62 | ]);
63 | }
64 | }
--------------------------------------------------------------------------------
/Tests/Fixtures/App/app/config/config_test.yml:
--------------------------------------------------------------------------------
1 | imports:
2 | - { resource: services.yml }
3 | # - { resource: parameters.yml }
4 |
5 | framework:
6 | secret: Hell yeah!
7 | router: { resource: "%kernel.root_dir%/config/routing.yml" }
8 | form: true
9 | csrf_protection: true
10 | templating:
11 | engines: ['twig']
12 | test: ~
13 | session:
14 | storage_id: session.storage.mock_file
15 | default_locale: en
16 | translator: { fallback: en }
17 | profiler:
18 | collect: false
19 | validation: { enable_annotations: true }
20 |
21 | monolog:
22 | handlers:
23 | main:
24 | type: stream
25 | path: "%kernel.logs_dir%/%kernel.environment%.log"
26 | level: error
27 | channels: ['!abc.job']
28 | abc_job:
29 | type: stream
30 | path: "%kernel.logs_dir%/abc_job_%kernel.environment%.log"
31 | level: debug
32 | channels: ["abc.job"]
33 |
34 | # Twig Configuration
35 | twig:
36 | debug: "%kernel.debug%"
37 | strict_variables: "%kernel.debug%"
38 |
39 | doctrine:
40 | dbal:
41 | driver: "pdo_sqlite"
42 | path: "%kernel.cache_dir%/sqlite.db"
43 | types:
44 | json: Sonata\Doctrine\Types\JsonType
45 |
46 | orm:
47 | auto_generate_proxy_classes: true
48 | auto_mapping: true
49 |
50 | swiftmailer:
51 | disable_delivery: true
52 |
53 | bernard:
54 | driver: doctrine
55 |
56 | abc_resource_lock:
57 | db_driver: orm
58 |
59 | abc_scheduler:
60 | db_driver: orm
61 |
62 | abc_job:
63 | adapter: sonata
64 | register_default_jobs: true
65 | logging:
66 | storage_handler:
67 | type: orm # Choose "orm" if you want to store job logs in the database instead of files
--------------------------------------------------------------------------------
/Resources/docs/cancel-jobs.md:
--------------------------------------------------------------------------------
1 | Cancel Jobs
2 | ===========
3 |
4 | In some cases it is necessary to cancel a job either manually or if for example a new version of the application is deployed. By default a job cannot be cancelled at runtime unless a process termination signal kills the underlying PHP process.
5 |
6 | To make job cancellable the job class must implement the interface ControllerAwareInterface:
7 |
8 | ```php
9 | namespace Abc\ProcessControl;
10 |
11 | use Abc\ProcessControl\ControllerInterface;
12 |
13 | interface ControllerAwareInterface
14 | {
15 | public function setController(ControllerInterface $controller);
16 | }
17 | ```
18 |
19 | This `ControllerAwareInterface` defines the method `doExit()` which indicates whether the job should abort it's execution:
20 |
21 | ```php
22 | namespace Abc\ProcessControl;
23 |
24 | interface ControllerInterface
25 | {
26 | public function doExit();
27 | }
28 | ```
29 |
30 | __Note:__ It is recommended to implement this interface in every job that performs work for a longer period of time (> 1 second) in order to prevent uncontrolled termination of jobs and in order support manual cancellation of jobs.
31 |
32 | Below you see an example implementation how a job uses the controller:
33 |
34 | ```php
35 | use Abc\ProcessControl\ControllerAwareInterface;
36 | use Abc\ProcessControl\ControllerInterface;
37 |
38 | class Sleeper implements ControllerAwareInterface
39 | {
40 | private $controller;
41 |
42 | public function setController(ControllerInterface $controller)
43 | {
44 | $this->controller = $controller;
45 | }
46 |
47 | /**
48 | * @ParamType("seconds", type="integer")
49 | * @ParamType("logger", type="@abc.logger")
50 | */
51 | public function sleep($seconds, LoggerInterface $logger)
52 | {
53 | // ...
54 | }
55 | }
56 | ```
57 |
58 | Back to [index](../../README.md)
--------------------------------------------------------------------------------
/Resources/config/services/registry.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 | Metadata\MetadataFactory
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | %abc.job.queue_config%
31 | %abc.job.default_queue%
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/Tests/Logger/Handler/StreamHandlerFactoryTest.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Logger\Handler;
12 |
13 | use Abc\Bundle\JobBundle\Logger\Handler\StreamHandlerFactory;
14 | use Abc\Bundle\JobBundle\Model\Job;
15 | use Monolog\Handler\StreamHandler;
16 | use Monolog\Logger;
17 | use org\bovigo\vfs\vfsStream;
18 | use org\bovigo\vfs\vfsStreamDirectory;
19 | use PHPUnit\Framework\TestCase;
20 |
21 | /**
22 | * @author Hannes Schulz
23 | */
24 | class StreamHandlerFactoryTest extends TestCase
25 | {
26 | /**
27 | * @var vfsStreamDirectory
28 | */
29 | private $root;
30 |
31 | /**
32 | * @var StreamHandlerFactory
33 | */
34 | private $subject;
35 |
36 | /**
37 | * {@inheritdoc}
38 | */
39 | public function setUp()
40 | {
41 | $this->root = vfsStream::setup();
42 | $this->subject = new StreamHandlerFactory($this->root->url());
43 | }
44 |
45 | /**
46 | * @param int $level
47 | * @param boolean $bubble
48 | * @dataProvider provideLevels
49 | */
50 | public function testCreateHandler($level, $bubble)
51 | {
52 | $job = new Job();
53 | $job->setTicket('JobTicket');
54 |
55 | $handler = $this->subject->createHandler($job, $level, $bubble);
56 | $this->assertInstanceOf(StreamHandler::class, $handler);
57 | }
58 |
59 | /**
60 | * @return array
61 | */
62 | public static function provideLevels()
63 | {
64 | return [
65 | [Logger::CRITICAL, true],
66 | [Logger::CRITICAL, false]
67 | ];
68 | }
69 | }
--------------------------------------------------------------------------------
/Tests/Functional/Job/ConnectionTest.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Functional\Job;
12 |
13 | use Abc\Bundle\JobBundle\Job\ManagerInterface;
14 | use Abc\Bundle\JobBundle\Job\Queue\ConsumerInterface;
15 | use Abc\Bundle\JobBundle\Job\Status;
16 | use Abc\Bundle\JobBundle\Test\DatabaseKernelTestCase;
17 |
18 | /**
19 | * @author Hannes Schulz
20 | */
21 | class ConnectionTest extends DatabaseKernelTestCase
22 | {
23 | /**
24 | * {@inheritdoc}
25 | */
26 | public function setUp()
27 | {
28 | $this->setEntityManagerNames(['default', 'abc_job_processing']);
29 | $this->setKernelOptions(['environment' => 'dedicated_connection']);
30 | parent::setUp();
31 | }
32 |
33 | public function testWithDedicatedConnection()
34 | {
35 | $job = $this->getJobManager()->addJob('throw_dbal_exception');
36 |
37 | $this->processJobs();
38 |
39 | $this->getEntityManager()->clear();
40 |
41 | $this->assertEquals(Status::ERROR(), $job->getStatus());
42 | }
43 |
44 | /**
45 | * @return ManagerInterface
46 | */
47 | protected function getJobManager()
48 | {
49 | return $this->getContainer()->get('abc.job.manager');
50 | }
51 |
52 | /**
53 | * @return void
54 | */
55 | protected function processJobs()
56 | {
57 | /**
58 | * @var ConsumerInterface $consumer
59 | */
60 | $consumer = $this->getContainer()->get('abc.job.consumer');
61 | $consumer->consume('default', [
62 | 'stop-when-empty' => true
63 | ]);
64 | }
65 | }
--------------------------------------------------------------------------------
/Tests/Logger/Handler/OrmHandlerFactoryTest.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Logger\Handler;
12 |
13 | use Abc\Bundle\JobBundle\Logger\Handler\JobAwareOrmHandler;
14 | use Abc\Bundle\JobBundle\Logger\Handler\OrmHandlerFactory;
15 | use Abc\Bundle\JobBundle\Model\Job;
16 | use Abc\Bundle\JobBundle\Model\LogManagerInterface;
17 | use Monolog\Logger;
18 | use PHPUnit\Framework\TestCase;
19 |
20 | /**
21 | * @author Hannes Schulz
22 | */
23 | class OrmHandlerFactoryTest extends TestCase
24 | {
25 | /**
26 | * @var LogManagerInterface|\PHPUnit_Framework_MockObject_MockObject
27 | */
28 | private $manager;
29 |
30 | /**
31 | * @var OrmHandlerFactory
32 | */
33 | private $subject;
34 |
35 | /**
36 | * {@inheritdoc}
37 | */
38 | public function setUp()
39 | {
40 | $this->manager = $this->createMock(LogManagerInterface::class);
41 | $this->subject = new OrmHandlerFactory($this->manager);
42 | }
43 |
44 | /**
45 | * @param int $level
46 | * @param boolean $bubble
47 | * @dataProvider provideLevels
48 | */
49 | public function testCreateHandler($level, $bubble)
50 | {
51 | $job = new Job();
52 | $handler = $this->subject->createHandler($job, $level, $bubble);
53 |
54 | $this->assertInstanceOf(JobAwareOrmHandler::class, $handler);
55 | }
56 |
57 | /**
58 | * @return array
59 | */
60 | public static function provideLevels()
61 | {
62 | return [
63 | [Logger::CRITICAL, true],
64 | [Logger::CRITICAL, false]
65 | ];
66 | }
67 | }
--------------------------------------------------------------------------------
/DependencyInjection/Compiler/ControllerConfigurationPass.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\DependencyInjection\Compiler;
12 |
13 | use Abc\ProcessControl\ControllerInterface;
14 | use Abc\ProcessControl\NullController;
15 | use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
16 | use Symfony\Component\DependencyInjection\ContainerBuilder;
17 | use Symfony\Component\DependencyInjection\Definition;
18 |
19 | /**
20 | * @author Hannes Schulz
21 | */
22 | class ControllerConfigurationPass implements CompilerPassInterface
23 | {
24 | public function process(ContainerBuilder $container)
25 | {
26 | $controllerService = $container->getParameter('abc.job.controller_service');
27 |
28 | if ($controllerService != 'abc.process_control.controller') {
29 |
30 | $class = $container->getParameterBag()->resolveValue(
31 | $container->findDefinition($controllerService)->getClass()
32 | );
33 |
34 | if (!in_array(ControllerInterface::class, class_implements($class))) {
35 | throw new \InvalidArgumentException(sprintf('"abc.job.controller" must implement %s (instance of %s given).', ControllerInterface::class, $class));
36 | }
37 | } elseif ($container->hasDefinition('abc.process_control.controller') || $container->hasAlias('abc.process_control.controller')) {
38 | $container->setAlias('abc.job.controller', 'abc.process_control.controller');
39 | }
40 | else {
41 | $container->setDefinition('abc.job.controller', new Definition(NullController::class));
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/DependencyInjection/Compiler/RegisterConstraintProvidersPass.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\DependencyInjection\Compiler;
12 |
13 | use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
14 | use Symfony\Component\DependencyInjection\ContainerBuilder;
15 |
16 | /**
17 | * @author Hannes Schulz
18 | */
19 | class RegisterConstraintProvidersPass implements CompilerPassInterface
20 | {
21 | /**
22 | * @var string
23 | */
24 | private $validator;
25 |
26 | /**
27 | * @var string
28 | */
29 | private $tag;
30 |
31 | /**
32 | * @param string $validator Service name of the definition registry in processed container
33 | * @param string $tag The tag name used for jobs
34 | */
35 | public function __construct($validator = 'abc.job.validator.parameters', $tag = 'abc.job.constraint_provider')
36 | {
37 | $this->validator = $validator;
38 | $this->tag = $tag;
39 | }
40 |
41 | /**
42 | * {@inheritdoc}
43 | */
44 | public function process(ContainerBuilder $container)
45 | {
46 | if (!$container->hasDefinition($this->validator) && !$container->hasAlias($this->validator)) {
47 | return;
48 | }
49 |
50 | $validator = $container->findDefinition($this->validator);
51 | foreach ($container->findTaggedServiceIds($this->tag) as $id => $tags) {
52 | $definition = $container->getDefinition($id);
53 |
54 | foreach ($tags as $tag) {
55 | $validator->addMethodCall('register', array($definition));
56 | }
57 | }
58 | }
59 | }
--------------------------------------------------------------------------------
/Entity/Schedule.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Entity;
12 |
13 | use Abc\Bundle\JobBundle\Model\JobInterface;
14 | use Abc\Bundle\JobBundle\Model\Schedule as BaseSchedule;
15 | use JMS\Serializer\Annotation as JMS;
16 |
17 | /**
18 | * @JMS\ExclusionPolicy("all")
19 | *
20 | * @author Hannes Schulz
21 | */
22 | class Schedule extends BaseSchedule
23 | {
24 | /**
25 | * @var integer
26 | */
27 | protected $id;
28 |
29 | /**
30 | * @var string
31 | */
32 | protected $jobTicket;
33 |
34 | /**
35 | * @var JobInterface
36 | */
37 | protected $job;
38 |
39 | /**
40 | * @param int $id
41 | * @return void
42 | */
43 | public function setId($id)
44 | {
45 | $this->id = $id;
46 | }
47 |
48 | /**
49 | * @return integer
50 | */
51 | public function getId()
52 | {
53 | return $this->id;
54 | }
55 |
56 | /**
57 | * @return string
58 | */
59 | public function getJobTicket()
60 | {
61 | return $this->jobTicket;
62 | }
63 |
64 | /**
65 | * @return JobInterface|null
66 | */
67 | public function getJob()
68 | {
69 | return $this->job;
70 | }
71 |
72 | /**
73 | * @param JobInterface|null $job
74 | */
75 | public function setJob(JobInterface $job = null)
76 | {
77 | $this->job = $job;
78 | }
79 |
80 | /**
81 | * Override clone in order to avoid duplicating entries in Doctrine
82 | */
83 | public function __clone()
84 | {
85 | parent::__clone();
86 |
87 | $this->id = null;
88 | }
89 | }
--------------------------------------------------------------------------------
/Resources/docs/serialization.md:
--------------------------------------------------------------------------------
1 | Serialization
2 | =============
3 |
4 | Serialization of parameters and return values of a job happens in two places. First place is when a job is persisted to the database. When this happens the parameters and return value of a job is serialized and persisted to the database together with the rest of the data of a job. The second place is the REST-Api. In this case the whole job instance including parameters and response are serialized.
5 |
6 | The AbcJobBundle uses the [JMS serializer](https://github.com/schmittjoh/serializer) by default for serialization.
7 |
8 | ## Serialization Options
9 |
10 | You can configure serialization options for the parameters and return value of a job.
11 |
12 | ```php
13 | namespace My\Bundle\ExampleBundle\Job\MyJob;
14 |
15 | use Abc\Bundle\JobBundle\Annotation\JobParameters;
16 | use My\Bundle\ExampleBundle\Entity\MyEntity;
17 |
18 | class MyJob
19 | {
20 | private $entityManager;
21 |
22 | /**
23 | * @ParamType("entity", type="My\Bundle\ExampleBundle\Entity\MyEntity", options={"groups"={"primarykey"}, "version"="1"})
24 | * @ReturnType("My\Bundle\ExampleBundle\Model\SomeObject", options={"groups"={"mygroup"}, "version"="2")
25 | */
26 | public function doSomething($entity)
27 | {
28 | if(!$this->entityManager->contains($entity)
29 | {
30 | $entity = $this->entityManager->findByPK($entity::class, $entity->getId())
31 | }
32 |
33 | // ...
34 |
35 | return $someObject;
36 | }
37 | }
38 | ```
39 | __Note:__ The serialization groups are only applied when a job is persisted and loaded from the database. The reason for this is that the [JMS serializer](https://github.com/schmittjoh/serializer) so far does not support the definition of serialization groups for specific properties of an entity but only globally for the whole serialization of an object.
40 |
41 | Back to [index](../../README.md)
--------------------------------------------------------------------------------
/Logger/Handler/BaseHandlerFactory.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Logger\Handler;
12 |
13 | use Abc\Bundle\JobBundle\Job\JobInterface;
14 | use Abc\Bundle\SchedulerBundle\Schedule\ProcessorInterface;
15 | use Monolog\Formatter\FormatterInterface;
16 | use Monolog\Handler\HandlerInterface;
17 |
18 | /**
19 | * @author Hannes Schulz
20 | */
21 | abstract class BaseHandlerFactory implements HandlerFactoryInterface
22 | {
23 | /**
24 | * @var FormatterInterface
25 | */
26 | protected $formatter;
27 |
28 | /**
29 | * @var array|ProcessorInterface[]
30 | */
31 | protected $processors = array();
32 |
33 | /**
34 | * {@inheritdoc}
35 | */
36 | public abstract function createHandler(JobInterface $job, $level, $bubble);
37 |
38 | /**
39 | * {@inheritdoc}
40 | */
41 | public function setFormatter(FormatterInterface $formatter = null)
42 | {
43 | $this->formatter = $formatter;
44 | }
45 |
46 | /**
47 | * {@inheritdoc}
48 | */
49 | public function setProcessors(array $processors)
50 | {
51 | $this->processors = $processors;
52 | }
53 |
54 | /**
55 | * Sets formatter and processors.
56 | *
57 | * @param HandlerInterface $handler
58 | * @return HandlerInterface
59 | */
60 | protected function initHandler(HandlerInterface $handler)
61 | {
62 | if ($this->formatter != null) {
63 | $handler->setFormatter($this->formatter);
64 | }
65 |
66 | foreach ($this->processors as $processor) {
67 | $handler->pushProcessor($processor);
68 | }
69 |
70 | return $handler;
71 | }
72 | }
--------------------------------------------------------------------------------
/Tests/Adapter/Bernard/ConsumerAdapterTest.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Adapter\Bernard;
12 |
13 | use Abc\Bundle\JobBundle\Adapter\Bernard\ConsumerAdapter;
14 | use Bernard\Consumer;
15 | use Bernard\Queue;
16 | use Bernard\QueueFactory;
17 | use PHPUnit\Framework\TestCase;
18 |
19 | /**
20 | * @author Hannes Schulz
21 | */
22 | class ConsumerAdapterTest extends TestCase
23 | {
24 | /**
25 | * @var Consumer|\PHPUnit_Framework_MockObject_MockObject
26 | */
27 | private $consumer;
28 |
29 | /**
30 | * @var QueueFactory|\PHPUnit_Framework_MockObject_MockObject
31 | */
32 | private $queueFactory;
33 |
34 | /**
35 | * @var ConsumerAdapter
36 | */
37 | private $subject;
38 |
39 | /**
40 | * {@inheritdoc}
41 | */
42 | public function setUp()
43 | {
44 | $this->consumer = $this->getMockBuilder(Consumer::class)->disableOriginalConstructor()->getMock();
45 | $this->queueFactory = $this->getMockBuilder(QueueFactory::class)->disableOriginalConstructor()->getMock();
46 | $this->subject = new ConsumerAdapter($this->consumer, $this->queueFactory);
47 | }
48 |
49 | public function testConsume() {
50 |
51 | $queue = $this->createMock(Queue::class);
52 | $options = array('foo' => 'bar');
53 |
54 | $this->queueFactory->expects($this->once())
55 | ->method('create')
56 | ->with('foobar')
57 | ->willReturn($queue);
58 |
59 | $this->consumer->expects($this->once())
60 | ->method('consume')
61 | ->with($queue, $options);
62 |
63 | $this->subject->consume('foobar', $options);
64 | }
65 | }
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aboutcoders/job-bundle",
3 | "type": "symfony-bundle",
4 | "description": "A symfony bundle for asynchronous job processing.",
5 | "keywords": ["job", "jobs", "schedule", "scheduler", "cron", "cronjob", "bundle", "queue", "task", "background", "rest", "rest-api" , "asynchronous"],
6 | "homepage": "http://aboutcoders.com",
7 | "license": "MIT",
8 | "authors": [
9 | {
10 | "name": "Hannes Schulz",
11 | "email": "hannes.schulz@aboutcoders.com"
12 | }
13 | ],
14 | "require": {
15 | "php": ">=7.0.0",
16 | "symfony/symfony": "~2.6|~3.0|~4.0",
17 | "myclabs/php-enum": "~1.5",
18 | "gedmo/doctrine-extensions": "~2.0",
19 | "jms/serializer-bundle": "*",
20 | "nelmio/api-doc-bundle": "~3",
21 | "doctrine/annotations": "1.*",
22 | "aboutcoders/process-control": "~1.3",
23 | "aboutcoders/scheduler-bundle": "~1.2",
24 | "aboutcoders/resource-lock-bundle": "~0.1"
25 | },
26 | "require-dev": {
27 | "phpunit/phpunit": "~5.0|~6.0",
28 | "php-mock/php-mock-phpunit": "dev-master",
29 | "mikey179/vfsStream": "^1.5",
30 | "doctrine/orm": "~2.2,>=2.2.3",
31 | "doctrine/doctrine-bundle": "~1.2",
32 | "symfony/monolog-bundle": "~2",
33 | "symfony/swiftmailer-bundle": "~2.3",
34 | "sonata-project/notification-bundle": "~2.2",
35 | "zendframework/zendxml": "~1",
36 | "bernard/bernard-bundle" : "dev-master",
37 | "aboutcoders/process-control-bundle": "~1.3@dev"
38 | },
39 | "suggest": {
40 | "aboutcoders/process-control-bundle": "Adds process control, requires ^1.3",
41 | "aboutcoders/supervisor-bundle": "Manage supervisor processes, requires dev-master"
42 | },
43 | "autoload": {
44 | "psr-4": { "Abc\\Bundle\\JobBundle\\": "" }
45 | },
46 | "minimum-stability": "dev",
47 | "prefer-stable": true
48 | }
49 |
--------------------------------------------------------------------------------
/Validator/Job/ConstraintProviderInterface.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Validator\Job;
12 |
13 | /**
14 | * @author Hannes Schulz
15 | */
16 | interface ConstraintProviderInterface
17 | {
18 | /**
19 | * Returns the priority of the provider, which determines which provider is used for a job type.
20 | *
21 | * @return int Priority number (higher - preferred)
22 | */
23 | public function getPriority();
24 |
25 | /**
26 | * Returns an array of constraints to validate the parameters of a job.
27 | *
28 | * The number of the elements in the array should match the number of parameters a job can be created or updated with.
29 | *
30 | * Runtime parameters are not validated!
31 | *
32 | * Assuming the job does not use any runtime parameters the first element will be used to validate the first parameter of
33 | * the job, the seconds element will be used to validate the seconds parameter and so on. Use null to prevent validation
34 | * of a parameter.
35 | *
36 | * If your job uses runtime parameters they must be omitted in the returned constraints. If the method signature defines
37 | * three parameters where second parameter is a runtime parameter the returned array should only contain two elements,
38 | * where first element is used to validate first parameter and second element is used to validate third parameter.
39 | *
40 | * If the array contains less elements that the job defines parameters the remaining parameters will not be validated.
41 | *
42 | * @param string $type The job type
43 | * @return array The constraints of a job type
44 | */
45 | public function getConstraints($type);
46 | }
--------------------------------------------------------------------------------
/Logger/Handler/OrmHandler.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Logger\Handler;
12 |
13 | use Abc\Bundle\JobBundle\Model\LogInterface;
14 | use Abc\Bundle\JobBundle\Model\LogManagerInterface;
15 | use Monolog\Handler\AbstractProcessingHandler;
16 | use Monolog\Logger;
17 |
18 | /**
19 | * @author Hannes Schulz
20 | */
21 | class OrmHandler extends AbstractProcessingHandler
22 | {
23 | /**
24 | * @var LogManagerInterface
25 | */
26 | protected $manager;
27 |
28 | /**
29 | * @param LogManagerInterface $manager
30 | * @param bool|int $level defaults to Monolog\Logger\Logger::DEBUG
31 | * @param bool $bubble defaults to true
32 | */
33 | public function __construct(LogManagerInterface $manager, $level = Logger::DEBUG, $bubble = true)
34 | {
35 | parent::__construct($level, $bubble);
36 |
37 | $this->manager = $manager;
38 | }
39 |
40 | /**
41 | * {@inheritdoc}
42 | */
43 | protected function write(array $record)
44 | {
45 | $log = $this->manager->create();
46 |
47 | $this->populateLog($log, $record);
48 |
49 | $this->manager->save($log);
50 | }
51 |
52 | /**
53 | * @param LogInterface $log
54 | * @param $record
55 | */
56 | protected function populateLog(LogInterface $log, $record)
57 | {
58 | $log->setChannel($record['channel']);
59 | $log->setLevel($record['level']);
60 | $log->setLevelName($record['level_name']);
61 | $log->setMessage($record['message']);
62 | $log->setDatetime($record['datetime']);
63 | $log->setContext($record['context']);
64 | $log->setExtra($record['extra']);
65 | }
66 | }
--------------------------------------------------------------------------------
/Adapter/Bernard/ControlledConsumer.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Adapter\Bernard;
12 |
13 | use Abc\ProcessControl\ControllerInterface;
14 | use Bernard\Consumer as BaseConsumer;
15 | use Bernard\Queue;
16 | use Bernard\Router;
17 | use Symfony\Component\EventDispatcher\EventDispatcherInterface;
18 |
19 | /**
20 | * A custom implementation of Consumer that is controlled by a process controller.
21 | *
22 | * @author Hannes Schulz
23 | */
24 | class ControlledConsumer extends BaseConsumer
25 | {
26 | /**
27 | * @var ControllerInterface
28 | */
29 | private $controller;
30 |
31 | /**
32 | * @param Router $router
33 | * @param EventDispatcherInterface $dispatcher
34 | * @param ControllerInterface $controller
35 | */
36 | public function __construct(Router $router, EventDispatcherInterface $dispatcher, ControllerInterface $controller)
37 | {
38 | parent::__construct($router, $dispatcher);
39 |
40 | $this->controller = $controller;
41 | }
42 |
43 | /**
44 | * {@inheritdoc}
45 | */
46 | public function tick(Queue $queue, array $options = [])
47 | {
48 | // weired, no clue why this is necessary, but somehow configure is not invoked otherwise
49 | $this->doConfigure($options);
50 |
51 | if ($this->controller->doStop()) {
52 | return false;
53 | }
54 |
55 | if ($this->controller->doPause()) {
56 | return true;
57 | }
58 |
59 | return parent::tick($queue, $options);
60 | }
61 |
62 | /**
63 | * {@inheritdoc}
64 | */
65 | protected function doConfigure(array $options)
66 | {
67 | parent::configure($options);
68 | }
69 | }
--------------------------------------------------------------------------------
/Listener/JobListener.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Listener;
12 |
13 | use Abc\Bundle\JobBundle\Event\ExecutionEvent;
14 | use Abc\Bundle\JobBundle\Job\ManagerInterface;
15 | use Abc\Bundle\JobBundle\Logger\LoggerFactoryInterface;
16 | use Psr\Log\LoggerInterface;
17 | use Psr\Log\NullLogger;
18 |
19 | /**
20 | * Registers the default runtime parameters "manager" and "logger".
21 | *
22 | * @author Hannes Schulz
23 | */
24 | class JobListener
25 | {
26 | /**
27 | * @var ManagerInterface
28 | */
29 | private $manager;
30 |
31 | /**
32 | * @var LoggerFactoryInterface
33 | */
34 | private $factory;
35 |
36 | /**
37 | * @var LoggerInterface
38 | */
39 | private $logger;
40 |
41 | /**
42 | * @param ManagerInterface $manager
43 | * @param LoggerFactoryInterface $factory
44 | */
45 | function __construct(ManagerInterface $manager, LoggerFactoryInterface $factory, LoggerInterface $logger = null)
46 | {
47 | $this->manager = $manager;
48 | $this->factory = $factory;
49 | $this->logger = $logger == null ? new NullLogger() : $logger;
50 | }
51 |
52 | /**
53 | * @param ExecutionEvent $event
54 | * @return void
55 | */
56 | public function onPreExecute(ExecutionEvent $event)
57 | {
58 | $event->getContext()->set('abc.manager', $this->manager);
59 |
60 | $this->logger->debug('Added runtime parameter "manager" to context', ['abc.manager' => $this->manager]);
61 |
62 | $logger = $this->factory->create($event->getJob());
63 |
64 | $event->getContext()->set('abc.logger', $logger);
65 |
66 | $this->logger->debug('Added runtime parameter "logger" to context', ['abc.logger' => $logger]);
67 | }
68 | }
--------------------------------------------------------------------------------
/Controller/BaseController.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Controller;
12 |
13 | use Abc\Bundle\JobBundle\Job\JobTypeRegistry;
14 | use Abc\Bundle\JobBundle\Job\ManagerInterface;
15 | use Abc\Bundle\JobBundle\Model\JobManagerInterface;
16 | use Abc\Bundle\JobBundle\Serializer\SerializerInterface;
17 | use Symfony\Bundle\FrameworkBundle\Controller\Controller;
18 | use Symfony\Component\HttpFoundation\Response;
19 | use Symfony\Component\Validator\Validator\ValidatorInterface;
20 |
21 | /**
22 | * @author Hannes Schulz
23 | */
24 | abstract class BaseController extends Controller
25 | {
26 | /**
27 | * @param mixed $data
28 | * @param int $status
29 | * @return Response
30 | */
31 | protected function serialize($data, $status = 200)
32 | {
33 | return new Response($this->getSerializer()->serialize($data, 'json'), $status);
34 | }
35 |
36 | /**
37 | * @return JobTypeRegistry
38 | */
39 | protected function getRegistry()
40 | {
41 | return $this->get('abc.job.registry');
42 | }
43 |
44 | /**
45 | * @return ManagerInterface
46 | */
47 | protected function getManager()
48 | {
49 | return $this->get('abc.job.manager');
50 | }
51 |
52 | /**
53 | * @return JobManagerInterface
54 | */
55 | protected function getJobManager()
56 | {
57 | return $this->get('abc.job.job_manager');
58 | }
59 |
60 | /**
61 | * @return SerializerInterface
62 | */
63 | protected function getSerializer()
64 | {
65 | return $this->get('abc.job.serializer');
66 | }
67 |
68 | /**
69 | * @return ValidatorInterface
70 | */
71 | protected function getValidator()
72 | {
73 | return $this->get('abc.job.validator');
74 | }
75 | }
--------------------------------------------------------------------------------
/Resources/config/services/adapter_sonata.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | %abc.job.default_queue%
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/Job/Context/Context.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Job\Context;
12 |
13 | use Abc\Bundle\JobBundle\Job\Context\Exception\ParameterNotFoundException;
14 |
15 | /**
16 | * @author Hannes Schulz
17 | */
18 | class Context implements ContextInterface
19 | {
20 |
21 | protected $parameters = array();
22 |
23 | /**
24 | * @param array $parameters An array of parameters
25 | */
26 | public function __construct(array $parameters = array())
27 | {
28 | foreach($parameters as $name => $parameter)
29 | {
30 | $this->set($name, $parameter);
31 | }
32 | }
33 |
34 | /**
35 | * {@inheritdoc}
36 | */
37 | public function clear()
38 | {
39 | $this->parameters = array();
40 | }
41 |
42 | /**
43 | * {@inheritdoc}
44 | */
45 | public function all()
46 | {
47 | return $this->parameters;
48 | }
49 |
50 | /**
51 | * {@inheritdoc}
52 | */
53 | public function get($name)
54 | {
55 | $name = strtolower($name);
56 | if(!array_key_exists($name, $this->parameters))
57 | {
58 | throw new ParameterNotFoundException($name);
59 | }
60 |
61 | return $this->parameters[$name];
62 | }
63 |
64 | /**
65 | * {@inheritdoc}
66 | */
67 | public function set($name, $value)
68 | {
69 | $this->parameters[strtolower($name)] = $value;
70 | }
71 |
72 | /**
73 | * {@inheritdoc}
74 | */
75 | public function has($name)
76 | {
77 | return array_key_exists(strtolower($name), $this->parameters);
78 | }
79 |
80 | /**
81 | * {@inheritdoc}
82 | */
83 | public function remove($name)
84 | {
85 | unset($this->parameters[strtolower($name)]);
86 | }
87 | }
--------------------------------------------------------------------------------
/Resources/docs/logging.md:
--------------------------------------------------------------------------------
1 | Logging
2 | =======
3 |
4 | During the execution of a job each job has access to it's own standard PSR logger.
5 |
6 | There are two ways to inject the logger into the job class.
7 |
8 | ## Injecting the logger as a runtime parameter
9 |
10 | To inject the logger as a runtime parameter you simply have to specify the `@abc.logger` in the `@ParamType` annotation of the method and add the logger to the method signature:
11 |
12 | ```php
13 | namespace My\Bundle\ExampleBundle\Job\MyJob;
14 |
15 | class MyJob
16 | {
17 | /**
18 | * @ParamType("logger", type="@abc.logger")
19 | */
20 | public function doSomething(Psr\Log\LoggerInterface $logger)
21 | {
22 | $logger->info('Hello World');
23 | }
24 | }
25 | ```
26 |
27 | This approach is especially useful if your job class defines more than one job.
28 |
29 | ## Injecting the logger using the LoggerAwareInterface
30 |
31 | Another option is to inject the logger by making the job class implement the interface `Psr\Log\LoggerInterfaceInterface`:
32 |
33 | ```php
34 | namespace My\Bundle\ExampleBundle\Job\MyJob;
35 |
36 | use Psr\Log\LoggerAwareInterface;
37 | use Psr\Log\LoggerInterface;
38 |
39 | class MyJob implements LoggerAwareInterface
40 | {
41 | protected $logger;
42 |
43 | public function setLogger(LoggerInterface $logger)
44 | {
45 | $this->logger = $logger;
46 | }
47 |
48 | public function doSomething()
49 | {
50 | $this->logger->info('Hello World');
51 | }
52 | }
53 | ```
54 |
55 | ## Getting the logs of a job
56 |
57 | Use the following command to get to logs of a job:
58 |
59 | ```php
60 | $records = $manager->getLogs($job->getTicket());
61 | ```
62 |
63 | This will return an array of log records that are available for this job.
64 |
65 | __Note:__ Depending on the configuration the records are internally stored either on the filesystem in the JSON format or in the database.
66 |
67 | Please refer to the chapter [Configuration](./configuration.md) to get information about the available configuration options.
68 |
69 | Back to [index](../../README.md)
--------------------------------------------------------------------------------
/Listener/ScheduleListener.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Listener;
12 |
13 | use Abc\Bundle\JobBundle\Job\Queue\Message;
14 | use Abc\Bundle\JobBundle\Job\Queue\ProducerInterface;
15 | use Abc\Bundle\JobBundle\Model\Schedule;
16 | use Abc\Bundle\SchedulerBundle\Event\SchedulerEvent;
17 | use Psr\Log\LoggerInterface;
18 | use Psr\Log\NullLogger;
19 |
20 | /**
21 | * Listens to scheduler events for jobs and sends messages to the queue engine
22 | *
23 | * @author Hannes Schulz
24 | */
25 | class ScheduleListener
26 | {
27 | /**
28 | * @var ProducerInterface
29 | */
30 | private $queueEngine;
31 |
32 | /**
33 | * @var LoggerInterface
34 | */
35 | private $logger;
36 |
37 | /**
38 | * @param ProducerInterface $queueEngine
39 | * @param LoggerInterface|null $logger
40 | */
41 | function __construct(ProducerInterface $queueEngine, LoggerInterface $logger = null)
42 | {
43 | $this->queueEngine = $queueEngine;
44 | $this->logger = $logger == null ? new NullLogger() : $logger;
45 | }
46 |
47 | /**
48 | * @param SchedulerEvent $event
49 | */
50 | public function onSchedule(SchedulerEvent $event)
51 | {
52 | $schedule = $event->getSchedule();
53 | if($schedule instanceof Schedule)
54 | {
55 | $this->logger->debug('Process schedule {schedule}', array('schedule' => $schedule));
56 |
57 | if($job = $schedule->getJob())
58 | {
59 | $message = new Message($job->getType(), $job->getTicket(), $job->getTicket());
60 |
61 | $this->queueEngine->produce($message);
62 |
63 | return;
64 | }
65 |
66 | $this->logger->error('There is no job associated with this schedule {schedule}', array('schedule' => $schedule));
67 | }
68 | }
69 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | AbcJobBundle
2 | ============
3 |
4 | A symfony bundle to process jobs asynchronously by simply annotating a method and registering the class within the service container.
5 |
6 | Build Status: [](https://travis-ci.org/aboutcoders/job-bundle)
7 |
8 | ## Features
9 |
10 | This bundle provides the following features:
11 |
12 | - Asynchronous execution of jobs
13 | - Status information about jobs
14 | - Functionality to cancel, update, restart a job
15 | - Repeated execution of jobs with schedules (cron based expressions)
16 | - JSON REST-Api
17 | - Support for multiple message queue systems:
18 | - Doctrine DBAL
19 | - PhpAmqp / RabbitMQ
20 | - InMemory
21 | - Predis / PhpRedis
22 | - Amazon SQS
23 | - Iron MQ
24 | - Pheanstalk
25 |
26 | ## Documentation
27 |
28 | - [Installation](./Resources/docs/installation.md)
29 | - [Configuration](./Resources/docs/configuration.md)
30 | - [Basic Usage](./Resources/docs/basic-usage.md)
31 | - [Message Consuming](./Resources/docs/message-consuming.md)
32 | - [Job Management](./Resources/docs/job-management.md)
33 | - [Scheduled Jobs](./Resources/docs/scheduled-jobs.md)
34 | - [Cancel Jobs](./Resources/docs/cancel-jobs.md)
35 | - [Runtime Parameters](./Resources/docs/runtime-parameters.md)
36 | - [Serialization](./Resources/docs/serialization.md)
37 | - [Validation](./Resources/docs/validation.md)
38 | - [Logging](./Resources/docs/logging.md)
39 | - [Lifecycle Events](./Resources/docs/lifecycle-events.md)
40 | - [Unit Testing](./Resources/docs/unit-testing.md)
41 | - [REST-API](./Resources/docs/rest-api.md)
42 | - [Process Control](./Resources/docs/process-control.md)
43 | - [Clustered Environment](./Resources/docs/clustered-environment.md)
44 | - [Configuration Reference](./Resources/docs/configuration-reference.md)
45 |
46 | ## Demo Project
47 |
48 | Please take a look at [aboutcoders/job-bundle-skeleton-app](https://github.com/aboutcoders/job-bundle-skeleton-app) to see how the AbcJobBundle can be used within Symfony project.
49 |
50 | ## License
51 |
52 | The MIT License (MIT). Please see [License File](./LICENSE) for more information.
--------------------------------------------------------------------------------
/Tests/Functional/Doctrine/LogManagerTest.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Functional\Doctrine;
12 |
13 | use Abc\Bundle\JobBundle\Doctrine\LogManager;
14 | use Abc\Bundle\JobBundle\Entity\Log;
15 | use Abc\Bundle\JobBundle\Test\DatabaseKernelTestCase;
16 |
17 | /**
18 | * @author Hannes Schulz
19 | */
20 | class LogManagerTest extends DatabaseKernelTestCase
21 | {
22 | /**
23 | * @var LogManager
24 | */
25 | private $subject;
26 |
27 | /**
28 | * {@inheritDoc}
29 | */
30 | public function setUp()
31 | {
32 | parent::setUp();
33 |
34 | $this->subject = new \Abc\Bundle\JobBundle\Entity\LogManager(
35 | $this->getEntityManager(),
36 | 'Abc\Bundle\JobBundle\Logger\Entity\Log'
37 | );
38 | }
39 |
40 | public function testIsExpectedInstance()
41 | {
42 | $this->assertInstanceOf(LogManager::class, $this->subject);
43 | }
44 |
45 | public function testCRUD()
46 | {
47 | $log = $this->subject->create();
48 | $log->setChannel('Channel');
49 | $log->setLevel(200);
50 | $log->setLevelName('info');
51 | $log->setMessage('Message');
52 | $log->setDatetime(new \DateTime());
53 | $log->setContext(['context' => 'Context']);
54 | $log->setExtra(['extra' => 'Extra']);
55 |
56 | $this->subject->save($log);
57 |
58 | $this->getEntityManager()->clear();
59 |
60 | /** @var Log[] $logs */
61 | $logs = $this->subject->findAll();
62 | /** @var Log $log */
63 | $log = $logs[0];
64 |
65 | $this->assertCount(1, $logs);
66 | $this->assertEquals($log, $logs[0]);
67 |
68 | $this->subject->delete($log);
69 |
70 | $this->getEntityManager()->clear();
71 |
72 | $this->assertEmpty($this->subject->findAll());
73 | }
74 | }
--------------------------------------------------------------------------------
/Job/JobBuilder.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Job;
12 |
13 | use Abc\Bundle\JobBundle\Model\Job;
14 | use Abc\Bundle\JobBundle\Model\Schedule;
15 |
16 | /**
17 | * @author Hannes Schulz
18 | */
19 | class JobBuilder
20 | {
21 | /**
22 | * @var string
23 | */
24 | protected $type;
25 |
26 | /**
27 | * @var array
28 | */
29 | protected $parameters;
30 |
31 | /**
32 | * @var array
33 | */
34 | protected $schedules = [];
35 |
36 | /**
37 | * @param string $type the job type
38 | */
39 | protected function __construct($type)
40 | {
41 | $this->type = $type;
42 | }
43 |
44 | /**
45 | * @param $type
46 | * @return static
47 | */
48 | public static function create($type)
49 | {
50 | return new static($type);
51 | }
52 |
53 | /**
54 | * @param array $parameters
55 | * @return $this The current instance
56 | */
57 | public function setParameters(array $parameters)
58 | {
59 | $this->parameters = $parameters;
60 |
61 | return $this;
62 | }
63 |
64 | /**
65 | * @param string $type The scheduler type
66 | * @param string $expression The scheduler expression
67 | * @return $this The current instance
68 | */
69 | public function addSchedule($type, $expression)
70 | {
71 | $this->schedules[] = [$type, $expression];
72 |
73 | return $this;
74 | }
75 |
76 | /**
77 | * @return JobInterface
78 | */
79 | public function build()
80 | {
81 | $job = new Job();
82 | $job->setType($this->type);
83 | $job->setParameters($this->parameters);
84 | foreach ($this->schedules as $schedule) {
85 | $job->addSchedule(new Schedule($schedule[0], $schedule[1]));
86 | }
87 |
88 | return $job;
89 | }
90 | }
--------------------------------------------------------------------------------
/Model/LogInterface.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Model;
12 |
13 | /**
14 | * @author Hannes Schulz
15 | */
16 | interface LogInterface
17 | {
18 | /**
19 | * @return string
20 | */
21 | public function getChannel();
22 |
23 | /**
24 | * @param string|null $channel
25 | * @return void
26 | */
27 | public function setChannel($channel);
28 |
29 | /**
30 | * @return int
31 | */
32 | public function getLevel();
33 |
34 | /**
35 | * @param int $level
36 | * @return void
37 | */
38 | public function setLevel($level);
39 |
40 | /**
41 | * @return string
42 | */
43 | public function getLevelName();
44 |
45 | /**
46 | * @param string $levelName
47 | * @return void
48 | */
49 | public function setLevelName($levelName);
50 |
51 | /**
52 | * @return string
53 | */
54 | public function getMessage();
55 |
56 | /**
57 | * @param string|null $message
58 | * @return void
59 | */
60 | public function setMessage($message);
61 |
62 | /**
63 | * @return \DateTime
64 | */
65 | public function getDatetime();
66 |
67 | /**
68 | * @param \DateTime $datetime
69 | * @return void
70 | */
71 | public function setDatetime($datetime);
72 |
73 | /**
74 | * @return array
75 | */
76 | public function getContext();
77 |
78 | /**
79 | * @param array|null $context
80 | * @return void
81 | */
82 | public function setContext($context);
83 |
84 | /**
85 | * @return array
86 | */
87 | public function getExtra();
88 |
89 | /**
90 | * @param array|null $extra
91 | * @return void
92 | */
93 | public function setExtra($extra);
94 |
95 | /**
96 | * @return array The PSR compliant log record
97 | */
98 | public function toRecord();
99 | }
--------------------------------------------------------------------------------
/Resources/config/routing/rest-job.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 | AbcJobBundle:Job:list
9 | json
10 | json
11 |
12 |
13 |
14 | AbcJobBundle:Job:get
15 | json
16 | json
17 |
18 |
19 |
20 | AbcJobBundle:Job:add
21 | json
22 | json
23 |
24 |
25 |
26 | AbcJobBundle:Job:update
27 | json
28 | json
29 |
30 |
31 |
32 | AbcJobBundle:Job:cancel
33 | json
34 | json
35 |
36 |
37 |
38 | AbcJobBundle:Job:restart
39 | json
40 | json
41 |
42 |
43 |
44 | AbcJobBundle:Job:logs
45 | json
46 | json
47 |
48 |
49 |
--------------------------------------------------------------------------------
/Job/Mailer/Mailer.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Job\Mailer;
12 |
13 | use Abc\Bundle\JobBundle\Job\JobAwareInterface;
14 | use Abc\Bundle\JobBundle\Annotation\ParamType;
15 | use Abc\Bundle\JobBundle\Job\JobInterface;
16 | use Psr\Log\LoggerInterface;
17 |
18 | /**
19 | * @author Hannes Schulz
20 | */
21 | class Mailer implements JobAwareInterface
22 | {
23 | /**
24 | * @var JobInterface
25 | */
26 | private $job;
27 |
28 | /**
29 | * @var \Swift_Mailer
30 | */
31 | private $mailer;
32 |
33 | /**
34 | * @param \Swift_Mailer $mailer
35 | */
36 | public function __construct(\Swift_Mailer $mailer)
37 | {
38 | $this->mailer = $mailer;
39 | }
40 |
41 | /**
42 | * {@inheritdoc}
43 | */
44 | public function setJob(JobInterface $job)
45 | {
46 | $this->job = $job;
47 | }
48 |
49 | /**
50 | * Sends a mail.
51 | *
52 | * @ParamType("message", type="Abc\Bundle\JobBundle\Job\Mailer\Message")
53 | * @ParamType("logger", type="@abc.logger")
54 | *
55 | * @param Message $message
56 | * @param LoggerInterface $logger
57 | * @throws \Exception Rethrows exceptions thrown by mailer
58 | */
59 | public function send(Message $message, LoggerInterface $logger)
60 | {
61 | $logger->debug('Send mail {message}', array('message' => $message));
62 |
63 | $mail = $this->mailer->createMessage()
64 | ->setSubject($message->getSubject())
65 | ->setFrom($message->getFrom())
66 | ->setTo($message->getTo());
67 |
68 | $mail->addPart($message->getMessage(), 'text/plain');
69 |
70 | try {
71 | $this->mailer->send($mail);
72 |
73 | $this->mailer->getTransport()->stop();
74 | } catch (\Exception $e) {
75 | $this->mailer->getTransport()->stop();
76 |
77 | throw $e;
78 | }
79 | }
80 | }
--------------------------------------------------------------------------------
/Test/DatabaseWebTestCase.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Test;
12 |
13 | use Symfony\Bundle\FrameworkBundle\Console\Application;
14 | use Symfony\Component\Console\Input\ArrayInput;
15 | use Symfony\Component\DependencyInjection\ContainerInterface;
16 |
17 | /**
18 | * @author Hannes Schulz
19 | */
20 | class DatabaseWebTestCase extends WebTestCase
21 | {
22 | /**
23 | * @var Application
24 | */
25 | protected static $application;
26 |
27 | /**
28 | * {@inheritDoc}
29 | */
30 | protected function setUp()
31 | {
32 | self::runCommand('doctrine:schema:drop', array("--force" => true));
33 | self::runCommand('doctrine:schema:update', array("--force" => true));
34 | }
35 |
36 | /**
37 | * @param string $command
38 | * @param array $options
39 | * @return int 0 if everything went fine, or an error code
40 | * @throws \Exception
41 | */
42 | protected static function runCommand($command, array $options = array())
43 | {
44 | $options["-e"] = "test";
45 | $options["-q"] = null;
46 | $options = array_merge($options, array('command' => $command));
47 |
48 | return self::getApplication()->run(new ArrayInput($options));
49 | }
50 |
51 | /**
52 | * @return Application
53 | */
54 | protected static function getApplication()
55 | {
56 | if(null === self::$application)
57 | {
58 | $client = static::createClient();
59 |
60 | self::$application = new Application($client->getKernel());
61 | self::$application->setAutoExit(false);
62 | self::$application->setCatchExceptions(false);
63 | }
64 |
65 | return self::$application;
66 | }
67 |
68 |
69 | /**
70 | * @return ContainerInterface
71 | */
72 | protected function getContainer()
73 | {
74 | return static::$kernel->getContainer();
75 | }
76 | }
--------------------------------------------------------------------------------
/Tests/Logger/Handler/BaseHandlerFactoryTest.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * For the full copyright and license information, please view the LICENSE
8 | * file that was distributed with this source code.
9 | */
10 |
11 | namespace Abc\Bundle\JobBundle\Tests\Logger\Handler;
12 |
13 | use Abc\Bundle\JobBundle\Logger\Handler\BaseHandlerFactory;
14 | use Monolog\Formatter\FormatterInterface;
15 | use Monolog\Handler\HandlerInterface;
16 | use PHPUnit\Framework\TestCase;
17 |
18 | /**
19 | * @author Hannes Schulz
20 | */
21 | class BaseHandlerFactoryTest extends TestCase
22 | {
23 | /**
24 | * @var BaseHandlerFactory
25 | */
26 | private $subject;
27 |
28 | /**
29 | * {@inheritdoc}
30 | */
31 | public function setUp()
32 | {
33 | $this->subject = $this->getMockForAbstractClass(BaseHandlerFactory::class);
34 | }
35 |
36 | public function testInitHandler() {
37 |
38 | $handler = $this->createMock(HandlerInterface::class);
39 | $formatter = $this->createMock(FormatterInterface::class);
40 | $processors = ['foobar'];
41 |
42 | $this->subject->setFormatter($formatter);
43 | $this->subject->setProcessors($processors);
44 |
45 | $handler->expects($this->once())
46 | ->method('setFormatter')
47 | ->with($formatter);
48 |
49 | $handler->expects($this->once())
50 | ->method('pushProcessor')
51 | ->with('foobar');
52 |
53 | $this->invokeMethod($this->subject, 'initHandler', [$handler]);
54 | }
55 |
56 | /**
57 | * Call protected/private method of a class.
58 | *
59 | * @param object &$object
60 | * @param string $methodName
61 | * @param array $parameters
62 | * @return mixed
63 | */
64 | private function invokeMethod(&$object, $methodName, array $parameters = array())
65 | {
66 | $reflection = new \ReflectionClass(get_class($object));
67 | $method = $reflection->getMethod($methodName);
68 | $method->setAccessible(true);
69 |
70 | return $method->invokeArgs($object, $parameters);
71 | }
72 | }
--------------------------------------------------------------------------------