Skip to content

Commit

Permalink
Merge pull request #72 from matomo-org/notifyemail
Browse files Browse the repository at this point in the history
Send email notification when queue reaches a certain size
  • Loading branch information
tsteur authored Apr 16, 2018
2 parents 411a6f2 + cc47f4b commit 7b467c7
Show file tree
Hide file tree
Showing 8 changed files with 276 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
- Added possibility to use a MySQL backend instead of redis
- New option `queue-id` for the `queuedtracking:process` command which may improve processing speed as the command would only focus on one queue instead of trying to get the lock for a random queue.
- Various other minor performance improvements
- New feature: Get notified by email when a single queue reaches a specific threshold

3.0.2

Expand Down
93 changes: 93 additions & 0 deletions Configuration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\QueuedTracking;

use Piwik\Config;

class Configuration
{
public static $DEFAULT_NOTIFY_EMAILS = [];
const DEFAULT_NOTIFY_THRESHOLD = 250000;
const KEY_NOTIFY_EMAILS = 'notify_queue_threshold_emails';
const KEY_NOTIFY_THRESHOLD = 'notify_queue_threshold_single_queue';

public function install()
{
$config = $this->getConfig();

if (empty($config->QueuedTracking)) {
$config->QueuedTracking = array();
}
$reports = $config->QueuedTracking;

// we make sure to set a value only if none has been configured yet, eg in common config.
if (empty($reports[self::KEY_NOTIFY_THRESHOLD])) {
$reports[self::KEY_NOTIFY_THRESHOLD] = self::DEFAULT_NOTIFY_THRESHOLD;
}
if (empty($reports[self::KEY_NOTIFY_EMAILS])) {
$reports[self::KEY_NOTIFY_EMAILS] = self::$DEFAULT_NOTIFY_EMAILS;
}
$config->QueuedTracking = $reports;

$config->forceSave();
}

public function uninstall()
{
$config = $this->getConfig();
$config->QueuedTracking = array();
$config->forceSave();
}

/**
* @return int
*/
public function getNotifyThreshold()
{
$value = $this->getConfigValue(self::KEY_NOTIFY_THRESHOLD, self::DEFAULT_NOTIFY_THRESHOLD);

if ($value === false || $value === '' || $value === null) {
$value = self::DEFAULT_NOTIFY_THRESHOLD;
}

return (int) $value;
}

/**
* @return array
*/
public function getNotifyEmails()
{
$value = $this->getConfigValue(self::KEY_NOTIFY_EMAILS, self::$DEFAULT_NOTIFY_EMAILS);

if (empty($value)) {
$value = self::$DEFAULT_NOTIFY_EMAILS;
}
if (!is_array($value)) {
$value = array($value);
}

return $value;
}

private function getConfig()
{
return Config::getInstance();
}

private function getConfigValue($name, $default)
{
$config = $this->getConfig();
$attribution = $config->QueuedTracking;
if (isset($attribution[$name])) {
return $attribution[$name];
}
return $default;
}
}
5 changes: 5 additions & 0 deletions Queue/Backend/MySQL.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ public function install()
UNIQUE unique_queue_key (`queue_key`)");
}

public function uninstall()
{
Db::query(sprintf('DROP TABLE IF EXISTS `%s`', $this->tablePrefixed));
}

private function makePrefixedKeyListTableName($key)
{
return Common::prefixTable($this->tableListPrefix . $key);
Expand Down
12 changes: 12 additions & 0 deletions QueuedTracking.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,18 @@ public function install()
{
$mysql = new MySQL();
$mysql->install();

$configuration = new Configuration();
$configuration->install();
}

public function uninstall()
{
$mysql = new MySQL();
$mysql->uninstall();

$configuration = new Configuration();
$configuration->uninstall();
}

public function isTrackerPlugin()
Expand Down
67 changes: 67 additions & 0 deletions Tasks.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,81 @@
namespace Piwik\Plugins\QueuedTracking;

use Piwik\Common;
use Piwik\Config;
use Piwik\Db;
use Piwik\Mail;
use Piwik\Plugins\QueuedTracking\Queue\Backend\MySQL;
use Piwik\SettingsPiwik;

class Tasks extends \Piwik\Plugin\Tasks
{
/**
* @var Configuration
*/
private $config;

public function __construct(Configuration $configuration)
{
$this->config = $configuration;
}

public function schedule()
{
$this->daily('optimizeQueueTable', null, self::LOWEST_PRIORITY);
$this->hourly('notifyQueueSize', null, self::LOWEST_PRIORITY);
}

/**
* run eg using ./console core:run-scheduled-tasks "Piwik\Plugins\QueuedTracking\Tasks.notifyQueueSize"
*/
public function notifyQueueSize()
{
$settings = Queue\Factory::getSettings();

if (!$settings->queueEnabled->getValue()) {
// not needed to check anything
return;
}

$emailsToNotify = $this->config->getNotifyEmails();
$threshold = $this->config->getNotifyThreshold();

if (empty($emailsToNotify) || empty($threshold) || $threshold <= 0) {
// nobody to notify or no threshold defined
return;
}

$backend = Queue\Factory::makeBackend();
$queueManager = Queue\Factory::makeQueueManager($backend);

$larger = "";
$smaller = "";

foreach ($queueManager->getAllQueues() as $queue) {
$size = $queue->getNumberOfRequestSetsInQueue();
$entriesMessage = sprintf("Queue ID %s has %s entries.<br />", $queue->getId(), $size);
if ($size >= $threshold) {
$larger .= $entriesMessage;
} else {
$smaller .= $entriesMessage;
}
}

if (!empty($larger)) {
$message = sprintf("This is a notification that the threshold %s for a single queue has been reached.<br /><br />The following queue sizes are greater than the threshold: <br />%s", $threshold, $larger);

if (!empty($smaller)) {
$message .= sprintf("<br /><br />The remaining queue sizes, which are below the threshold, are listed below: <br />%s", $smaller);
}

$message = $message . "<br /><br />Sent from " . SettingsPiwik::getPiwikUrl();
$mail = new Mail();
$mail->setDefaultFromPiwik();
$mail->addTo($emailsToNotify);
$mail->setSubject('Queued Tracking - queue size has reached your threshold');
$mail->setBodyHtml($message);
$mail->send();
}
}

/**
Expand Down
4 changes: 4 additions & 0 deletions Updates/3.2.0.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

namespace Piwik\Plugins\QueuedTracking;

use Piwik\Config;
use Piwik\Updater;
use Piwik\Updates as PiwikUpdates;
use Piwik\Updater\Migration\Factory as MigrationFactory;
Expand Down Expand Up @@ -42,5 +43,8 @@ public function getMigrations(Updater $updater)
public function doUpdate(Updater $updater)
{
$updater->executeMigrations(__FILE__, $this->getMigrations($updater));

$config = new Configuration();
$config->install();
}
}
11 changes: 11 additions & 0 deletions docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,17 @@ __Can I configure multiple Sentinel servers?__

Yes, once Sentinel is enabled you can configure multiple servers by specifying multiple hosts and ports comma separated via the UI.

__Can I be notified when a queue reaches a certain threshold?__

Yes, you can optionally receive an email when the number of requests queued in a single queue reaches a configured
threshold. You can configure this in your `config/config.ini.php` config file using the following configuration:

```
[QueuedTracking]
notify_queue_threshold_emails[] = [email protected]
notify_queue_threshold_single_queue = 250000
```

__Are there any known issues?__

* In case you are using bulk tracking the bulk tracking response varies compared to the regular one. We will always return
Expand Down
83 changes: 83 additions & 0 deletions tests/Unit/ConfigurationTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\QueuedTracking\tests\Unit;

use Piwik\Config;
use Piwik\Plugins\QueuedTracking\Configuration;

/**
* @group QueuedTracking
* @group Plugins
*/
class ConfigurationTest extends \PHPUnit_Framework_TestCase
{
/**
* @var Configuration
*/
private $configuration;

public function setUp()
{
parent::setUp();

$this->configuration = new Configuration();
}

public function test_shouldInstallConfig()
{
$this->configuration->install();

$QueuedTracking = Config::getInstance()->QueuedTracking;
$this->assertEquals(array(
'notify_queue_threshold_single_queue' => Configuration::DEFAULT_NOTIFY_THRESHOLD,
'notify_queue_threshold_emails' => Configuration::$DEFAULT_NOTIFY_EMAILS
), $QueuedTracking);
}

public function test_getNotifyThreshold_shouldReturnDefaultThreshold()
{
$this->assertEquals(250000, $this->configuration->getNotifyThreshold());
}

public function test_getNotifyThreshold_shouldBePossibleToChangeValue()
{
Config::getInstance()->QueuedTracking = array(
Configuration::KEY_NOTIFY_THRESHOLD => 150
);
$this->assertEquals(150, $this->configuration->getNotifyThreshold());
}

public function test_getNotifyThreshold_noConfig_shouldReturnDefault()
{
Config::getInstance()->QueuedTracking = array();
$this->assertEquals(Configuration::DEFAULT_NOTIFY_THRESHOLD, $this->configuration->getNotifyThreshold());
}


public function test_getNotifyEmails_shouldReturnDefaultThreshold()
{
$this->assertEquals(array(), $this->configuration->getNotifyEmails());
}

public function test_getNotifyEmails_shouldBePossibleToChangeValue()
{
Config::getInstance()->QueuedTracking = array(
Configuration::KEY_NOTIFY_EMAILS => ['[email protected]']
);
$this->assertEquals(['[email protected]'], $this->configuration->getNotifyEmails());
}

public function test_getNotifyEmails_noConfig_shouldReturnDefault()
{
Config::getInstance()->QueuedTracking = array();
$this->assertEquals(Configuration::$DEFAULT_NOTIFY_EMAILS, $this->configuration->getNotifyEmails());
}


}

0 comments on commit 7b467c7

Please sign in to comment.