Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add alerts via slack and mattermost when the job fail #133

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
21 changes: 13 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
# Jobby, a PHP cron job manager #
[![Total Downloads](https://img.shields.io/packagist/dt/hellogerard/jobby.svg)](https://packagist.org/packages/hellogerard/jobby)
[![Latest Version](https://img.shields.io/packagist/v/hellogerard/jobby.svg)](https://packagist.org/packages/hellogerard/jobby)
[![Build Status](https://img.shields.io/travis/jobbyphp/jobby.svg)](https://travis-ci.org/jobbyphp/jobby)
[![MIT License](https://img.shields.io/packagist/l/hellogerard/jobby.svg)](https://github.com/jobbyphp/jobby/blob/master/LICENSE)
[![Total Downloads](https://img.shields.io/packagist/dt/hatimox/jobby.svg)](https://packagist.org/packages/hatimox/jobby)
[![Latest Version](https://img.shields.io/packagist/v/hatimox/jobby.svg)](https://packagist.org/packages/hatimox/jobby)
[![Build Status](https://img.shields.io/travis/hatimox/jobby.svg)](https://travis-ci.org/hatimox/jobby)
[![MIT License](https://img.shields.io/packagist/l/hatimox/jobby.svg)](https://github.com/hatimox/jobby/blob/master/LICENSE)

Install the master jobby cron job, and it will manage all your offline tasks. Add jobs without modifying crontab.
Jobby can handle logging, locking, error emails and more.

**NEW REPO:** We have moved `jobby` to a Github org. Please update your remotes to `https://github.com/jobbyphp/jobby.git`.

## Features ##

- Maintain one master crontab job.
Expand All @@ -19,14 +17,15 @@ Jobby can handle logging, locking, error emails and more.
- Run job as another user, if crontab user has `sudo` privileges.
- Run only on certain hostnames (handy in webfarms).
- Theoretical Windows support (but not ever tested)
- Send alerts to Slack or Mattermost whenever a job exits with an error status.

## Getting Started ##

### Installation ###

The recommended way to install Jobby is through [Composer](http://getcomposer.org):
```
$ composer require hellogerard/jobby
$ composer require hatimox/jobby
```

Then add the following line to your (or whomever's) crontab:
Expand All @@ -36,7 +35,7 @@ Then add the following line to your (or whomever's) crontab:

After Jobby installs, you can copy an example file to the project root.
```
$ cp vendor/hellogerard/jobby/resources/jobby.php .
$ cp vendor/hatimox/jobby/resources/jobby.php .
```

### Running a job ###
Expand Down Expand Up @@ -208,13 +207,19 @@ dateFormat | string | Y-m-d H:i:s | Format for da
_**Mailing**_ | | | _**Options for emailing errors**_
recipients | string | null | Comma-separated string of email addresses
mailer | string | sendmail | Email method: _sendmail_ or _smtp_ or _mail_
mailSubject | string | null | Email subject
smtpHost | string | null | SMTP host, if `mailer` is smtp
smtpPort | integer | 25 | SMTP port, if `mailer` is smtp
smtpUsername | string | null | SMTP user, if `mailer` is smtp
smtpPassword | string | null | SMTP password, if `mailer` is smtp
smtpSecurity | string | null | SMTP security option: _ssl_ or _tls_, if `mailer` is smtp
smtpSender | string | jobby@<hostname> | The sender and from addresses used in SMTP notices
smtpSenderName | string | Jobby | The name used in the from field for SMTP messages
_**Notifications**_ | | | _**Options for sending Alerts when errors**_
mattermostUrl | string | null | The webhook url from Mattermost
slackChannel | string | null | The name of Slack Channel (#channel)
slackUrl | string | null | The webhook url from Slack
slackSender | string | null | The name used in the from field for Slack

## Symfony integration ##

Expand Down
17 changes: 7 additions & 10 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
{
"name": "hellogerard/jobby",
"homepage": "https://github.com/jobbyphp/jobby",
"name": "hatimox/jobby",
"homepage": "https://github.com/hatimox/jobby",
"license": "MIT",
"description": "Manage all your cron jobs without modifying crontab. Handles locking, logging, error emails, and more.",
"authors": [
{
"name": "Gerard Sychay",
"email": "[email protected]",
"homepage": "https://github.com/hellogerard"
},
{
"name": "Michael Contento",
"homepage": "https://github.com/michaelcontento"
"name": "Hatim HAFFANE",
"email": "[email protected]",
"homepage": "https://github.com/hatimox"
}
],
"require": {
"php": ">=5.6",
"php": ">=7.4",
"alek13/slack": "^2.2",
"dragonmantank/cron-expression": "^3.0",
"opis/closure": "^3.5",
"swiftmailer/swiftmailer": "^5.4|^6.0",
Expand Down
49 changes: 44 additions & 5 deletions src/BackgroundJob.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,11 @@ public function __construct($job, array $config, Helper $helper = null)
'dateFormat' => null,
'enabled' => null,
'haltDir' => null,
'debug' => null,
'mattermostUrl' => null,
'slackChannel' => null,
'slackUrl' => null,
'slackSender' => null,
'mailSubject' => null,
];

$this->config['output_stdout'] = $this->config['output_stdout'] === null ? $this->config['output'] : $this->config['output_stdout'];
Expand All @@ -73,7 +77,7 @@ public function run()
$this->checkMaxRuntime($lockFile);
} catch (Exception $e) {
$this->log('ERROR: ' . $e->getMessage(), 'stderr');
$this->mail($e->getMessage());
$this->notify($e->getMessage());

return;
}
Expand All @@ -96,15 +100,15 @@ public function run()
$this->log('INFO: ' . $e->getMessage(), 'stderr');
} catch (Exception $e) {
$this->log('ERROR: ' . $e->getMessage(), 'stderr');
$this->mail($e->getMessage());
$this->notify($e->getMessage());
}

if ($lockAcquired) {
$this->helper->releaseLock($lockFile);

// remove log file if empty
$logfile = $this->getLogfile();
if (is_file($logfile) && filesize($logfile) <= 0) {
if (is_file($logfile) && (filesize($logfile) <= 2 || file_get_contents($logfile) == "[]")) {
unlink($logfile);
}
}
Expand Down Expand Up @@ -144,6 +148,7 @@ protected function checkMaxRuntime($lockFile)

/**
* @param string $message
* Deprecated
*/
protected function mail($message)
{
Expand All @@ -158,6 +163,38 @@ protected function mail($message)
);
}

/**
* @param string $message
*/
protected function notify($message)
{
if (!empty($this->config['recipients'])) {
$this->helper->sendMail(
$this->job,
$this->config,
$message
);
}

if (!empty($this->config['mattermostUrl'])) {
$this->helper->sendMattermostAlert(
$this->job,
$this->config,
$message
);
}

if (!empty($this->config['slackChannel']) && !empty($this->config['slackUrl'])) {
$this->helper->sendSlackAlert(
$this->job,
$this->config,
$message
);
}


}

/**
* @param string $output
* @return string
Expand Down Expand Up @@ -246,7 +283,9 @@ protected function runFunction()
}
$content = ob_get_contents();
if ($logfile = $this->getLogfile()) {
file_put_contents($this->getLogfile(), $content, FILE_APPEND);
if(strlen($content) > 2){
file_put_contents($this->getLogfile(), $content, FILE_APPEND);
}
}
ob_end_clean();

Expand Down
79 changes: 73 additions & 6 deletions src/Helper.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<?php
namespace Jobby;

use GuzzleHttp\Client as Guzzle;

class Helper
{
/**
Expand All @@ -23,12 +25,21 @@ class Helper
*/
private $mailer;

/**
* The Guzzle HTTP client instance
*
* @var \GuzzleHttp\Client
*/
protected $guzzle;


/**
* @param \Swift_Mailer $mailer
*/
public function __construct(\Swift_Mailer $mailer = null)
{
$this->mailer = $mailer;
$this->guzzle = new Guzzle;
}

/**
Expand All @@ -42,16 +53,21 @@ public function sendMail($job, array $config, $message)
{
$host = $this->getHost();
$body = <<<EOF
$message
$message

You can find its output in {$config['output']} on $host.
You can find its output in {$config['output']} on $host.

Best,
jobby@$host
EOF;
Best,
jobby@$host
EOF;

$mail = new \Swift_Message();
$mail->setTo(explode(',', $config['recipients']));
$mail->setSubject("[$host] '{$job}' needs some attention!");
if(empty($config['mailSubject'])){
$mail->setSubject("[$host] '{$job}' needs some attention!");
}else{
$mail->setSubject($config['mailSubject']);
}
$mail->setBody($body);
$mail->setFrom([$config['smtpSender'] => $config['smtpSenderName']]);
$mail->setSender($config['smtpSender']);
Expand Down Expand Up @@ -249,4 +265,55 @@ public function getSystemNullDevice()
}
return 'NUL';
}

/**
* @param string $job
* @param array $config
* @param string $message
*
* @return void
*/
public function sendSlackAlert($job, array $config, $message)
{
$host = $this->getHost();
$body = <<<EOF
$message

You can find its output in {$config['output']} on $host.

Best,
jobby@$host
EOF;
$client = new \Maknz\Slack\Client($config['slackUrl']);
$client->to($config['slackChannel']);
if($config['slackSender']){
$client->from($config['slackSender']);
}
$client->send($body);

}

/**
* @param string $job
* @param array $config
* @param string $message
*
* @return void
*/
public function sendMattermostAlert($job, array $config, $message)
{
$host = $this->getHost();
$body = <<<EOF
$message

You can find its output in {$config['output']} on $host.

Best,
jobby@$host
EOF;
$payload = ['text'=>$body];
$encoded = json_encode($payload, JSON_UNESCAPED_UNICODE);
$this->guzzle->post($config['mattermostUrl'], ['body' => $encoded]);

}
}
5 changes: 5 additions & 0 deletions src/Jobby.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ public function getDefaultConfig()
'enabled' => true,
'haltDir' => null,
'debug' => false,
'mattermostUrl' => null,
'slackChannel' => null,
'slackUrl' => null,
'slackSender' => null,
'mailSubject' => null,
];
}

Expand Down