SAAS-1229 - initial work on bandwidth limit within Airtime; overhaul TaskFactory to get tasks reflectively
This commit is contained in:
parent
c328515f4b
commit
6c2d1f008b
|
@ -3,8 +3,7 @@
|
|||
/**
|
||||
* Class TaskManager
|
||||
*
|
||||
* When adding a new task, the new AirtimeTask class will also need to be added
|
||||
* as a class constant and to the array in TaskFactory
|
||||
* Background class for 'asynchronous' task management for Airtime stations
|
||||
*/
|
||||
final class TaskManager {
|
||||
|
||||
|
@ -34,8 +33,8 @@ final class TaskManager {
|
|||
* Private constructor so class is uninstantiable
|
||||
*/
|
||||
private function __construct() {
|
||||
foreach (array_keys(TaskFactory::$tasks) as $v) {
|
||||
$this->_taskList[$v] = false;
|
||||
foreach (TaskFactory::getTasks() as $k => $task) {
|
||||
$this->_taskList[$task] = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -278,12 +277,12 @@ class ImportCleanupTask implements AirtimeTask {
|
|||
/**
|
||||
* Class StationPodcastTask
|
||||
*
|
||||
* Checks the Station podcast rollover timer and resets monthly allotted
|
||||
* Checks the Station podcast rollover timer and resets allotted
|
||||
* downloads if enough time has passed (default: 1 month)
|
||||
*/
|
||||
class StationPodcastTask implements AirtimeTask {
|
||||
|
||||
const STATION_PODCAST_RESET_TIMER_SECONDS = 2.628e+6; // 1 month XXX: should we use datetime roll for this instead?
|
||||
const STATION_PODCAST_RESET_TIMER_SECONDS = 2.628e+6; // 1 month
|
||||
|
||||
/**
|
||||
* Check whether or not the download counter for the station podcast should be reset
|
||||
|
@ -305,32 +304,74 @@ class StationPodcastTask implements AirtimeTask {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: this and the above StationPodcastTask should probably be unified since the
|
||||
* behaviour is essentially identical
|
||||
*
|
||||
* Class BandwidthLimitTask
|
||||
*
|
||||
* Checks the bandwidth limit rollover timer and resets the allotted
|
||||
* limit if enough time has passed (default: 1 month)
|
||||
*/
|
||||
class BandwidthLimitTask implements AirtimeTask {
|
||||
|
||||
const BANDWIDTH_LIMIT_RESET_TIMER_SECONDS = 2.628e+6;
|
||||
|
||||
/**
|
||||
* Check whether the task should be run
|
||||
*
|
||||
* @return bool true if the task needs to be run, otherwise false
|
||||
*/
|
||||
public function shouldBeRun() {
|
||||
$lastReset = Application_Model_Preference::getBandwidthLimitResetTimer();
|
||||
return empty($lastReset) || (microtime(true) > ($lastReset + self::BANDWIDTH_LIMIT_RESET_TIMER_SECONDS));
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the task
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run() {
|
||||
Application_Model_Preference::resetStationPodcastDownloadCounter();
|
||||
Application_Model_Preference::setBandwidthLimitResetTimer(microtime(true));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Class TaskFactory Factory class to abstract task instantiation
|
||||
*/
|
||||
class TaskFactory {
|
||||
|
||||
/**
|
||||
* PHP doesn't have ENUMs so declare them as constants
|
||||
* Task types - values don't really matter as long as they're unique
|
||||
* Check if the class with the given name implements AirtimeTask
|
||||
*
|
||||
* @param $c string class name
|
||||
*
|
||||
* @return bool true if the class $c implements AirtimeTask
|
||||
*/
|
||||
|
||||
const UPGRADE = "upgrade";
|
||||
const CELERY = "celery";
|
||||
const PODCAST = "podcast";
|
||||
const IMPORT = "import";
|
||||
const STATION_PODCAST = "station-podcast";
|
||||
private static function _isTask($c) {
|
||||
$reflect = new ReflectionClass($c);
|
||||
$clazz = version_compare(phpversion(), '5.5.0', '<') ? "AirtimeTask" : AirtimeTask::class;
|
||||
return $reflect->implementsInterface($clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* @var array map of arbitrary identifiers to class names to be instantiated reflectively
|
||||
* Filter all declared classes to get all classes implementing the AirtimeTask interface
|
||||
*
|
||||
* @return array all classes implementing the AirtimeTask interface
|
||||
*/
|
||||
public static $tasks = array(
|
||||
"upgrade" => "UpgradeTask",
|
||||
"celery" => "CeleryTask",
|
||||
"podcast" => "PodcastTask",
|
||||
"import" => "ImportCleanupTask",
|
||||
"station-podcast" => "StationPodcastTask",
|
||||
);
|
||||
private static function _getTaskClasses() {
|
||||
return array_filter(get_declared_classes(), array(__CLASS__, "_isTask"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function getTasks() {
|
||||
return self::_getTaskClasses();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an AirtimeTask based on a task type
|
||||
|
@ -341,7 +382,7 @@ class TaskFactory {
|
|||
* task exists or is implemented
|
||||
*/
|
||||
public static function getTask($task) {
|
||||
return new self::$tasks[$task]();
|
||||
return new $task();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@ class ApiController extends Zend_Controller_Action
|
|||
|
||||
public function init()
|
||||
{
|
||||
$this->view->layout()->disableLayout();
|
||||
$this->_helper->viewRenderer->setNoRender(true);
|
||||
|
||||
//Ignore API key and session authentication for these APIs:
|
||||
$ignoreAuth = array("live-info",
|
||||
|
@ -101,14 +103,6 @@ class ApiController extends Zend_Controller_Action
|
|||
exit();
|
||||
}
|
||||
|
||||
public function pollCeleryAction() {
|
||||
$this->view->layout()->disableLayout();
|
||||
$this->_helper->viewRenderer->setNoRender(true);
|
||||
|
||||
$taskManager = TaskManager::getInstance();
|
||||
$taskManager->runTask(TaskFactory::CELERY);
|
||||
}
|
||||
|
||||
public function versionAction()
|
||||
{
|
||||
$this->_helper->json->sendJson( array(
|
||||
|
@ -136,6 +130,35 @@ class ApiController extends Zend_Controller_Action
|
|||
$this->_helper->json->sendJson(array());
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually trigger the TaskManager task to poll for completed Celery tasks
|
||||
*/
|
||||
public function pollCeleryAction() {
|
||||
$taskManager = TaskManager::getInstance();
|
||||
$clazz = version_compare(phpversion(), '5.5.0', '<') ? get_class(new CeleryTask) : CeleryTask::class;
|
||||
$taskManager->runTask($clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: move this function into a more generic analytics REST controller
|
||||
*
|
||||
* Update station bandwidth usage based on icecast log data
|
||||
*/
|
||||
public function bandwidthUsageAction() {
|
||||
// FIXME: this function is using placeholder names
|
||||
$bandwidthUsage = json_decode($this->getRequest()->getParam("bandwidth_usage"));
|
||||
$usageBytes = 0;
|
||||
foreach ($bandwidthUsage as $entry) {
|
||||
Logging::info($entry);
|
||||
// TODO: store the IP address for future use
|
||||
$ts = strtotime($entry->timestamp);
|
||||
if ($ts > Application_Model_Preference::getBandwidthLimitUpdateTimer()) {
|
||||
$usageBytes += $entry->bytes;
|
||||
}
|
||||
}
|
||||
Application_Model_Preference::incrementBandwidthLimitCounter($usageBytes);
|
||||
}
|
||||
|
||||
//Used by the SaaS monitoring
|
||||
public function onAirLightAction()
|
||||
{
|
||||
|
|
|
@ -64,7 +64,8 @@ class PageLayoutInitPlugin extends Zend_Controller_Plugin_Abstract
|
|||
// We can't afford to wait 7 minutes to run an upgrade: users could
|
||||
// have several minutes of database errors while waiting for a
|
||||
// schema change upgrade to happen after a deployment
|
||||
$taskManager->runTask(TaskFactory::UPGRADE);
|
||||
$clazz = version_compare(phpversion(), '5.5.0', '<') ? get_class(new UpgradeTask) : UpgradeTask::class;
|
||||
$taskManager->runTask($clazz);
|
||||
|
||||
// Piggyback the TaskManager onto API calls. This provides guaranteed consistency
|
||||
// (there is at least one API call made from pypo to Airtime every 7 minutes) and
|
||||
|
|
|
@ -1584,4 +1584,33 @@ class Application_Model_Preference
|
|||
public static function setStationPodcastPrivacy($value) {
|
||||
self::setValue("station_podcast_privacy", $value);
|
||||
}
|
||||
|
||||
public static function getBandwidthLimitCounter() {
|
||||
return self::getValue("bandwidth_limit_counter");
|
||||
}
|
||||
|
||||
public static function incrementBandwidthLimitCounter($value) {
|
||||
$counter = intval(self::getValue("bandwidth_limit_counter"));
|
||||
self::setValue("bandwidth_limit_counter", $counter + intval($value));
|
||||
}
|
||||
|
||||
public static function resetBandwidthLimitCounter() {
|
||||
self::setValue("bandwidth_limit_counter", 0);
|
||||
}
|
||||
|
||||
public static function getBandwidthLimitResetTimer() {
|
||||
return self::getValue("bandwidth_limit_reset_timer");
|
||||
}
|
||||
|
||||
public static function setBandwidthLimitResetTimer($value) {
|
||||
self::setValue("bandwidth_limit_reset_timer", $value);
|
||||
}
|
||||
|
||||
public static function getBandwidthLimitUpdateTimer() {
|
||||
return self::getValue("bandwidth_limit_reset_timer");
|
||||
}
|
||||
|
||||
public static function setBandwidthLimitUpdateTimer() {
|
||||
self::setValue("bandwidth_limit_reset_timer", microtime(true));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue