Created: 2011-07-16 22:02
Updated: 2018-04-25 19:50


* NEW And Improved cron-expression component by Michael Dowling *


##Overview## This bundle enables the use of the ninethousand jobqueue component library with a Symfony2 Project.

The NineThousand Jobqueue library is meant to be very extensible in that it employs the use of adapters to add customizations to what kind of code can be run by jobs and what kind of data persistence layer can be used to track the queue progress.

In the libraries are interfaces for Jobs, Queues, Job Adapters, Queue Adapters, and JobControl Adapters. Each of these serves a specific purpose that adds extensibility to the project that this library may be attached to.

This library is a work in progress.



add the bundle and jobqueue component to your deps configuration



I recommend adding Michael Downling's Cron component to your project. The ninethousand-jobqueue component has a sub-set of Michael's cron library, but in order to benefit from any updates he makes, it would be best to load the library from his repository.


in app/config.yml

            cron_class: Cron\CronExpression


Add the following to your autoload.php file:

    'NineThousand'     => array(__DIR__.'/../vendor/ninethousand-jobqueue/lib', __DIR__.'/../vendor/bundles'),
    // for mtdowlings cron library
    'Cron'             => array(__DIR__.'/../vendor/cron-expression/src'),


Add The Jobqueue bundle to your kernel bootstrap sequence

