Skip to content

Commit

Permalink
added event listeners to make it easy to extend cron jobs and hook in…
Browse files Browse the repository at this point in the history
… custom behaviors
  • Loading branch information
Jared King committed Jun 2, 2018
1 parent 02fd1af commit 6c0856c
Show file tree
Hide file tree
Showing 16 changed files with 327 additions and 30 deletions.
17 changes: 17 additions & 0 deletions README.md
Expand Up @@ -70,6 +70,23 @@ Scheduled jobs module for Infuse Framework
* * * * * php /var/www/example.com/infuse cron:run
```

### Events

You can subscribe to events with [event subscribers](https://symfony.com/doc/current/components/event_dispatcher.html#using-event-subscribers) from the symfony/event-dispatcher component. Your subscribers an listen to these events:

- `schedule_run.begin`
- `schedule_run.finished`
- `cron_job.begin`
- `cron_job.finished`

When you have created an [event subscriber](https://symfony.com/doc/current/components/event_dispatcher.html#using-event-subscribers) you can add it to your config like this:

```php
'cronSubscribers' => [
'App\EventSubscribers\MySubscriber'
]
```

### Webhooks

You can optionally specify a URL that will be called upon a successful run. The output from the run will be available using the `m` query parameter. This was designed to be compatible with [Dead Man's Snitch](https://deadmanssnitch.com/).
3 changes: 2 additions & 1 deletion composer.json
Expand Up @@ -23,7 +23,8 @@
},
"require": {
"php": ">=5.6.0",
"symfony/lock": "~3.0|~4.0"
"symfony/lock": "~3.0|~4.0",
"symfony/event-dispatcher": "~3.0|~4.0"
},
"require-dev": {
"infuse/infuse": "~1.6",
Expand Down
17 changes: 17 additions & 0 deletions src/Console/RunScheduledCommand.php
Expand Up @@ -42,8 +42,25 @@ private function getSchedule()
$lockFactory = $this->app['lock_factory'];
$namespace = $this->app['config']->get('app.hostname');
$schedule = new JobSchedule($jobs, $lockFactory, $namespace);
$this->addSubscribers($schedule);
$schedule->setLogger($this->app['logger']);

return $schedule;
}

/**
* @param JobSchedule $schedule
*/
private function addSubscribers(JobSchedule $schedule)
{
$subscribers = $this->app['config']->get('cronSubscribers', []);
foreach ($subscribers as $class) {
$subscriber = new $class();
if (method_exists($subscriber, 'setApp')) {
$subscriber->setApp($this->app);
}

$schedule->subscribe($subscriber);
}
}
}
31 changes: 31 additions & 0 deletions src/Events/CronJobBeginEvent.php
@@ -0,0 +1,31 @@
<?php

namespace Infuse\Cron\Events;

use Symfony\Component\EventDispatcher\Event;

class CronJobBeginEvent extends Event
{
const NAME = 'cron_job.begin';

/**
* @var string
*/
protected $jobId;

/**
* @param string $jobId
*/
public function __construct($jobId)
{
$this->jobId = $jobId;
}

/**
* @return string
*/
public function getJobId()
{
return $this->jobId;
}
}
46 changes: 46 additions & 0 deletions src/Events/CronJobFinishedEvent.php
@@ -0,0 +1,46 @@
<?php

namespace Infuse\Cron\Events;

use Symfony\Component\EventDispatcher\Event;

class CronJobFinishedEvent extends Event
{
const NAME = 'cron_job.finished';

/**
* @var string
*/
protected $jobId;

/**
* @var string
*/
protected $result;

/**
* @param string $jobId
* @param string $result
*/
public function __construct($jobId, $result)
{
$this->jobId = $jobId;
$this->result = $result;
}

/**
* @return string
*/
public function getJobId()
{
return $this->jobId;
}

/**
* @return string
*/
public function getResult()
{
return $this->result;
}
}
10 changes: 10 additions & 0 deletions src/Events/ScheduleRunBeginEvent.php
@@ -0,0 +1,10 @@
<?php

namespace Infuse\Cron\Events;

use Symfony\Component\EventDispatcher\Event;

class ScheduleRunBeginEvent extends Event
{
const NAME = 'schedule_run.begin';
}
10 changes: 10 additions & 0 deletions src/Events/ScheduleRunFinishedEvent.php
@@ -0,0 +1,10 @@
<?php

namespace Infuse\Cron\Events;

use Symfony\Component\EventDispatcher\Event;

class ScheduleRunFinishedEvent extends Event
{
const NAME = 'schedule_run.finished';
}
58 changes: 57 additions & 1 deletion src/Libs/JobSchedule.php
Expand Up @@ -11,9 +11,13 @@

namespace Infuse\Cron\Libs;

use Infuse\Cron\Events\ScheduleRunBeginEvent;
use Infuse\Cron\Events\ScheduleRunFinishedEvent;
use Infuse\Cron\Models\CronJob;
use Psr\Log\LoggerAwareTrait;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Lock\Factory;

class JobSchedule
Expand All @@ -25,6 +29,11 @@ class JobSchedule
*/
private $jobs;

/**
* @var EventDispatcher
*/
private $dispatcher;

/**
* @var Factory
*/
Expand All @@ -45,6 +54,7 @@ public function __construct(array $jobs, Factory $lockFactory, $namespace = '')
$this->jobs = $jobs;
$this->lockFactory = $lockFactory;
$this->namespace = $namespace;
$this->dispatcher = new EventDispatcher();
}

/**
Expand All @@ -57,6 +67,46 @@ public function getAllJobs()
return $this->jobs;
}

/**
* Gets the event dispatcher.
*
* @return EventDispatcher
*/
public function getEventDispatcher()
{
return $this->dispatcher;
}

/**
* Registers a listener for an event.
*
* @param string $eventName
* @param callable $listener
* @param int $priority
*
* @return $this
*/
public function listen($eventName, callable $listener, $priority = 0)
{
$this->dispatcher->addListener($eventName, $listener, $priority);

return $this;
}

/**
* Registers an event subscriber.
*
* @param EventSubscriberInterface $subscriber
*
* @return $this
*/
public function subscribe(EventSubscriberInterface $subscriber)
{
$this->dispatcher->addSubscriber($subscriber);

return $this;
}

/**
* Gets all of the jobs scheduled to run, now.
*
Expand Down Expand Up @@ -106,13 +156,19 @@ public function runScheduled(OutputInterface $output)
{
$success = true;

$event = new ScheduleRunBeginEvent();
$this->dispatcher->dispatch($event::NAME, $event);

foreach ($this->getScheduledJobs() as $jobInfo) {
$job = $jobInfo['model'];
$run = $this->runJob($job, $jobInfo, $output);

$success = $run->succeeded() && $success;
}

$event = new ScheduleRunFinishedEvent();
$this->dispatcher->dispatch($event::NAME, $event);

return $success;
}

Expand All @@ -131,7 +187,7 @@ private function runJob(CronJob $job, array $jobInfo, OutputInterface $output)

// set up the runner
$class = array_value($jobInfo, 'class');
$runner = new Runner($job, $class, $this->lockFactory, $this->namespace);
$runner = new Runner($job, $class, $this->dispatcher, $this->lockFactory, $this->namespace);
if ($this->logger) {
$runner->setLogger($this->logger);
}
Expand Down
6 changes: 3 additions & 3 deletions src/Libs/Run.php
Expand Up @@ -25,7 +25,7 @@ class Run
private $output = [];

/**
* @var int
* @var string
*/
private $result;

Expand Down Expand Up @@ -69,7 +69,7 @@ public function getOutput()
/**
* Sets the result of the run.
*
* @param int $result
* @param string $result
*
* @return self
*/
Expand All @@ -83,7 +83,7 @@ public function setResult($result)
/**
* Gets the result of the run.
*
* @return int
* @return string
*/
public function getResult()
{
Expand Down
38 changes: 31 additions & 7 deletions src/Libs/Runner.php
Expand Up @@ -3,8 +3,11 @@
namespace Infuse\Cron\Libs;

use Exception;
use Infuse\Cron\Events\CronJobBeginEvent;
use Infuse\Cron\Events\CronJobFinishedEvent;
use Infuse\Cron\Models\CronJob;
use Psr\Log\LoggerAwareTrait;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\Lock\Factory;

class Runner
Expand All @@ -16,6 +19,11 @@ class Runner
*/
private $jobModel;

/**
* @var EventDispatcher
*/
private $dispatcher;

/**
* @var Lock
*/
Expand All @@ -27,15 +35,17 @@ class Runner
private $class;

/**
* @param CronJob $job
* @param string $class callable job class
* @param Factory $lockFactory
* @param string $namespace
* @param CronJob $job
* @param string $class callable job class
* @param EventDispatcher $dispatcher
* @param Factory $lockFactory
* @param string $namespace
*/
public function __construct(CronJob $job, $class, Factory $lockFactory, $namespace = '')
public function __construct(CronJob $job, $class, EventDispatcher $dispatcher, Factory $lockFactory, $namespace = '')
{
$this->jobModel = $job;
$this->class = $class;
$this->dispatcher = $dispatcher;
$this->lock = new Lock($this->jobModel->id, $lockFactory, $namespace);
}

Expand Down Expand Up @@ -79,15 +89,27 @@ public function go($expires = 0, $successUrl = false, Run $run = null)
return $run->setResult(Run::RESULT_LOCKED);
}

// call the `cron_job.begin` event
$event = new CronJobBeginEvent($this->jobModel->id);
$this->dispatcher->dispatch($event::NAME, $event);
if ($event->isPropagationStopped()) {
$run->writeOutput('Rejected by cron_job.begin event listener')
->setResult(Run::RESULT_FAILED);
}

// set up the callable
$job = $this->setUp($this->class, $run);

// this is where the job actually gets called
if ($job) {
if ($job && !$event->isPropagationStopped()) {
$this->invoke($job, $run);
}

// perform post-run tasks:
// call the `cron_job.finished` event
$event = new CronJobFinishedEvent($this->jobModel->id, $run->getResult());
$this->dispatcher->dispatch($event::NAME, $event);

// persist the result
$this->saveRun($run);

Expand Down Expand Up @@ -181,7 +203,9 @@ private function saveRun(Run $run)
}

/**
* Pings a URL about a successful run.
* @deprecated should be moved to an event listener
*
* Pings a URL about a successful run
*
* @param string $url
* @param Run $run
Expand Down
2 changes: 1 addition & 1 deletion src/migrations/20140823163217_cron_job.php
Expand Up @@ -3,7 +3,7 @@
/**
* @author Jared King <j@jaredtking.com>
*
* @link http://jaredtking.com
* @see http://jaredtking.com
*
* @copyright 2015 Jared King
* @license MIT
Expand Down

0 comments on commit 6c0856c

Please sign in to comment.