PHPackages                             ac/fiendish-bundle - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Queues &amp; Workers](/categories/queues)
4. /
5. ac/fiendish-bundle

ActiveSymfony-bundle[Queues &amp; Workers](/categories/queues)

ac/fiendish-bundle
==================

Background daemons for your Symfony2 app

0.2.6(11y ago)211[2 issues](https://github.com/AmericanCouncils/fiendish-bundle/issues)MITPHP

Since Jun 13Pushed 11y ago1 watchersCompare

[ Source](https://github.com/AmericanCouncils/fiendish-bundle)[ Packagist](https://packagist.org/packages/ac/fiendish-bundle)[ RSS](/packages/ac-fiendish-bundle/feed)WikiDiscussions master Synced today

READMEChangelogDependencies (11)Versions (11)Used By (0)

Fiendish-Bundle
===============

[](#fiendish-bundle)

Fiendish-bundle allows you to write daemons within Symfony2, and control their execution.

[API Documentation](http://americancouncils.github.com/fiendish-bundle/annotated.html)

Installation
------------

[](#installation)

First you need to install and set up these non-PHP dependencies:

- [RabbitMQ](http://www.rabbitmq.com)
- [Supervisor](http://supervisord.org/)
- [Twiddler](https://github.com/mnaberez/supervisor_twiddler)

You will also need to make sure that you have the PHP executable available from the command line. On Ubuntu, that means installing the `php5-cli` package, and on other distributions it's most likely something similar.

Next, install fiendish-bundle into your Symfony2 app via composer:

```
"require": {
    ...
    "americancouncils/fiendish-bundle": "dev-master"
}

```

And add both Fiendish and the RabbitMQ bundle to your `app/AppKernel.php`bundles list:

```
new OldSound\RabbitMqBundle\OldSoundRabbitMqBundle(),
new AC\FiendishBundle\ACFiendishBundle()

```

Then you'll need to set up the `Process` table in your database. For now, that means manually installing and running the migration file found in the project's DoctrineMigrations folder.

Finally, you need to add some settings to supervisor to organize the daemons for your specific app. Here's an example of a config `/etc/supervisor/conf.d/foobar.conf` for a project called Foobar:

```
[program:foobar_master]
command=/usr/bin/php /var/www/foobar/app/console fiendish:master-daemon foobar
redirect_stderr=true

[group:foobar]

```

The group section is deliberately empty; Fiendish will be adding and removing processes in that group dynamically.

You'll also want to add a corresponding section to your Symfony config file:

```
fiendish:
    groups:
        foobar:
            process_user: "www-data"

```

`process_user` is the UNIX user that your daemons will run as.

Writing a Daemon
----------------

[](#writing-a-daemon)

Daemons are implemented as classes that derive from `BaseDaemon`. Here's an example daemon for Foobar:

```
namespace SomeRandomCoder\FoobarBundle\Daemon;

use AC\FiendishBundle\Daemon\BaseDaemon;

class UselessDaemon extends BaseDaemon
{
    public function run($arg)
    {
        while(true) {
            $this->heartbeat();

            print("FOO " . $arg['phrase'] . "!\n");
            sleep(1);
            print("BAR " . $arg['phrase'] . "!\n");
            sleep(1);
        }
    }
}
```

The `run` method is called when your daemon starts. If your daemon is meant to stay up all the time, then `run` should never return. It also needs to call the `heartbeat` method regularly, every few seconds or so. If a long enough time passes between heartbeats (by default, 30 seconds), your daemon will be assumed frozen and forcibly restarted.

The daemon has full access to your Symfony app's services. You can get to the container by calling `$this->getContainer()`.

You can also pass arguments to your daemons when you start them. Any JSON-serializable object can be used. In the example above an associative array with a single key was passed in.

Starting and Stopping Daemon Processes
--------------------------------------

[](#starting-and-stopping-daemon-processes)

To start a daemon process, use the Group service as shown:

```
use SomeRandomCoder\FoobarBundle\Daemon\UselessDaemon;

$container = $this->getContainer();
$kernel = $container->get('kernel');
$group = $container->get('fiendish.groups.foobar');
$proc = $group->newProcess(
    "useless_thing", // Name prefix, to help identify this process
    UselessDaemon::toCommand($kernel), // The command to execute
    ["phrase" => "fries and a shake"] // The argument for run()
);
$procName = $proc->getProcName(); // Needed to access this Process later
$group->applyChanges(); // This call does not block
```

When applyChanges is called, the master daemon wakes up and adds all new processes to the Supervisor group and starts them up.

Stopping a running daemon is similar:

```
$container = $this->getContainer();
$group = $container->get('fiendish.groups.foobar');
$proc = $group->getProcess($procName); // This is the procName you got earlier...
$group->removeProcess($proc);
$group->applyChanges();
```

Debugging
---------

[](#debugging)

Supervisor will keep track of everything printed out by your daemons and all activity related to them starting and stopping. Your best bet for figuring out any problems with your daemons is to use the Supervisor console:

```
$ sudo supervisorctl
> status
foobar_master              RUNNING    pid 8263, uptime 1:35:03
foobar:useless_thing.373771873643687276    RUNNING   pid 8267, uptime 1:28:28
> tail -f foobar:useless_thing.373771873643687276
FOO fries and a shake!
BAR fries and a shake!
FOO fries and a shake!
BAR fries and a shake!
...  (All print output and PHP error output ends up here) ...

```

(Thankfully, Supervisor's console has tab-completion, so there's no need to type out the long random numbers used to uniquely tag processes.)

Non-PHP Daemons
---------------

[](#non-php-daemons)

You can write your daemon processes in a language other than PHP by using the `ExternalDaemon` class. Implement the `getExternalCommand` method, returning a resource path or absolute path to the executable:

```
namespace JoeCoder\MyBundle\Daemon;

use AC\FiendishBundle\Daemon\ExternalDaemon;

class MyPythonAppDaemon extends ExternalDaemon
{
    public function getExternalCommand()
    {
        return "@JoeCoderMyBundle/Resources/scripts/myapp.py";
    }
}
```

The third argument passsed to startProcess should be an array, whose contents which will be passed to your program as command-line arguments.

Your daemon still has to emit heartbeats at regular intervals. To help with this, two environment variables are set:

- `FIENDISH_HEARTBEAT_ROUTING_KEY`
- `FIENDISH_HEARTBEAT_MESSAGE`

To emit a heartbeat, publish the given message to default exchange with the given routing key on AMQP.

###  Health Score

21

—

LowBetter than 18% of packages

Maintenance0

Infrequent updates — may be unmaintained

Popularity8

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity59

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~6 days

Total

10

Last Release

4347d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/078a9522fb48452e2952c7398e4a555b2501e10e564869efeb4bc1f16547743e?d=identicon)[dsimon](/maintainers/dsimon)

---

Top Contributors

[![DavidMikeSimon](https://avatars.githubusercontent.com/u/350396?v=4)](https://github.com/DavidMikeSimon "DavidMikeSimon (27 commits)")

---

Tags

daemonsupervisor

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/ac-fiendish-bundle/health.svg)

```
[![Health](https://phpackages.com/badges/ac-fiendish-bundle/health.svg)](https://phpackages.com/packages/ac-fiendish-bundle)
```

###  Alternatives

[rcsofttech/audit-trail-bundle

Enterprise-grade, high-performance Symfony audit trail bundle. Automatically track Doctrine entity changes with split-phase architecture, multiple transports (HTTP, Queue, Doctrine), and sensitive data masking.

1189.8k](/packages/rcsofttech-audit-trail-bundle)[kimai/kimai

Kimai - Time Tracking

4.8k9.0k1](/packages/kimai-kimai)[easycorp/easyadmin-bundle

Admin generator for Symfony applications

4.3k17.9M388](/packages/easycorp-easyadmin-bundle)[sylius/sylius

E-Commerce platform for PHP, based on Symfony framework.

8.5k5.9M736](/packages/sylius-sylius)[pimcore/pimcore

Content &amp; Product Management Framework (CMS/PIM/E-Commerce)

3.8k3.8M508](/packages/pimcore-pimcore)[open-dxp/opendxp

Content &amp; Product Management Framework (CMS/PIM)

9421.6k61](/packages/open-dxp-opendxp)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