public function registerBundles()
    $bundles = array(
        new NineThousand\Bundle\NineThousandJobqueueBundle\NineThousandJobqueueBundle(),

    return $bundles;


By Default, Jobqueue has a sensible configuration which will use Doctrine ORM and the default EM available in your project. If you need to change any configuration setting and/or extend the jobqueue library, you could do it by adding this configuration to your project config. Only the values that need to be changed should be added, the jobqueue extension will merge your config into its defaults.


        class:  NineThousand\Jobqueue\Job\StandardJob
        class:  NineThousand\Jobqueue\Service\JobqueueControl
        class:  NineThousand\Jobqueue\Vendor\Doctrine\Adapter\Queue\DoctrineQueueAdapter
            cron_class:             NineThousand\Jobqueue\Util\Cron\CronExpression
            job_entity_class:       NineThousand\Bundle\NineThousandJobqueueBundle\Entity\Job
            job_adapter_class:      NineThousand\Bundle\NineThousandJobqueueBundle\Vendor\Doctrine\Adapter\Job\Symfony2DoctrineJobAdapter
            history_entity_class:   NineThousand\Bundle\NineThousandJobqueueBundle\Entity\History
            history_adapter_class:  NineThousand\Jobqueue\Vendor\Doctrine\Adapter\History\DoctrineHistoryAdapter
            log_adapter_class:      NineThousand\Jobqueue\Vendor\Doctrine\Adapter\Log\MonologAdapter
                    SymfonyConsoleJobControl:   NineThousand\Jobqueue\Vendor\Symfony2\Adapter\Job\Control\Symfony2ConsoleJobControl
            limit:          40
            pages_before:   5
            pages_after:    5


Import the bundle routing into your projects routing config with your desired prefix:

    resource: "@NineThousandJobqueueBundle/Resources/config/routing.xml"
    prefix:   /jobqueue

initialize database

doctrine ORM

If you're using the doctrine configuration that's default to your project, it could be as simple as running a schema update from the command line:

jesse@picard:~/$ php app/console doctrine:schema:update

other database adapters

Since no other database adapters have been created yet, if you extend the data persistence layer, bear in mind that your tables or data structure will need to be initialized somehow.



To access your queues from the controller Simply call the jobqueue.control service.

namespace NineThousand\Bundle\NineThousandJobqueueBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class DefaultController extends Controller
    public function indexAction()
        $queueControl = $this->get('jobqueue.control');
        return $this->render('JobqueueBundle:Default:index.html.twig', array(
            'activeQueue'    => $queueControl->getActiveQueue(),
            'retryQueue'     => $queueControl->getRetryQueue(),
            'scheduleQueue'  => $queueControl->getScheduleQueue()

To create a new Job

Here is a gist that shows the code api of how to create a new job


All Queues should implement PHPs \Iterator interface, so displaying the queue information in your template is simply a matter of iterating over them in a foreach loop:

{% extends 'JobqueueBundle::layout.html.twig' %}
{% block title "Jobqueue Status Control Center" %}
{% block body %}

    $(function() {
        $( ".section_accordion" ).accordion({
		    collapsible: true,
		    active: false,
		    autoHeight: false,
		    header: 'h2'
	    $( ".accordion" ).accordion({
		    collapsible: true,
		    active: false,
		    autoHeight: false,
		    header: 'h3'

<section id="jobqueues" class="section_accordion" />
    <h1>Jobqueue Status</h1>
    <article id="schedulequeue">
    <h2>Schedule Queue</h2>
        {% if scheduleQueue.totalJobs %}
            <ul class="accordion">
            {% for job in scheduleQueue %}
                    <h3></span><a href="#"> {{ }} </a></h3>
                    <ul class="jobdata">
                        <lh> Type </lh>
                        <li> {{ job.type }} </li>
                        <lh> Schedule </lh>
                        <li> {{ job.schedule }} </li>
                        {% if job.lastRunDate is defined %}
                            <lh> Last Run </lh>
                            <li> {{ job.lastRunDate|date("m/d/Y") }} </li>
                        {% endif %}
            {% endfor %}
        {% else %}
            <p class="emptyqueue"> No jobs found in queue </p>
        {% endif %}


This bundle comes with a number of commands but the only truly important command is the Command\RunCommand.php script.

To run this command from the smfony command console simply enter the following on your command line from your root directory:

jesse@picard:~/$ php app/console jobqueue:run

You can see that there's not alot going on here, it's simply a call to the control service's run() method, which cycles through all the queues and runs pending jobs.

namespace NineThousand\Bundle\NineThousandJobqueueBundle\Command;

use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;

class RunCommand extends ContainerAwareCommand

    protected function configure()
            ->setDescription('Cycles through the jobqueue only once')
The <info>{$this->getName()}</info> Run the Jobqueue one time through.

    protected function execute(InputInterface $input, OutputInterface $output)


To persistently run your job queue you could run the command every 10 seconds (or any interval) as a cron job:

*/10 * * * * (cd /home/jesse/ && php app/console jobqueue:run > /dev/null 2>&1 )

Run as a Daemon

You could also run the job queue as a system daemon

CodeMemeDaemonBundle is a wrapper for the PEAR library System_Daemon which was created by Kevin Vanzonneveld.

This will enable you to install the symfony bundle and easily convert your Symfony2 console scripts into system daemons.

pcntl is required to be configured in your PHP binary to use this. On my Ubuntu server I was able to install pcntl easily with the following command:

sudo apt-get install php-5.3-pcntl-zend-server
install CodeMemeDaemonBundle

You can add the Daemonbundle to your deps file for easy installation


Add the following to your autoload.php file:

    'CodeMeme'     => __DIR__.'/../vendor/bundles',

Add The CodeMemeDaemonBundle to your kernel bootstrap sequence

public function registerBundles()
    $bundles = array(
        new CodeMeme\Bundle\CodeMemeDaemonBundle\CodeMemeDaemonBundle(),

    return $bundles;


By Default, system daemons have a sensible configuration. If you need to change any configuration setting , you could do it by adding this configuration to your project config. Only the values that need to be changed should be added, the bundle extension will merge your daemon configs into its defaults.


#CodeMemeDaemonBundle Configuration Example
        #creates a daemon using default options
        jobqueue: ~

        #an example of all the available options
            appName: example
            appDir: %kernel.root_dir%
            appDescription: Example of how to configure the DaemonBundle
            logLocation: %kernel.logs_dir%/%kernel.environment%.example.log
            authorName: Jesse Greathouse
            appPidLocation: %kernel.cache_dir%/example/
            sysMaxExecutionTime: 0
            sysMaxInputTime: 0
            sysMemoryLimit: 1024M
            appUser: apache
            appGroup: apache
            appRunAsGID: 1000
            appRunAsUID: 1000


You can run the daemon as a different user or group depending on what is best for your application. By default it will resolve the user and group of the user who is running the daemon from the command console, but if you want to run as a different user you can use the appUser, appGroup or appRunAsGID, appRunAsUID options. Remember if you need to run as a different user you must start the daemon as sudo or a superuser.

To find out the group and user id of a specific user you can use the following commands.

jesse@picard:~/$ id -u www-data
jesse@picard:~/$ id -g www-data

Now you can simply start and stop the Jobqueue Daemon with the following commands

jesse@picard:~/$ php app/console jobqueue:start

jesse@picard:~/$ php app/console jobqueue:stop

jesse@picard:~/$ php app/console jobqueue:restart
Cookies help us deliver our services. By using our services, you agree to our use of cookies Learn more