├── .gitignore ├── Config ├── Schema │ ├── empty │ └── schema.php └── queue.php.default ├── Console └── Command │ ├── QueueShell.php │ └── Task │ └── empty ├── Controller ├── Component │ └── empty ├── QueueAppController.php └── QueueTasksController.php ├── Lib ├── Queue.php ├── QueueUtil.php └── empty ├── Model ├── Behavior │ └── empty ├── Datasource │ └── empty ├── QueueAppModel.php ├── QueueTask.php └── QueueTaskLog.php ├── Test ├── Case │ ├── Controller │ │ ├── Component │ │ │ └── empty │ │ └── QueueTasksControllerTest.php │ ├── Model │ │ ├── Behavior │ │ │ └── empty │ │ └── QueueTaskTest.php │ └── View │ │ └── Helper │ │ └── empty └── Fixture │ ├── QueueTaskFixture.php │ ├── QueueTaskLogFixture.php │ └── empty ├── Vendor └── empty ├── View ├── Helper │ └── empty └── QueueTasks │ ├── admin_add.ctp │ ├── admin_edit.ctp │ ├── admin_index.ctp │ └── admin_view.ctp ├── composer.json ├── readme.markdown ├── scripts └── process.sh └── webroot └── empty /.gitignore: -------------------------------------------------------------------------------- 1 | notes.txt 2 | -------------------------------------------------------------------------------- /Config/Schema/empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webtechnick/CakePHP-Queue-Plugin/996623bc0265cee13d3ee17e3022457eb3d4f465/Config/Schema/empty -------------------------------------------------------------------------------- /Config/Schema/schema.php: -------------------------------------------------------------------------------- 1 | array('type' => 'string', 'null' => false, 'default' => null, 'length' => 36, 'key' => 'primary', 'collate' => 'utf8_general_ci', 'charset' => 'utf8'), 13 | 'user_id' => array('type' => 'biginteger', 'null' => true, 'default' => null, 'length' => 22, 'comment' => 'user_id of who created/modified this queue. optional'), 14 | 'created' => array('type' => 'datetime', 'null' => true, 'default' => null, 'key' => 'index'), 15 | 'modified' => array('type' => 'datetime', 'null' => true, 'default' => null), 16 | 'executed' => array('type' => 'datetime', 'null' => true, 'default' => null, 'key' => 'index', 'comment' => 'datetime when executed.'), 17 | 'scheduled' => array('type' => 'datetime', 'null' => true, 'default' => null, 'key' => 'index', 'comment' => 'When the task is scheduled. if null as soon as possible. Otherwise it will be first on list if it\'s the highest scheduled.'), 18 | 'scheduled_end' => array('type' => 'datetime', 'null' => true, 'default' => null, 'key' => 'index', 'comment' => 'If we go past this time, don\'t execute. We need to reschedule based on reschedule.'), 19 | 'reschedule' => array('type' => 'string', 'null' => true, 'default' => null, 'length' => 50, 'collate' => 'utf8_general_ci', 'comment' => 'strtotime parsable addition to scheduled until in future if window is not null.', 'charset' => 'utf8'), 20 | 'start_time' => array('type' => 'biginteger', 'null' => true, 'default' => null, 'length' => 22, 'comment' => 'microtime start of execution.'), 21 | 'end_time' => array('type' => 'biginteger', 'null' => true, 'default' => null, 'length' => 22, 'comment' => 'microtime end of execution.'), 22 | 'cpu_limit' => array('type' => 'integer', 'null' => true, 'default' => null, 'length' => 3, 'key' => 'index', 'comment' => 'percent limit of cpu to execute. (95 = less than 95% cpu usage)'), 23 | 'is_restricted' => array('type' => 'boolean', 'null' => false, 'default' => '0', 'key' => 'index', 'comment' => 'will be 1 if hour, day, or cpu_limit are not null.'), 24 | 'priority' => array('type' => 'integer', 'null' => false, 'default' => '100', 'length' => 4, 'key' => 'index', 'comment' => 'priorty, lower the number, the higher on the list it will run.'), 25 | 'status' => array('type' => 'integer', 'null' => false, 'default' => '1', 'length' => 2, 'key' => 'index', 'comment' => '1:queued,2:inprogress,3:finished,4:paused'), 26 | 'type' => array('type' => 'integer', 'null' => false, 'default' => null, 'length' => 2, 'key' => 'index', 'comment' => '1:model,2:shell,3:url,4:php_cmd,5:shell_cmd'), 27 | 'command' => array('type' => 'text', 'null' => false, 'default' => null, 'collate' => 'utf8_general_ci', 'charset' => 'utf8'), 28 | 'result' => array('type' => 'text', 'null' => true, 'default' => null, 'collate' => 'utf8_general_ci', 'charset' => 'utf8'), 29 | 'indexes' => array( 30 | 'PRIMARY' => array('column' => 'id', 'unique' => 1), 31 | 'status' => array('column' => 'status', 'unique' => 0), 32 | 'type' => array('column' => 'type', 'unique' => 0), 33 | 'created' => array('column' => 'created', 'unique' => 0), 34 | 'priority' => array('column' => 'priority', 'unique' => 0), 35 | 'is_restricted' => array('column' => 'is_restricted', 'unique' => 0), 36 | 'cpu_limit' => array('column' => 'cpu_limit', 'unique' => 0), 37 | 'executed' => array('column' => 'executed', 'unique' => 0), 38 | 'scheduled' => array('column' => 'scheduled', 'unique' => 0), 39 | 'scheduled_end' => array('column' => 'scheduled_end', 'unique' => 0) 40 | ), 41 | 'tableParameters' => array('charset' => 'utf8', 'collate' => 'utf8_general_ci', 'engine' => 'InnoDB') 42 | ); 43 | 44 | public $queue_tasks = array( 45 | 'id' => array('type' => 'string', 'null' => false, 'default' => null, 'length' => 36, 'key' => 'primary', 'collate' => 'utf8_general_ci', 'charset' => 'utf8'), 46 | 'user_id' => array('type' => 'biginteger', 'null' => true, 'default' => null, 'length' => 22, 'comment' => 'user_id of who created/modified this queue. optional'), 47 | 'created' => array('type' => 'datetime', 'null' => true, 'default' => null, 'key' => 'index'), 48 | 'modified' => array('type' => 'datetime', 'null' => true, 'default' => null), 49 | 'executed' => array('type' => 'datetime', 'null' => true, 'default' => null, 'key' => 'index', 'comment' => 'datetime when executed.'), 50 | 'scheduled' => array('type' => 'datetime', 'null' => true, 'default' => null, 'key' => 'index', 'comment' => 'When the task is scheduled. if null as soon as possible. Otherwise it will be first on list if it\'s the highest scheduled.'), 51 | 'scheduled_end' => array('type' => 'datetime', 'null' => true, 'default' => null, 'key' => 'index', 'comment' => 'If we go past this time, don\'t execute. We need to reschedule based on reschedule.'), 52 | 'reschedule' => array('type' => 'string', 'null' => true, 'default' => null, 'length' => 50, 'collate' => 'utf8_general_ci', 'comment' => 'strtotime parsable addition to scheduled until in future if window is not null.', 'charset' => 'utf8'), 53 | 'start_time' => array('type' => 'biginteger', 'null' => true, 'default' => null, 'length' => 22, 'comment' => 'microtime start of execution.'), 54 | 'end_time' => array('type' => 'biginteger', 'null' => true, 'default' => null, 'length' => 22, 'comment' => 'microtime end of execution.'), 55 | 'cpu_limit' => array('type' => 'integer', 'null' => true, 'default' => null, 'length' => 3, 'key' => 'index', 'comment' => 'percent limit of cpu to execute. (95 = less than 95% cpu usage)'), 56 | 'is_restricted' => array('type' => 'boolean', 'null' => false, 'default' => '0', 'key' => 'index', 'comment' => 'will be 1 if hour, day, or cpu_limit are not null.'), 57 | 'priority' => array('type' => 'integer', 'null' => false, 'default' => '100', 'length' => 4, 'key' => 'index', 'comment' => 'priorty, lower the number, the higher on the list it will run.'), 58 | 'status' => array('type' => 'integer', 'null' => false, 'default' => '1', 'length' => 2, 'key' => 'index', 'comment' => '1:queued,2:inprogress,3:finished,4:paused'), 59 | 'type' => array('type' => 'integer', 'null' => false, 'default' => null, 'length' => 2, 'key' => 'index', 'comment' => '1:model,2:shell,3:url,4:php_cmd,5:shell_cmd'), 60 | 'command' => array('type' => 'text', 'null' => false, 'default' => null, 'collate' => 'utf8_general_ci', 'charset' => 'utf8'), 61 | 'result' => array('type' => 'text', 'null' => true, 'default' => null, 'collate' => 'utf8_general_ci', 'charset' => 'utf8'), 62 | 'indexes' => array( 63 | 'PRIMARY' => array('column' => 'id', 'unique' => 1), 64 | 'status' => array('column' => 'status', 'unique' => 0), 65 | 'type' => array('column' => 'type', 'unique' => 0), 66 | 'created' => array('column' => 'created', 'unique' => 0), 67 | 'priority' => array('column' => 'priority', 'unique' => 0), 68 | 'is_restricted' => array('column' => 'is_restricted', 'unique' => 0), 69 | 'cpu_limit' => array('column' => 'cpu_limit', 'unique' => 0), 70 | 'executed' => array('column' => 'executed', 'unique' => 0), 71 | 'scheduled' => array('column' => 'scheduled', 'unique' => 0), 72 | 'scheduled_end' => array('column' => 'scheduled_end', 'unique' => 0) 73 | ), 74 | 'tableParameters' => array('charset' => 'utf8', 'collate' => 'utf8_general_ci', 'engine' => 'InnoDB') 75 | ); 76 | 77 | } 78 | -------------------------------------------------------------------------------- /Config/queue.php.default: -------------------------------------------------------------------------------- 1 | array( 9 | 'log' => true, //logs every task run in a log file. 10 | 'limit' => 1, //limit how many queues can run at a time. (default 1). 11 | 'allowedTypes' => array( //restrict what type of command can be queued. 12 | 1, //model 13 | 2, //shell 14 | 3, //url 15 | //4, //php_cmd 16 | //5, //shell_cmd 17 | ), 18 | 'archiveAfterExecute' => true, //will archive the task once finished executing for quicker queues 19 | 'cache' => '+5 minute', //how long to cache cpu usage and list. (false disables cache) 20 | 'cores' => '8', //number of cpu cores to correctly gauge current CPU load. 21 | 'userIdMethod' => false, //Function to call on QueueAppModel to obtain the value for user_id (ships with _getUserId, defaults to off) 22 | ) 23 | ); 24 | -------------------------------------------------------------------------------- /Console/Command/QueueShell.php: -------------------------------------------------------------------------------- 1 | QueueTask = ClassRegistry::init('Queue.QueueTask'); 20 | } 21 | 22 | /** 23 | * {@inheritDoc} 24 | */ 25 | public function getOptionParser() { 26 | $parser = parent::getOptionParser(); 27 | return $parser->description( 28 | 'The Queue shell.' . 29 | '') 30 | ->addSubcommand('add', array( 31 | 'help' => __('Add a task to the queue.'), 32 | 'parser' => array( 33 | 'description' => array( 34 | __('Use this command to add tasks to the queue') 35 | ), 36 | 'arguments' => array( 37 | 'command' => array( 38 | 'help' => __('The actual command string'), 39 | 'required' => true, 40 | //'short' => 'c', 41 | ) 42 | ), 43 | 'options' => array( 44 | 'type' => array( 45 | 'help' => __('The type of task command.'), 46 | 'required' => true, 47 | 'short' => 't', 48 | 'default' => 'model', 49 | 'choices' => array_values($this->QueueTask->_types) 50 | ), 51 | 'start' => array( 52 | 'help' => __('optional: strtotime parsable scheduled date to execute. \'Sunday 11 pm\',\'Tuesday 2 am\' (default null = no restriction)'), 53 | 'short' => 's', 54 | 'default' => null 55 | ), 56 | 'end' => array( 57 | 'help' => __('optional: strtotime parsable scheduled end date to execute. \'Monday 4am\' (default null = no restriction)'), 58 | 'short' => 'e', 59 | 'default' => null 60 | ), 61 | 'reschedule' => array( 62 | 'help' => __('optional: string of addition to scheduled if window of start and end are missed. Parsable by strtotime. \'+1 day\', \'+1 week\' (default null, required if end is not null)'), 63 | 'short' => 'r', 64 | 'default' => null 65 | ), 66 | 'cpu' => array( 67 | 'help' => __('optional: CPU Percent Limit to run task, 0-100. \'95\',\'10\' (default null = no restriction)'), 68 | 'short' => 'c', 69 | 'default' => null 70 | ), 71 | 'priority' => array( 72 | 'help' => __('optional: Priority of task, lower number the sooner it will run. \'5\',\'100\''), 73 | 'short' => 'p', 74 | 'default' => 100 75 | ), 76 | ) 77 | ) 78 | ) 79 | ) 80 | ->addSubcommand('run', array( 81 | 'help' => __('Run a task in the queue.'), 82 | 'parser' => array( 83 | 'description' => array( 84 | __('Use this command to run a paticular queue') 85 | ), 86 | 'arguments' => array( 87 | 'id' => array( 88 | 'help' => __('UUID of queue to run'), 89 | 'required' => true, 90 | ) 91 | ) 92 | ) 93 | ) 94 | ) 95 | ->addSubcommand('view', array( 96 | 'help' => __('View a task in the queue.'), 97 | 'parser' => array( 98 | 'description' => array( 99 | __('Use this command to view a paticular queue. Including results.') 100 | ), 101 | 'arguments' => array( 102 | 'id' => array( 103 | 'help' => __('UUID of queue to view'), 104 | 'required' => true, 105 | ) 106 | ) 107 | ) 108 | ) 109 | ) 110 | ->addSubcommand('next', array( 111 | 'help' => __('Show what is queued.'), 112 | 'parser' => array( 113 | 'description' => array( 114 | __('Use this command to see what X next in queue.') 115 | ), 116 | 'arguments' => array( 117 | 'limit' => array( 118 | 'help' => __('INT of how many you want to see in the future, \`10\`,\'5\''), 119 | 'required' => true, 120 | 'default' => 10 121 | ) 122 | ) 123 | ) 124 | ) 125 | ) 126 | ->addSubcommand('process', array( 127 | 'help' => __('Process the queue, runs the next limit items on the queue.') 128 | ) 129 | ) 130 | ->addSubcommand('in_progress', array( 131 | 'help' => __('Show the queues in progress.') 132 | ) 133 | ) 134 | ->addSubcommand('in_progress_count', array( 135 | 'help' => __('Show the in progress count.') 136 | ) 137 | ) 138 | ->addSubcommand('remove', array( 139 | 'help' => __('Remove a task from the queue.'), 140 | 'parser' => array( 141 | 'description' => array( 142 | __('Use this command to remove a paticular task.') 143 | ), 144 | 'arguments' => array( 145 | 'id' => array( 146 | 'help' => __('UUID of task to remove. Will not remove in_process tasks.'), 147 | 'required' => true, 148 | ) 149 | ), 150 | 'options' => array( 151 | 'force' => array( 152 | 'help' => __('if true will force a delete even on in_progress tasks.'), 153 | 'boolean' => true, 154 | 'short' => 'f', 155 | 'default' => false 156 | ) 157 | ) 158 | ) 159 | ) 160 | ); 161 | } 162 | 163 | /** 164 | * Override main 165 | * 166 | * @return void 167 | */ 168 | public function main() { 169 | $this->out($this->getOptionParser()->help()); 170 | } 171 | 172 | public function add() { 173 | $command = array_shift($this->args); 174 | $defaults = array( 175 | 'start' => null, 176 | 'end' => null, 177 | 'reschedule' => null, 178 | 'cpu' => null, 179 | 'cpu_limit' => null, 180 | 'priority' => 100 181 | ); 182 | $options = array_merge($defaults, (array) $this->params); 183 | $options['cpu_limit'] = $options['cpu']; 184 | $options = array_intersect_key($options, $defaults); 185 | 186 | if (Queue::add($command, $this->params['type'], $options)) { 187 | $this->out('Task succesfully added.', 1, Shell::QUIET); 188 | $this->out(Queue::view($this->QueueTask->id)); 189 | } else { 190 | $this->out('Error adding task.'); 191 | $this->out(); 192 | print_r($this->QueueTask->validationErrors); 193 | } 194 | } 195 | 196 | public function remove() { 197 | $id = array_shift($this->args); 198 | $this->out('Removing ' . $id); 199 | if (Queue::remove($id, $this->params['force'])) { 200 | $this->out('Queue Removed.'); 201 | } else { 202 | $this->out('Failed to remove Queue.'); 203 | $this->out(Queue::view($id)); 204 | } 205 | } 206 | 207 | public function view() { 208 | $id = array_shift($this->args); 209 | $this->out(Queue::view($id)); 210 | } 211 | 212 | public function run() { 213 | $id = array_shift($this->args); 214 | $this->out('Running ' . $id); 215 | if (Queue::run($id)) { 216 | $this->out('Success.'); 217 | $this->out(Queue::view($id)); 218 | $this->out(); 219 | } else { 220 | $this->out('Failed to run task. Check logs.'); 221 | } 222 | } 223 | 224 | public function process() { 225 | $this->out('Processing Queue.'); 226 | if (Queue::process()) { 227 | $this->out('Success.'); 228 | } else { 229 | $this->out('One or more failed, Check logs.'); 230 | } 231 | } 232 | 233 | public function next() { 234 | $limit = array_shift($this->args); 235 | $this->out('Retrieving Queue List.'); 236 | $queue = Queue::next($limit, false); 237 | $i = 1; 238 | foreach ($queue as $task) { 239 | $this->out($i . ') ' . Queue::view($task['QueueTask']['id'])); 240 | $i++; 241 | } 242 | } 243 | 244 | public function in_progress() { 245 | $this->out('Retrieving In Progress Queues.'); 246 | $queue = Queue::inProgress(); 247 | if (empty($queues)) { 248 | $this->out('No Tasks currently running.'); 249 | exit(1); 250 | } 251 | $i = 1; 252 | foreach ($queue as $task) { 253 | $this->out($i . ') ' . Queue::view($task['QueueTask']['id'])); 254 | $i++; 255 | } 256 | } 257 | 258 | public function in_progress_count() { 259 | $this->out(Queue::inProgressCount(), 1, Shell::QUIET); 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /Console/Command/Task/empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webtechnick/CakePHP-Queue-Plugin/996623bc0265cee13d3ee17e3022457eb3d4f465/Console/Command/Task/empty -------------------------------------------------------------------------------- /Controller/Component/empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webtechnick/CakePHP-Queue-Plugin/996623bc0265cee13d3ee17e3022457eb3d4f465/Controller/Component/empty -------------------------------------------------------------------------------- /Controller/QueueAppController.php: -------------------------------------------------------------------------------- 1 | set('statuses', $this->QueueTask->_statuses); 24 | $this->set('types', $this->QueueTask->_types); 25 | } 26 | 27 | /** 28 | * admin_index method 29 | * 30 | * @return void 31 | */ 32 | public function admin_index($filter = null) { 33 | if(!empty($this->request->data)){ 34 | $filter = $this->request->data['QueueTask']['filter']; 35 | } 36 | $conditions = $this->QueueTask->generateFilterConditions($filter); 37 | $this->set('queueTasks',$this->paginate('QueueTask',$conditions)); 38 | $this->set('filter', $filter); 39 | } 40 | 41 | public function admin_logs($filter = null) { 42 | if (!empty($this->request->data)) { 43 | $filter = $this->request->data['QueueTaskLog']['filter']; 44 | } 45 | $conditions = $this->QueueTaskLog->generateFilterConditions($filter); 46 | $this->set('queueTaskLogs',$this->paginate('QueueTaskLog',$conditions)); 47 | $this->set('filter', $filter); 48 | } 49 | 50 | /** 51 | * admin_view method 52 | * 53 | * @throws NotFoundException 54 | * @param string $id 55 | * @return void 56 | */ 57 | public function admin_view($id = null) { 58 | if (!$this->QueueTask->exists($id) && !$this->QueueTaskLog->exists($id)) { 59 | throw new NotFoundException(__('Invalid queue task')); 60 | } 61 | $this->set('queueTask', $this->QueueTask->findForView($id)); 62 | } 63 | 64 | public function admin_process() { 65 | //Process the queue 66 | } 67 | 68 | public function admin_run($id = null) { 69 | if (!$this->QueueTask->exists($id)) { 70 | throw new NotFoundException(__('Invalid queue task')); 71 | } 72 | if ($this->QueueTask->run($id)) { 73 | $this->Session->setFlash('Queue ' . $id . ' Ran Successfully.'); 74 | } else { 75 | $this->Session->setFlash('Queue ' . $id . ' Failed to run.'); 76 | } 77 | return $this->redirect(array('admin' => true, 'action' => 'view', $id)); 78 | } 79 | 80 | /** 81 | * admin_edit method 82 | * 83 | * @throws NotFoundException 84 | * @param string $id 85 | * @return void 86 | */ 87 | public function admin_edit($id = null) { 88 | if (!empty($this->request->data)) { 89 | if ($this->QueueTask->adminSave($this->request->data)) { 90 | $this->Session->setFlash(__('The queue task has been saved')); 91 | $this->redirect(array('action' => 'index')); 92 | } else { 93 | $this->Session->setFlash(__('The queue task could not be saved. Please, try again.')); 94 | } 95 | } 96 | 97 | if ($id && empty($this->request->data)){ 98 | $this->request->data['QueueTask'] = $this->QueueTask->findById($id); 99 | $this->set('id', $id); 100 | } 101 | 102 | } 103 | 104 | /** 105 | * admin_delete method 106 | * 107 | * @throws NotFoundException 108 | * @throws MethodNotAllowedException 109 | * @param string $id 110 | * @return void 111 | */ 112 | public function admin_delete($id = null) { 113 | $this->QueueTask->id = $id; 114 | if (!$this->QueueTask->exists()) { 115 | throw new NotFoundException(__('Invalid queue task')); 116 | } 117 | $this->request->onlyAllow('post', 'delete'); 118 | if ($this->QueueTask->delete($id)) { 119 | $this->Session->setFlash(__('Queue task deleted')); 120 | } else { 121 | $this->Session->setFlash(__('Queue task was not deleted')); 122 | } 123 | 124 | $this->redirect(array('action' => 'index')); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /Lib/Queue.php: -------------------------------------------------------------------------------- 1 | add($command, $type, $options); 38 | } 39 | 40 | /** 41 | * Deletes a task from the queue. 42 | * @param string uuid 43 | * @param boolean force - if true will bypass in progress check and delete task. (default false) 44 | * @return boolean success 45 | */ 46 | public static function remove($id = null, $force = false) { 47 | self::loadQueuetask(); 48 | $retval = self::$QueueTask->remove($id, $force); 49 | QueueUtil::clearCache(); 50 | return $retval; 51 | } 52 | 53 | /** 54 | * Run a task specifically. 55 | * @param string uuid 56 | * @return boolean success 57 | */ 58 | public static function run($id = null) { 59 | self::loadQueueTask(); 60 | return self::$QueueTask->run($id); 61 | } 62 | 63 | /** 64 | * Return the queue from QueueTask or QueueTaskLog as an associative array 65 | * @param string uuid 66 | * @return mixed array of queue or false if not found. 67 | */ 68 | public static function findById($id = null) { 69 | self::loadQueueTask(); 70 | if (self::$QueueTask->hasAny(array('QueueTask.id' => $id))) { 71 | return self::$QueueTask->findById($id); 72 | } 73 | self::loadQueueTaskLog(); 74 | if (self::$QueueTaskLog->hasAny(array('QueueTaskLog.id' => $id))) { 75 | return self::$QueueTaskLog->findById($id); 76 | } 77 | return false; 78 | } 79 | /** 80 | * View the task as a string representation looks in QueueTask and QueueTaskLog 81 | * @param string uuid 82 | * @return string representation of task. 83 | */ 84 | public static function view($id = null) { 85 | self::loadQueueTask(); 86 | if (self::$QueueTask->hasAny(array('QueueTask.id' => $id))) { 87 | return self::$QueueTask->niceString($id); 88 | } 89 | self::loadQueueTaskLog(); 90 | if (self::$QueueTaskLog->hasAny(array('QueueTaskLog.id' => $id))) { 91 | return self::$QueueTaskLog->niceString($id); 92 | } 93 | return false; 94 | } 95 | /** 96 | * List next X upcomming tasks. 97 | * @param int limit 98 | */ 99 | public static function next($limit = 10) { 100 | self::loadQueueTask(); 101 | return self::$QueueTask->next($limit, false, false); 102 | } 103 | 104 | /** 105 | * Process the Queue, runs the queue 106 | * @return boolean success 107 | */ 108 | public static function process() { 109 | self::loadQueueTask(); 110 | return self::$QueueTask->process(); 111 | } 112 | 113 | /** 114 | * Returns the tasks in progress. 115 | * @return array of tasks currently in progress 116 | */ 117 | public static function inProgress() { 118 | self::loadQueueTask(); 119 | return self::$QueueTask->findInProgress(); 120 | } 121 | 122 | /** 123 | * Return the in progress count 124 | * @return int in progress count. 125 | */ 126 | public static function inProgressCount() { 127 | self::loadQueueTask(); 128 | return self::$QueueTask->inProgressCount(); 129 | } 130 | 131 | /** 132 | * Load the QueueTask Model instance 133 | */ 134 | public static function loadQueueTask() { 135 | if (!self::$QueueTask) { 136 | App::uses('QueueTask','Queue.Model'); 137 | self::$QueueTask = ClassRegistry::init('Queue.QueueTask'); 138 | } 139 | } 140 | /** 141 | * Load the QueueTask Model instance 142 | */ 143 | public static function loadQueueTaskLog() { 144 | if (!self::$QueueTaskLog) { 145 | App::uses('QueueTaskLog','Queue.Model'); 146 | self::$QueueTaskLog = ClassRegistry::init('Queue.QueueTaskLog'); 147 | } 148 | } 149 | } -------------------------------------------------------------------------------- /Lib/QueueUtil.php: -------------------------------------------------------------------------------- 1 | 'File', 76 | 'duration' => $duration, 77 | 'path' => CACHE, 78 | 'prefix' => 'queue_' 79 | )); 80 | } 81 | } 82 | /** 83 | * Get the cache key config if we have cache setup 84 | * @param string key 85 | * @return mixed boolean false or 86 | */ 87 | public static function readCache($key) { 88 | if (self::getConfig('cache')) { 89 | return Cache::read($key, 'queue'); 90 | } 91 | return false; 92 | } 93 | /** 94 | * Write the cache if we have a cache setup 95 | * @param string key 96 | * @param mixed value 97 | * @return boolean success 98 | */ 99 | public static function writeCache($key, $value) { 100 | if (self::getConfig('cache')) { 101 | return Cache::write($key, $value, 'queue'); 102 | } 103 | return false; 104 | } 105 | 106 | /** 107 | * Clears all queue cache. 108 | * @return boolean success 109 | */ 110 | public static function clearCache() { 111 | if (self::getConfig('cache')) { 112 | return Cache::clear(false, 'queue'); 113 | } 114 | return true; 115 | } 116 | 117 | /** 118 | * Write log if we have logging on. 119 | * @param string message to write 120 | */ 121 | public static function writeLog($message) { 122 | if (self::getConfig('log')) { 123 | CakeLog::write('queue', $message); 124 | } 125 | } 126 | /** 127 | * Get the current Cpu Usage as a percentages 128 | * Grabs from cache if we have it. 129 | * @throws Exception 130 | * @return float current cpu percentage. 131 | */ 132 | public static function currentCpu() { 133 | if ($cpu = self::readCache('cpu')) { 134 | return $cpu; 135 | } 136 | $uptime = shell_exec('uptime'); 137 | if (empty($uptime) || strpos($uptime, 'load') === false) { 138 | throw new Exception('Unable to retrieve load avearge from uptime.'); 139 | } 140 | $uptime = explode(':', $uptime); 141 | $averages = trim(array_pop($uptime)); 142 | list($min1, $min5, $min15) = explode(' ', $averages, 3); 143 | $cores = self::getConfig('cores'); 144 | if (!$cores) { 145 | $cores = 1; 146 | } 147 | $percent = ($min5 / $cores) * 100; 148 | $percent = round($percent); 149 | self::writeCache('cpu', $percent); 150 | 151 | return $percent; 152 | } 153 | } -------------------------------------------------------------------------------- /Lib/empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webtechnick/CakePHP-Queue-Plugin/996623bc0265cee13d3ee17e3022457eb3d4f465/Lib/empty -------------------------------------------------------------------------------- /Model/Behavior/empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webtechnick/CakePHP-Queue-Plugin/996623bc0265cee13d3ee17e3022457eb3d4f465/Model/Behavior/empty -------------------------------------------------------------------------------- /Model/Datasource/empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webtechnick/CakePHP-Queue-Plugin/996623bc0265cee13d3ee17e3022457eb3d4f465/Model/Datasource/empty -------------------------------------------------------------------------------- /Model/QueueAppModel.php: -------------------------------------------------------------------------------- 1 | 'queued', 32 | 2 => 'in progress', 33 | 3 => 'finished', 34 | 4 => 'paused', 35 | ); 36 | /** 37 | * type key to human readable 38 | * @var array 39 | * @access protected 40 | */ 41 | protected $_types = array( 42 | 1 => 'model', 43 | 2 => 'shell', 44 | 3 => 'url', 45 | 4 => 'php_cmd', 46 | 5 => 'shell_cmd', 47 | ); 48 | /** 49 | * afterFind will add status_human and type_human to the result 50 | * human readable and understandable type and status. 51 | * @param array of results 52 | * @param boolean primary 53 | * @return array of altered results 54 | */ 55 | public function afterFind($results = array(), $primary = false){ 56 | foreach ($results as $key => $val) { 57 | if (isset($val[$this->alias]['type'])) { 58 | $results[$key][$this->alias]['type_human'] = $this->_types[$val[$this->alias]['type']]; 59 | } 60 | if (isset($val[$this->alias]['status'])) { 61 | $results[$key][$this->alias]['status_human'] = $this->_statuses[$val[$this->alias]['status']]; 62 | } 63 | } 64 | return $results; 65 | } 66 | /** 67 | * return conditions based on searchable fields and filter 68 | * 69 | * @param string filter 70 | * @return conditions array 71 | */ 72 | public function generateFilterConditions($filter = NULL, $pre = '') { 73 | $retval = array(); 74 | if ($filter) { 75 | foreach ($this->searchFields as $field) { 76 | $retval['OR']["$field LIKE"] = '%' . $filter . '%'; 77 | } 78 | } 79 | return $retval; 80 | } 81 | /** 82 | * This is what I want create to do, but without setting defaults. 83 | */ 84 | public function clear() { 85 | $this->id = false; 86 | $this->data = array(); 87 | $this->validationErrors = array(); 88 | return $this->data; 89 | } 90 | /** 91 | * String to datetime stamp 92 | * @param string that is parsable by str2time 93 | * @param boolean future, force future time incriment by week. 94 | * @return date time string for MYSQL 95 | */ 96 | function str2datetime($str = 'now', $future = false) { 97 | if (is_array($str) && isset($str['month']) && isset($str['day']) && isset($str['year'])) { 98 | $str = "{$str['month']}/{$str['day']}/{$str['year']}"; 99 | } 100 | $format = "Y-m-d H:i:s"; 101 | $retval = date($format, strtotime($str)); 102 | if ($future) { 103 | $retvaltime = strtotime($retval); 104 | $time = time(); 105 | $weektime = 604800; //seconds in a week 106 | while ($retvaltime < $time) { 107 | $retvaltime += $weektime; 108 | } 109 | $retval = date($format, $retvaltime); 110 | } 111 | return $retval; 112 | } 113 | 114 | /** 115 | * Returns if the variable is an int or string that matches an int 116 | * @param mixed var 117 | * @return boolean if is digit. 118 | */ 119 | public function isDigit($var = null) { 120 | return (is_int($var) || (is_string($var) && preg_match('/\d+$/', $var))); 121 | } 122 | 123 | /** 124 | * Get the current record, for QueueTask or QueueTaskLog 125 | * @param string uuid 126 | * @return mixed associative array of queue or false on failure 127 | */ 128 | public function findById($id = null) { 129 | if ($id) { 130 | $this->id = $id; 131 | } 132 | if (!$this->exists()) { 133 | return $this->__errorAndExit("QueueTask {$this->id} not found."); 134 | } 135 | $retval = $this->read(); 136 | return $retval[$this->alias]; 137 | } 138 | /** 139 | * String representation of task 140 | * @param uuid string 141 | * @return string of task. 142 | */ 143 | public function niceString($id = null) { 144 | if ($id) { 145 | $this->id = $id; 146 | } 147 | if (!$this->exists()) { 148 | return $this->__errorAndExit("QueueTask {$this->id} not found."); 149 | } 150 | $data = $this->read(); 151 | $retval = $data[$this->alias]['id'] . ' ' . $data[$this->alias]['status_human'] . ' ' . $data[$this->alias]['type_human']; 152 | $retval .= "\n\tCommand: " . $data[$this->alias]['command']; 153 | $retval .= "\n\tPriority: " . $data[$this->alias]['priority']; 154 | if ($data[$this->alias]['is_restricted']) { 155 | $retval .= "\n\tRestricted By:"; 156 | if ($data[$this->alias]['scheduled'] !== null) { 157 | $retval .= "\n\t\tStart: {$data[$this->alias]['scheduled']}"; 158 | if ($data[$this->alias]['scheduled_end'] !== null) { 159 | $retval .= "\n\t\tEnd: {$data[$this->alias]['scheduled_end']}"; 160 | } 161 | if ($data[$this->alias]['reschedule'] !== null) { 162 | $retval .= "\n\t\tReschedule: {$data[$this->alias]['reschedule']}"; 163 | } 164 | } 165 | if ($data[$this->alias]['cpu_limit'] !== null) { 166 | $retval .= "\n\t\tCPU <= {$data[$this->alias]['cpu_limit']}%"; 167 | } 168 | } 169 | if ($data[$this->alias]['status'] == 3 && !empty($data[$this->alias]['executed'])) { //Finished 170 | $retval .= "\n\tExecuted on " . date('l jS \of F Y h:i:s A', strtotime($data[$this->alias]['executed'])) . '. And took ' . $data[$this->alias]['execution_time'] . ' ms.'; 171 | $retval .= "\n\tResult: " . $data[$this->alias]['result']; 172 | } 173 | return $retval; 174 | } 175 | /** 176 | * Set and error and return false 177 | * @param string message 178 | * @return false 179 | * @access private 180 | */ 181 | public function __errorAndExit($message) { 182 | $this->errors[$this->id][] = $message; 183 | QueueUtil::writeLog('Error: ' . $message); 184 | return false; 185 | } 186 | 187 | /** 188 | * Wrapper for getUserId, so we can mock this for testing 189 | * @return mixed result of AuthComponent::user('id'); 190 | */ 191 | public function _getUserId() { 192 | App::uses('AuthComponent', 'Controller/Component'); 193 | return AuthComponent::user('id'); 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /Model/QueueTask.php: -------------------------------------------------------------------------------- 1 | array( 37 | 'validStatus' => array( 38 | 'rule' => array('validStatus'), 39 | 'message' => 'Please select a valid status', 40 | ), 41 | ), 42 | 'type' => array( 43 | 'validType' => array( 44 | 'rule' => array('validType'), 45 | 'message' => 'Please select a valid type', 46 | ), 47 | 'allowedType' => array( 48 | 'rule' => array('allowedType'), 49 | 'message' => 'Specified Type is not allowed by your configuration file. check Config/queue.php' 50 | ) 51 | ), 52 | 'scheduled' => array( 53 | 'datetime' => array( 54 | 'rule' => array('datetime'), 55 | 'message' => 'Must be a valid date time stamp.', 56 | 'allowEmpty' => true 57 | ) 58 | ), 59 | 'scheduled_end' => array( 60 | 'validWindow' => array( 61 | 'rule' => array('datetime'), 62 | 'message' => 'Must be a valid datetime stamp, or null.', 63 | 'allowEmpty' => true 64 | ) 65 | ), 66 | 'reschedule' => array( 67 | 'validReschedule' => array( 68 | 'rule' => array('validReschedule'), 69 | 'message' => 'Cannot be empty when schedule_end is not null. Must be a strtotime parsable string.', 70 | ) 71 | ), 72 | 'cpu_limit' => array( 73 | 'validCpu' => array( 74 | 'rule' => array('range', -1, 101), 75 | 'message' => 'Cpu Percent Limit must be between 0 and 100.', 76 | 'allowEmpty' => true 77 | ) 78 | ), 79 | 'is_restricted' => array( 80 | 'boolean' => array( 81 | 'rule' => array('boolean'), 82 | 'message' => 'is_required must be a 0 or 1' 83 | ) 84 | ), 85 | 'command' => array( 86 | 'notBlank' => array( 87 | 'rule' => array('notBlank'), 88 | 'message' => 'No command. Please specify.', 89 | ), 90 | 'validCommand' => array( 91 | 'rule' => array('validCommand'), 92 | 'message' => 'Command not valid for type.' 93 | ) 94 | ), 95 | ); 96 | 97 | public $virtualFields = array( 98 | 'execution_time' => 'QueueTask.end_time - QueueTask.start_time' 99 | ); 100 | 101 | /** 102 | * Filter fields 103 | * @var array 104 | */ 105 | public $searchFields = array( 106 | 'QueueTask.command','QueueTask.id','QueueTask.status','QueueTask.type' 107 | ); 108 | /** 109 | * Placeholder for shell 110 | */ 111 | public $Shell = null; 112 | 113 | /** 114 | * Construct to load config setting if we have cache 115 | */ 116 | public function __construct($id = false, $table = null, $ds = null) { 117 | if (QueueUtil::getConfig('cache')) { 118 | QueueUtil::configCache(); 119 | } 120 | return parent::__construct($id, $table, $ds); 121 | } 122 | /** 123 | * Assign the user_id if we have one. 124 | * @param array options 125 | * @return boolean success 126 | */ 127 | public function beforeSave($options = array()) { 128 | $user_id_method = QueueUtil::getConfig('userIdMethod'); 129 | if (!empty($user_id_method)) { 130 | if ($user_id = $this->$user_id_method()) { 131 | $this->data[$this->alias]['user_id'] = $user_id; 132 | } 133 | } 134 | return parent::beforeSave($options); 135 | } 136 | /** 137 | * Validataion of Type 138 | * @param array field 139 | * @return boolean if valid 140 | */ 141 | public function validType($field) { 142 | return isset($this->_types[$field['type']]); 143 | } 144 | 145 | /** 146 | * Validataion of Status 147 | * @param array field 148 | * @return boolean if valid 149 | */ 150 | public function validStatus($field) { 151 | return isset($this->_statuses[$field['status']]); 152 | } 153 | 154 | /** 155 | * Cannot be null unless scheduled_end is also null 156 | * @param arry field 157 | * @return boolean if valid 158 | */ 159 | public function validReschedule($field) { 160 | if (isset($this->data[$this->alias]['scheduled_end']) && !empty($this->data[$this->alias]['scheduled_end']) && empty($field['reschedule'])) { 161 | return false; 162 | } 163 | return true; 164 | } 165 | /** 166 | * Validataion of Command 167 | * @param array field 168 | * @return boolean if valid 169 | */ 170 | public function validCommand($field) { 171 | if (!isset($this->data[$this->alias]['type'])) { 172 | $this->invalidate('type', 'type must be present to validate command'); 173 | return false; 174 | } 175 | switch ($this->data[$this->alias]['type']) { 176 | case 1: //Model must have :: and ) as last character. 177 | if (strpos($field['command'], '::') === false || substr($field['command'], -1) != ')') { 178 | $this->invalidate('command', 'Please use Model Syntax: \'SomeModel::action()\' \'Plugin.SomeModel::action("param","param")\''); 179 | return false; 180 | } 181 | break; 182 | case 2: //Shell must not have whole word 'cake' in front. 183 | $nostrings = array('cake','./cake','Console/cake'); 184 | foreach ($nostrings as $string) { 185 | if (strpos($field['command'], $string) === 0) { 186 | $this->invalidate('command', 'Specify shell commands as though using dispatchShell string: \'Plugin.SomeShell command param1 param2\''); 187 | return false; 188 | } 189 | } 190 | break; 191 | case 3: //url must have a / in it 192 | if (strpos($field['command'], '/') === false) { 193 | $this->invalidate('command', 'Url must contain a /: \'/path/to/action\' \'http://example.com/path/to/action\''); 194 | return false; 195 | } 196 | break; 197 | case 4: //php_command basically can't be empty. 198 | if (empty($field['command'])) { 199 | $this->invalidate('command', 'PhpCmd must not be empty: \'5 + 7\''); 200 | return false; 201 | } 202 | break; 203 | case 5: //shell command basically can't be empty. 204 | if (empty($field['command'])) { 205 | $this->invalidate('command', 'ShellCmd must not be empty: \'echo "hello" && echo "world"\''); 206 | return false; 207 | } 208 | break; 209 | default: //we shouldn't get here, something went really wrong if we did but definately don't want to return true if we do. 210 | $this->invalidate('command', 'Unknown Type, cannot validate command'); 211 | return false; 212 | } 213 | return true; 214 | } 215 | 216 | /** 217 | * Validataion of Type Allowed, based on configuration app/Config/queue.php 218 | * @param array field 219 | * @return boolean if valid 220 | */ 221 | public function allowedType($field) { 222 | $allowedTypes = QueueUtil::getConfig('allowedTypes'); 223 | return in_array($field['type'], $allowedTypes); 224 | } 225 | /** 226 | * This converts the admin save to 227 | */ 228 | public function adminSave($data = array()) { 229 | $options = $data['QueueTask']; 230 | $command = $data['QueueTask']['command']; 231 | $type = $data['QueueTask']['type']; 232 | return $this->add($command, $type, $options); 233 | } 234 | /** 235 | * Convience function utilized by Queue::add() library 236 | * @param string command 237 | * @param string type 238 | * @param array of options 239 | * - start = strtotime datetime to execute. Will assume future date. (11 pm Sunday) (default null) 240 | * - end = strtotime datetime of window allowed to execute (5 am Monday) (default null) 241 | * - reschedule = strtotime addition to scheduled to execute. (+1 day | +1 week) (default null) 242 | * - cpu_limit = int 0-100 percent threshold for when to execute (95 will execute will less than 95% cpu load (default null). 243 | * if left null, as soon as possible will be assumed. 244 | * - priority = the priority of the task, a way to Cut in line. (default 100) 245 | * - id = if provided, will update the record instead of creating a new one. 246 | * @return boolean success 247 | */ 248 | public function add($command, $type, $options = array()) { 249 | if (!$command || !$type) { 250 | return $this->__errorAndExit("Command and Type required to add Task to Queue."); 251 | } 252 | $options = array_merge(array( 253 | 'id' => null, 254 | 'start' => null, 255 | 'end' => null, 256 | 'reschedule' => null, 257 | 'cpu_limit' => null, 258 | 'cpu' => null, 259 | 'priority' => 100, 260 | 'scheduled' => null, 261 | 'scheduled_end' => null, 262 | ), (array) $options); 263 | $options['cpu_limit'] = $options['cpu']; 264 | 265 | if (!$this->isDigit($type)) { 266 | $type = $this->__findType($type); 267 | } 268 | 269 | if ($options['start'] !== null) { 270 | $options['scheduled'] = $this->str2datetime($options['start']); 271 | } 272 | 273 | if ($options['end'] !== null) { 274 | $options['scheduled_end'] = $this->str2datetime($options['end'], true); 275 | } 276 | 277 | $data = array( 278 | 'id' => $options['id'], 279 | 'priority' => $options['priority'], 280 | 'command' => $command, 281 | 'type' => $type, 282 | 'scheduled' => $options['scheduled'], 283 | 'scheduled_end' => $options['scheduled_end'], 284 | 'reschedule' => $options['reschedule'], 285 | 'cpu_limit' => $options['cpu_limit'] 286 | ); 287 | if (!empty($options['scheduled']) || !empty($options['cpu_limit'])) { 288 | $data['is_restricted'] = true; 289 | } 290 | $this->clear(); 291 | return $this->save($data); 292 | } 293 | 294 | /** 295 | * Remove is a wrapper for delete that will check in progress status before 296 | * removing. 297 | * @param string uuid 298 | * @param boolean force - if true will bypass in progress check and delete task. (default false) 299 | * @throws Exception. 300 | * @return boolean 301 | */ 302 | public function remove($id = null, $force = false) { 303 | if ($id) { 304 | $this->id = $id; 305 | } 306 | if (!$this->exists()) { 307 | return $this->__errorAndExit("QueueTask {$this->id} not found."); 308 | } 309 | if (!$force && $this->field('status') == 2) { //In progress 310 | return $this->__errorAndExit("QueueTask {$this->id} is currently in progress."); 311 | } 312 | return $this->delete($id); 313 | } 314 | /** 315 | * Return count of in progress queues 316 | * @return int number of running queues. 317 | */ 318 | public function inProgressCount() { 319 | return $this->find('count', array( 320 | 'conditions' => array( 321 | "{$this->alias}.status" => 2 //in_progress 322 | ) 323 | )); 324 | } 325 | /** 326 | * Find for view. Will search through this 327 | * table and queueTaskLog as well 328 | */ 329 | public function findForView($id = null) { 330 | $retval = $this->find('first', array( 331 | 'conditions' => array( 332 | 'QueueTask.id' => $id 333 | ) 334 | )); 335 | if (empty($retval)) { 336 | $log = ClassRegistry::init('Queue.QueueTaskLog')->find('first', array( 337 | 'conditions' => array( 338 | 'QueueTaskLog.id' => $id 339 | ) 340 | )); 341 | if (!empty($log)) { 342 | $retval = array( 343 | 'QueueTask' => $log['QueueTaskLog'] 344 | ); 345 | } 346 | } 347 | return $retval; 348 | } 349 | /** 350 | * Generate the list of next 10 in queue. 351 | * @param int limit of how many to return for next in queue 352 | * @param boolean minimal fields returned 353 | * @param processing, if true only return true set of what needs to be executed next NOW 354 | * @return array of tasks in order of execution next. 355 | */ 356 | public function next($limit = 10, $minimal = true, $processing = true) { 357 | //If we don't have any queued in table just exit with empty set. 358 | if (!$this->hasAny(array("{$this->alias}.status" => 1))) { 359 | return array(); 360 | } 361 | $cpu = QueueUtil::currentCpu(); 362 | $now = $this->str2datetime(); 363 | $fields = $minimal ? array("{$this->alias}.id") : array("{$this->alias}.*"); 364 | //Set of conditions in order 365 | $conditions = array( 366 | array( //Look for restricted by scheduled and with a window with cpu 367 | "{$this->alias}.is_restricted" => true, 368 | "{$this->alias}.status" => 1, 369 | "{$this->alias}.scheduled <=" => $now, 370 | 'OR' => array( 371 | array("{$this->alias}.scheduled_end >=" => $now), 372 | array("{$this->alias}.scheduled_end" => null), 373 | ), 374 | "{$this->alias}.cpu_limit >=" => $cpu, 375 | ), 376 | array( //Look for restricted by scheduled and with a window 377 | "{$this->alias}.is_restricted" => true, 378 | "{$this->alias}.status" => 1, 379 | "{$this->alias}.scheduled <=" => $now, 380 | 'OR' => array( 381 | array("{$this->alias}.scheduled_end >=" => $now), 382 | array("{$this->alias}.scheduled_end" => null), 383 | ), 384 | ), 385 | array( //Look for restricted by cpu 386 | "{$this->alias}.is_restricted" => true, 387 | "{$this->alias}.status" => 1, 388 | "{$this->alias}.cpu_limit >=" => $cpu, 389 | ), 390 | array( //Unrestricted 391 | "{$this->alias}.is_restricted" => false, 392 | "{$this->alias}.status" => 1, 393 | ) 394 | ); 395 | 396 | if (!$processing) { 397 | $conditions[] = array( //Future scheduled 398 | "{$this->alias}.is_restricted" => true, 399 | "{$this->alias}.status" => 1, 400 | "{$this->alias}.scheduled >=" => $now, 401 | ); 402 | } 403 | 404 | $retval = array(); 405 | foreach ($conditions as $condition) { 406 | $current_count = count($retval); 407 | if ($current_count >= $limit) { 408 | break; 409 | } 410 | $new_limit = $limit - $current_count; 411 | $result = $this->find('all', array( 412 | 'limit' => $new_limit, 413 | 'order' => array("{$this->alias}.scheduled ASC, {$this->alias}.priority ASC"), 414 | 'fields' => $fields, 415 | 'conditions' => $condition 416 | )); 417 | if (!empty($result)) { 418 | $retval = array_merge($retval, $result); 419 | } 420 | } 421 | return $retval; 422 | } 423 | 424 | /** 425 | * Returns a list to run. Processing list 426 | * @return array set of queues to run. 427 | */ 428 | public function runList($minimal = true) { 429 | $limit = QueueUtil::getConfig('limit'); 430 | $in_progress = $this->inProgressCount(); 431 | //If we have them in progress shortcut it. 432 | if ($in_progress >= $limit) { 433 | return array(); 434 | } 435 | return $this->next($limit - $in_progress, $minimal, true); 436 | } 437 | 438 | /** 439 | * Actually run the queue 440 | * @param string uuid 441 | * @return boolean success 442 | */ 443 | public function run($id = null) { 444 | if ($id) { 445 | $this->id = $id; 446 | } 447 | if (!$this->exists()) { 448 | return $this->__errorAndExit("QueueTask {$this->id} not found."); 449 | } 450 | $this->__setInProgress($id); 451 | $data = $this->read(); 452 | QueueUtil::writeLog('Running Queue ID: ' . $id); 453 | switch ($data[$this->alias]['type']) { 454 | case 1: 455 | $retval = $this->__runModelQueue($data); 456 | break; 457 | case 2: 458 | $retval = $this->__runShellQueue($data); 459 | break; 460 | case 3: 461 | $retval = $this->__runUrlQueue($data); 462 | break; 463 | case 4: 464 | $retval = $this->__runPhpCmdQueue($data); 465 | break; 466 | case 5: 467 | $retval = $this->__runShellCmdQueue($data); 468 | break; 469 | default: 470 | $this->__setToPaused($id); 471 | throw new Exception("Unknown Type"); 472 | } 473 | $this->__setFinished($id, $retval['result']); 474 | return $retval['success']; 475 | } 476 | 477 | /** 478 | * Process the queue, this is the entry point of the shell and cron 479 | * @return boolean success 480 | */ 481 | public function process() { 482 | $queues = $this->runList(); 483 | if (empty($queues)) { 484 | return true; 485 | } 486 | $retval = true; 487 | foreach ($queues as $queue) { 488 | if (!$this->run($queue[$this->alias]['id'])) { 489 | $retval = false; 490 | } 491 | } 492 | return $retval; 493 | } 494 | 495 | /** 496 | * Archive this current QueueTask into QueueTaskLogs table 497 | * @param string uuid id 498 | * @return boolean success 499 | */ 500 | public function archive($id = null) { 501 | if ($id) { 502 | $this->id = $id; 503 | } 504 | if (!$this->exists()) { 505 | return $this->__errorAndExit("QueueTask {$this->id} not found."); 506 | } 507 | $data = $this->read(); 508 | if ($data[$this->alias]['status'] != 3) { //Finished 509 | return false; 510 | } 511 | if (!ClassRegistry::init('Queue.QueueTaskLog')->save($data['QueueTask'])) { 512 | return false; 513 | } 514 | return $this->delete($this->id); 515 | } 516 | /** 517 | * Generate filter conditions for filter search 518 | * @param string filter 519 | * @param string pre character for search (default '') optional '%' 520 | */ 521 | public function generateFilterConditions($filter = null, $pre = '') { 522 | $conditions = parent::generateFilterConditions($filter, $pre); 523 | foreach ($this->_statuses as $key => $name) { 524 | if (strtolower($filter) == $name) { 525 | $conditions['OR']["{$this->alias}.status"] = $key; 526 | unset($conditions['OR']["{$this->alias}.status LIKE"]); 527 | } 528 | } 529 | foreach ($this->_types as $key => $name) { 530 | if (strtolower($filter) == $name) { 531 | $conditions['OR']["{$this->alias}.type"] = $key; 532 | unset($conditions['OR']["{$this->alias}.type LIKE"]); 533 | } 534 | } 535 | } 536 | 537 | /** 538 | * Find tasks that are currently in progress 539 | * @return array of tasks in progress 540 | */ 541 | public function findInProgress() { 542 | return $this->find('all', array( 543 | 'conditions' => array( 544 | "{$this->alias}.status" => 2 //in progress 545 | ) 546 | )); 547 | } 548 | 549 | /** 550 | * Set and error and return false 551 | * @param string message 552 | * @return false 553 | * @access private 554 | */ 555 | private function __clearErrors() { 556 | $this->errors = array(); 557 | } 558 | 559 | /** 560 | * run the actual model command 561 | * @param queue data 562 | * @return array of result and success 563 | * @access private 564 | */ 565 | private function __runModelQueue($data) { 566 | $retval = array( 567 | 'success' => false, 568 | 'result' => null 569 | ); 570 | if (isset($data[$this->alias]['command'])) { 571 | list($pluginmodel, $function) = explode('::',$data[$this->alias]['command'], 2); 572 | list($plugin, $model) = pluginSplit($pluginmodel); 573 | if (!empty($plugin)) { 574 | App::uses($model, "$plugin.Model"); 575 | } else { 576 | App::uses($model, "Model"); 577 | } 578 | $Model = ClassRegistry::init($pluginmodel); 579 | $command = "\$retval['result'] = \$Model->$function;"; 580 | @eval($command); 581 | if ($retval['result'] !== false) { 582 | $retval['success'] = true; 583 | } 584 | } 585 | return $retval; 586 | } 587 | 588 | /** 589 | * run the actual shell command 590 | * @param queue data 591 | * @return array of result and success 592 | * @access private 593 | */ 594 | private function __runShellQueue($data) { 595 | $retval = array( 596 | 'success' => false, 597 | 'result' => null 598 | ); 599 | if (isset($data[$this->alias]['command'])) { 600 | if (!$this->Shell) { 601 | App::uses('Shell','Console'); 602 | App::uses('ShellDispatcher','Console'); 603 | $this->Shell = new Shell(); 604 | } 605 | $retval['result'] = $this->Shell->dispatchShell($data[$this->alias]['command']); 606 | if ($retval['result'] !== false) { 607 | $retval['success'] = true; 608 | } 609 | } 610 | return $retval; 611 | } 612 | /** 613 | * run the actual url command 614 | * @param queue data 615 | * @return array of result and success 616 | * @access private 617 | */ 618 | private function __runUrlQueue($data) { 619 | $retval = array( 620 | 'success' => false, 621 | 'result' => null 622 | ); 623 | if (isset($data[$this->alias]['command'])) { 624 | $retval['result'] = $this->requestAction($data[$this->alias]['command'], array('return' => true)); 625 | if ($retval['result'] !== false) { 626 | $retval['success'] = true; 627 | } 628 | } 629 | return $retval; 630 | } 631 | /** 632 | * run the actual php_cmd command 633 | * @param queue data 634 | * @return array of result and success 635 | * @access private 636 | */ 637 | private function __runPhpCmdQueue($data) { 638 | $retval = array( 639 | 'success' => false, 640 | 'result' => null 641 | ); 642 | if (isset($data[$this->alias]['command'])) { 643 | $cmd = $data[$this->alias]['command']; 644 | $command = "\$retval['result'] = $cmd;"; 645 | @eval($command); 646 | if ($retval['result'] !== false) { 647 | $retval['success'] = true; 648 | } 649 | } 650 | return $retval; 651 | } 652 | /** 653 | * run the actual shell_cmd command 654 | * @param queue data 655 | * @return array of result and success 656 | * @access private 657 | */ 658 | private function __runShellCmdQueue($data) { 659 | $retval = array( 660 | 'success' => false, 661 | 'result' => null 662 | ); 663 | if (isset($data[$this->alias]['command'])) { 664 | $retval['result'] = shell_exec($data[$this->alias]['command']); 665 | if ($retval['result'] !== false) { 666 | $retval['success'] = true; 667 | } 668 | } 669 | return $retval; 670 | } 671 | 672 | /** 673 | * Set the current queue to inprogress 674 | * @param string id (optional) 675 | * @return boolean success 676 | */ 677 | private function __setInProgress($id = null) { 678 | if ($id) { 679 | $this->id = $id; 680 | } 681 | if (!$this->exists()) { 682 | return $this->__errorAndExit("QueueTask {$this->id} not found."); 683 | } 684 | QueueUtil::writeLog('Starting Execution on Task: ' . $this->id); 685 | $this->saveField('start_time', microtime(true)); 686 | return $this->saveField('status', 2); 687 | } 688 | 689 | /** 690 | * Set the current queue to paused 691 | * @param string id (optional) 692 | * @return boolean success 693 | */ 694 | private function __setToPaused($id = null) { 695 | if ($id) { 696 | $this->id = $id; 697 | } 698 | if (!$this->exists()) { 699 | return $this->__errorAndExit("QueueTask {$this->id} not found."); 700 | } 701 | QueueUtil::writeLog('Pausing Task: ' . $this->id); 702 | $this->saveField('end_time', microtime(true)); 703 | return $this->saveField('status', 4); 704 | } 705 | 706 | /** 707 | * Set the current queue to finished 708 | * Will archive the task after execution 709 | * @param string id (optional) 710 | * @param mixed result to save back 711 | * @return boolean success 712 | */ 713 | private function __setFinished($id = null, $result = null) { 714 | if ($id) { 715 | $this->id = $id; 716 | } 717 | if (!$this->exists()) { 718 | return $this->__errorAndExit("QueueTask {$this->id} not found."); 719 | } 720 | $save_result = json_encode($result); 721 | $this->saveField('status', 3); 722 | $this->saveField('result', $save_result); 723 | $this->saveField('end_time', microtime(true)); 724 | $this->saveField('executed',$this->str2datetime()); 725 | QueueUtil::writeLog('Finished Execution on Task: ' . $this->id . "\nTook: " . $this->field('execution_time') . "\nResult:\n\n" . $save_result); 726 | if (QueueUtil::getConfig('archiveAfterExecute')) { 727 | $this->archive($this->id); 728 | } 729 | return true; 730 | } 731 | 732 | /** 733 | * Find the type int by a string 734 | * @param string type (model, shell, php_cmd, etc...) 735 | * @return mixed int of correct type or false if invalid. 736 | */ 737 | private function __findType($stringType) { 738 | $stringType = strtolower($stringType); 739 | $type = array_search($stringType, $this->_types); 740 | if ($type !== false) { 741 | return $type; 742 | } 743 | return false; 744 | } 745 | 746 | /** 747 | * Find the status int by a string 748 | * @param string status (queued, in_progress, etc..) 749 | * @return mixed int of correct status or false if invalid. 750 | */ 751 | private function __findStatus($stringStatus) { 752 | $stringStatus = strtolower($stringStatus); 753 | $status = array_search($stringStatus, $this->_statuses); 754 | if ($status !== false) { 755 | return $status; 756 | } 757 | return false; 758 | } 759 | 760 | /** 761 | * Reschedule a task based on reschedule 762 | * @param string uuid 763 | * @return boolean success 764 | */ 765 | private function __reschedule($id = null) { 766 | if ($id) { 767 | $this->id = $id; 768 | } 769 | if (!$this->exists()) { 770 | return $this->__errorAndExit("QueueTask {$this->id} not found."); 771 | } 772 | 773 | QueueUtil::writeLog('Rescheduling ' . $this->id . ' to '); 774 | } 775 | } 776 | -------------------------------------------------------------------------------- /Model/QueueTaskLog.php: -------------------------------------------------------------------------------- 1 | 'QueueTaskLog.end_time - QueueTaskLog.start_time' 18 | ); 19 | 20 | /** 21 | * Generate filter conditions for filter search 22 | * @param string filter 23 | * @param string pre character for search (default '') optional '%' 24 | */ 25 | public function generateFilterConditions($filter = null, $pre = '') { 26 | $conditions = parent::generateFilterConditions($filter, $pre); 27 | foreach ($this->_statuses as $key => $name) { 28 | if (strtolower($filter) == $name) { 29 | $conditions['OR']["{$this->alias}.status"] = $key; 30 | unset($conditions['OR']["{$this->alias}.status LIKE"]); 31 | } 32 | } 33 | foreach ($this->_types as $key => $name) { 34 | if (strtolower($filter) == $name) { 35 | $conditions['OR']["{$this->alias}.type"] = $key; 36 | unset($conditions['OR']["{$this->alias}.type LIKE"]); 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Test/Case/Controller/Component/empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webtechnick/CakePHP-Queue-Plugin/996623bc0265cee13d3ee17e3022457eb3d4f465/Test/Case/Controller/Component/empty -------------------------------------------------------------------------------- /Test/Case/Controller/QueueTasksControllerTest.php: -------------------------------------------------------------------------------- 1 | QueueTask = $this->getMockForModel('Queue.QueueTask', array('requestAction', 'getCurrentUser')); 37 | $this->QueueTask->Shell = $this->getMock('Shell'); 38 | Configure::write('Queue.allowedTypes', array(1,2,3,4,5)); 39 | } 40 | 41 | /** 42 | * tearDown method 43 | * 44 | * @return void 45 | */ 46 | public function tearDown() { 47 | unset($this->QueueTask); 48 | 49 | parent::tearDown(); 50 | } 51 | 52 | public function test_process() { 53 | QueueUtil::$configs['limit'] = 3; 54 | QueueUtil::$configs['archiveAfterExecute'] = true; 55 | $count = $this->QueueTask->find('count'); 56 | $result = $this->QueueTask->process(); 57 | $this->assertTrue($result); 58 | $this->assertEqual($this->QueueTask->find('count'), $count - 3); 59 | $QueueLog = ClassRegistry::init('Queue.QueueTaskLog'); 60 | $logs = $QueueLog->find('all'); 61 | $this->assertEqual(count($logs), 3); 62 | foreach ($logs as $log) { 63 | $this->assertEqual($log['QueueTaskLog']['status'], 3); //finixhed 64 | $this->assertTrue(!empty($log['QueueTaskLog']['executed'])); 65 | $this->assertTrue(!empty($log['QueueTaskLog']['start_time'])); 66 | $this->assertTrue(!empty($log['QueueTaskLog']['end_time'])); 67 | } 68 | } 69 | 70 | public function test_removeNotInProgress() { 71 | $this->QueueTask->id = '524b0c44-a3a0-4956-8428-dc3ee017215a'; 72 | $result = $this->QueueTask->remove(); //forcing delete 73 | $this->assertTrue($result); 74 | $this->assertFalse($this->QueueTask->exists()); 75 | } 76 | 77 | public function test_removeNoRemoveInProgress() { 78 | $this->QueueTask->id = '524b0c44-a3a0-4956-8428-dc3ee017215a'; 79 | $this->QueueTask->saveField('status', 2); //setting to in progress. 80 | $result = $this->QueueTask->remove(); 81 | $this->assertFalse($result); 82 | $this->assertTrue($this->QueueTask->exists()); 83 | } 84 | 85 | public function test_removeRemoveInProgressForce() { 86 | $this->QueueTask->id = '524b0c44-a3a0-4956-8428-dc3ee017215a'; 87 | $this->QueueTask->saveField('status', 2); //setting to in progress. 88 | $result = $this->QueueTask->remove(null, true); //forcing delete 89 | $this->assertTrue($result); 90 | $this->assertFalse($this->QueueTask->exists()); 91 | } 92 | 93 | public function test_addRestricted() { 94 | //Validation rules are tested, test restricted 95 | $count = $this->QueueTask->find('count'); 96 | $result = $this->QueueTask->add("Model::action()", 'model', array( 97 | 'start' => 'Sunday 11 pm', 98 | 'end' => 'Monday 5 am', 99 | 'reschedule' => '+1 week', 100 | 'cpu_limit' => 95, 101 | )); 102 | $this->assertTrue(!empty($result)); 103 | $this->assertEqual($this->QueueTask->find('count'), $count + 1); 104 | $this->assertTrue($this->QueueTask->field('is_restricted')); 105 | $this->assertEqual($this->QueueTask->field('cpu_limit'), 95); 106 | $this->assertEqual($this->QueueTask->field('type'), 1); 107 | $this->assertEqual($this->QueueTask->field('priority'), 100); 108 | $this->assertTrue(!empty($result['QueueTask']['scheduled'])); 109 | $this->assertTrue(!empty($result['QueueTask']['scheduled_end'])); 110 | $this->assertTrue(!empty($result['QueueTask']['reschedule'])); 111 | } 112 | 113 | public function test_addNormal_minimal() { 114 | $count = $this->QueueTask->find('count'); 115 | $result = $this->QueueTask->add("Model::action()", 'model'); 116 | $this->assertTrue(!empty($result)); 117 | $this->assertEqual($this->QueueTask->find('count'), $count + 1); 118 | $this->assertFalse($this->QueueTask->field('is_restricted')); 119 | $this->assertEqual($this->QueueTask->field('scheduled'), null); 120 | $this->assertEqual($this->QueueTask->field('scheduled_end'), null); 121 | $this->assertEqual($this->QueueTask->field('reschedule'), null); 122 | $this->assertEqual($this->QueueTask->field('cpu_limit'), null); 123 | $this->assertEqual($this->QueueTask->field('type'), 1); 124 | $this->assertEqual($this->QueueTask->field('priority'), 100); 125 | } 126 | 127 | public function test_addNormal_extra() { 128 | $count = $this->QueueTask->find('count'); 129 | $result = $this->QueueTask->add("Model::action()", 1, array( 130 | 'priority' => 50, 131 | )); 132 | $this->assertTrue(!empty($result)); 133 | $this->assertEqual($this->QueueTask->find('count'), $count + 1); 134 | $this->assertFalse($this->QueueTask->field('is_restricted')); 135 | $this->assertEqual($this->QueueTask->field('scheduled'), null); 136 | $this->assertEqual($this->QueueTask->field('scheduled_end'), null); 137 | $this->assertEqual($this->QueueTask->field('reschedule'), null); 138 | $this->assertEqual($this->QueueTask->field('cpu_limit'), null); 139 | $this->assertEqual($this->QueueTask->field('type'), 1); 140 | $this->assertEqual($this->QueueTask->field('priority'), 50); 141 | } 142 | 143 | public function test_next() { 144 | $result = $this->QueueTask->next(2, true, false); 145 | $this->assertEqual(count($result), 2); 146 | $this->assertEqual('524b0c44-a3a0-4956-8428-dc3ee017215f', $result[0]['QueueTask']['id']); 147 | $this->assertEqual('524b0c44-a3a0-4956-8428-dc3ee017215a', $result[1]['QueueTask']['id']); 148 | } 149 | 150 | public function test_archive() { 151 | QueueUtil::$configs['archiveAfterExecute'] = false; 152 | $this->QueueTask->id = '524b0c44-a3a0-4956-8428-dc3ee017215a'; 153 | $result = $this->QueueTask->run(); 154 | $this->assertTrue($result); 155 | 156 | $QueueTaskLog = ClassRegistry::init('Queue.QueueTaskLog'); 157 | $count = $QueueTaskLog->find('count'); 158 | $result = $this->QueueTask->archive(); 159 | $this->assertFalse($this->QueueTask->exists()); //deleted 160 | $this->assertEqual($QueueTaskLog->find('count'), $count + 1); 161 | } 162 | 163 | public function test_validCommandShellCmd() { 164 | //Validate phpShell 165 | $data = array( 166 | 'QueueTask' => array( 167 | 'type' => 5, 168 | 'command' => '', //emtpy 169 | ) 170 | ); 171 | $count = $this->QueueTask->find('count'); 172 | $result = $this->QueueTask->save($data); 173 | $this->assertFalse($result); 174 | $this->assertEqual($this->QueueTask->find('count'), $count); 175 | $this->assertTrue(!empty($this->QueueTask->validationErrors['command'])); 176 | } 177 | 178 | public function test_validCommandPhpShell() { 179 | //Validate phpShell 180 | $data = array( 181 | 'QueueTask' => array( 182 | 'type' => 4, 183 | 'command' => '', //emtpy 184 | ) 185 | ); 186 | $count = $this->QueueTask->find('count'); 187 | $result = $this->QueueTask->save($data); 188 | $this->assertFalse($result); 189 | $this->assertEqual($this->QueueTask->find('count'), $count); 190 | $this->assertTrue(!empty($this->QueueTask->validationErrors['command'])); 191 | 192 | //Validate works. 193 | QueueUtil::getConfig('allowedTypes'); 194 | QueueUtil::$configs['allowedTypes'] = array(1,2,3,4,5); 195 | $data = array( 196 | 'QueueTask' => array( 197 | 'type' => 4, //php cmd 198 | 'command' => '5 + 7' 199 | ) 200 | ); 201 | $count = $this->QueueTask->find('count'); 202 | $result = $this->QueueTask->save($data); 203 | $this->assertTrue(!empty($result)); 204 | $this->assertEqual($this->QueueTask->find('count'), $count + 1); 205 | $this->assertTrue(empty($this->QueueTask->validationErrors['command'])); 206 | } 207 | 208 | public function test_validCommandShell() { 209 | $validationErrorCommands = array( 210 | 'cake Shell command', 211 | 'Console/cake Shell command', 212 | './cake Shell command' 213 | ); 214 | foreach ($validationErrorCommands as $command) { 215 | //Validate SHell 216 | $data = array( 217 | 'QueueTask' => array( 218 | 'type' => 2, //shell 219 | 'command' => $command 220 | ) 221 | ); 222 | $count = $this->QueueTask->find('count'); 223 | $result = $this->QueueTask->save($data); 224 | $this->assertFalse($result); 225 | $this->assertEqual($this->QueueTask->find('count'), $count); 226 | $this->assertTrue(!empty($this->QueueTask->validationErrors['command'])); 227 | } 228 | 229 | //Validate works. 230 | $data = array( 231 | 'QueueTask' => array( 232 | 'type' => 2, //shell 233 | 'command' => 'Plugin.Queue command param1 param2' 234 | ) 235 | ); 236 | $count = $this->QueueTask->find('count'); 237 | $result = $this->QueueTask->save($data); 238 | $this->assertTrue(!empty($result)); 239 | $this->assertEqual($this->QueueTask->find('count'), $count + 1); 240 | $this->assertTrue(empty($this->QueueTask->validationErrors['command'])); 241 | } 242 | 243 | public function test_validUrlShell() { 244 | $validationErrorCommands = array( 245 | 'someurl', 246 | ); 247 | foreach ($validationErrorCommands as $command) { 248 | //Validate url 249 | $data = array( 250 | 'QueueTask' => array( 251 | 'type' => 3, //url 252 | 'command' => $command 253 | ) 254 | ); 255 | $count = $this->QueueTask->find('count'); 256 | $result = $this->QueueTask->save($data); 257 | $this->assertFalse($result); 258 | $this->assertEqual($this->QueueTask->find('count'), $count); 259 | $this->assertTrue(!empty($this->QueueTask->validationErrors['command'])); 260 | } 261 | 262 | //Validate works. 263 | $data = array( 264 | 'QueueTask' => array( 265 | 'type' => 3, //shell 266 | 'command' => '/some/url' 267 | ) 268 | ); 269 | $count = $this->QueueTask->find('count'); 270 | $result = $this->QueueTask->save($data); 271 | $this->assertTrue(!empty($result)); 272 | $this->assertEqual($this->QueueTask->find('count'), $count + 1); 273 | $this->assertTrue(empty($this->QueueTask->validationErrors['command'])); 274 | } 275 | 276 | public function test_validCommandModel() { 277 | $data = array( 278 | 'QueueTask' => array( 279 | //'type' => 1, //no type, validation error 280 | 'command' => 'Model::action()', 281 | ) 282 | ); 283 | $count = $this->QueueTask->find('count'); 284 | $result = $this->QueueTask->save($data); 285 | $this->assertFalse($result); 286 | $this->assertEqual($this->QueueTask->find('count'), $count); 287 | $this->assertTrue(!empty($this->QueueTask->validationErrors['type'])); 288 | 289 | //Validate Model 290 | $validationErrorCommands = array( 291 | 'Model:action()', 292 | 'Model::action(', 293 | ); 294 | foreach ($validationErrorCommands as $command) { 295 | //Validate model 296 | $data = array( 297 | 'QueueTask' => array( 298 | 'type' => 1, //model 299 | 'command' => $command 300 | ) 301 | ); 302 | $count = $this->QueueTask->find('count'); 303 | $result = $this->QueueTask->save($data); 304 | $this->assertFalse($result); 305 | $this->assertEqual($this->QueueTask->find('count'), $count); 306 | $this->assertTrue(!empty($this->QueueTask->validationErrors['command'])); 307 | } 308 | 309 | //Validate works. 310 | $data = array( 311 | 'QueueTask' => array( 312 | 'type' => 1, //model 313 | 'command' => 'Model::action("param2")' 314 | ) 315 | ); 316 | $count = $this->QueueTask->find('count'); 317 | $result = $this->QueueTask->save($data); 318 | $this->assertTrue(!empty($result)); 319 | $this->assertEqual($this->QueueTask->find('count'), $count + 1); 320 | $this->assertTrue(empty($this->QueueTask->validationErrors['command'])); 321 | } 322 | 323 | public function test_typeValidate(){ 324 | $data = array( 325 | 'QueueTask' => array( 326 | 'type' => 99, //no exist 327 | 'command' => 'Model::action()', 328 | ) 329 | ); 330 | $count = $this->QueueTask->find('count'); 331 | $result = $this->QueueTask->save($data); 332 | $this->assertFalse($result); 333 | $this->assertEqual($this->QueueTask->find('count'), $count); 334 | $this->assertTrue(!empty($this->QueueTask->validationErrors['type'])); 335 | } 336 | 337 | public function test_typeStatus(){ 338 | $data = array( 339 | 'QueueTask' => array( 340 | 'type' => 1, //model 341 | 'command' => 'Model::action()', 342 | 'status' => 99, //no exist 343 | ) 344 | ); 345 | $count = $this->QueueTask->find('count'); 346 | $result = $this->QueueTask->save($data); 347 | $this->assertFalse($result); 348 | $this->assertEqual($this->QueueTask->find('count'), $count); 349 | $this->assertTrue(!empty($this->QueueTask->validationErrors['status'])); 350 | } 351 | 352 | public function test_typeValidateAllowed(){ 353 | QueueUtil::getConfig('allowedTypes'); 354 | QueueUtil::$configs['allowedTypes'] = array(1,2); 355 | $data = array( 356 | 'QueueTask' => array( 357 | 'type' => 3, //valid type but not allowed 358 | 'command' => '/url/to/queue', 359 | ) 360 | ); 361 | $count = $this->QueueTask->find('count'); 362 | $result = $this->QueueTask->save($data); 363 | $this->assertFalse($result); 364 | $this->assertEqual($this->QueueTask->find('count'), $count); 365 | $this->assertTrue(!empty($this->QueueTask->validationErrors['type'])); 366 | 367 | //But a valid type works 368 | $data = array( 369 | 'QueueTask' => array( 370 | 'type' => 1, //valid 371 | 'command' => 'Model::action()', 372 | ) 373 | ); 374 | $result = $this->QueueTask->save($data); 375 | $this->assertTrue(!empty($result)); 376 | $this->assertEqual($this->QueueTask->find('count'), $count + 1); 377 | $this->assertTrue(empty($this->QueueTask->validationErrors['type'])); 378 | } 379 | 380 | public function test_saveUser(){ 381 | /* 382 | BROKEN, I'm not sure why I've set the mock correctly 383 | but AuthComponent::user is still being called. TODO 384 | 385 | $this->QueueTask->expects($this->once()) 386 | ->method('getCurrentUser') 387 | ->with('id') 388 | ->will($this->returnValue('1')); 389 | $this->QueueTask->id = '524b0c44-a3a0-4956-8428-dc3ee017215a'; 390 | $this->assertEqual($this->QueueTask->field('user_id'), null); 391 | $result = $this->QueueTask->saveField('type', 1); 392 | $this->assertTrue(!empty($result)); 393 | $this->assertEqual($this->QueueTask->field('user_id'), 1); 394 | */ 395 | } 396 | 397 | public function test_afterFind(){ 398 | $result = $this->QueueTask->find('first'); 399 | $this->assertEqual($result['QueueTask']['type_human'], 'model'); 400 | $this->assertEqual($result['QueueTask']['status_human'], 'queued'); 401 | $this->assertEqual($result['QueueTask']['execution_time'], 0); 402 | } 403 | 404 | public function test_runModel(){ 405 | $this->QueueTask->id = '524b0c44-a3a0-4956-8428-dc3ee017215a'; 406 | $executed = $this->QueueTask->field('executed'); 407 | $this->assertTrue(empty($executed)); 408 | 409 | $result = $this->QueueTask->run(); 410 | $this->assertTrue($result); 411 | $this->assertEqual($this->QueueTask->field('result'), '["param","param2"]'); 412 | $this->assertEqual($this->QueueTask->field('status'), 3); 413 | $executed = $this->QueueTask->field('executed'); 414 | $this->assertTrue(!empty($executed)); 415 | $start_time = $this->QueueTask->field('start_time'); 416 | $this->assertTrue(!empty($start_time)); 417 | $end_time = $this->QueueTask->field('end_time'); 418 | $this->assertTrue(!empty($end_time)); 419 | } 420 | 421 | public function test_runShell(){ 422 | $this->QueueTask->id = '524b0c44-a3a0-4956-8428-dc3ee017215b'; 423 | $executed = $this->QueueTask->field('executed'); 424 | $this->assertTrue(empty($executed)); 425 | 426 | $this->QueueTask->Shell->expects($this->once()) 427 | ->method('dispatchShell') 428 | ->with('Queue.SomeShell command param1 param2') 429 | ->will($this->returnValue('command executed.')); 430 | $result = $this->QueueTask->run(); 431 | 432 | $this->assertTrue($result); 433 | $this->assertEqual($this->QueueTask->field('result'), '"command executed."'); 434 | $this->assertEqual($this->QueueTask->field('status'), 3); 435 | $executed = $this->QueueTask->field('executed'); 436 | $this->assertTrue(!empty($executed)); 437 | $start_time = $this->QueueTask->field('start_time'); 438 | $this->assertTrue(!empty($start_time)); 439 | $end_time = $this->QueueTask->field('end_time'); 440 | $this->assertTrue(!empty($end_time)); 441 | } 442 | 443 | public function test_runUrl(){ 444 | $this->QueueTask->id = '524b0c44-a3a0-4956-8428-dc3ee017215c'; 445 | $executed = $this->QueueTask->field('executed'); 446 | $this->assertTrue(empty($executed)); 447 | 448 | $this->QueueTask->expects($this->once()) 449 | ->method('requestAction') 450 | ->with('/some/url/to/an/action') 451 | ->will($this->returnValue('
Paginator->sort('id'); ?> | 7 |Paginator->sort('user_id'); ?> | 8 |Paginator->sort('created'); ?> | 9 |Paginator->sort('modified'); ?> | 10 |Paginator->sort('executed'); ?> | 11 |Paginator->sort('scheduled'); ?> | 12 |Paginator->sort('scheduled_end'); ?> | 13 |Paginator->sort('reschedule'); ?> | 14 |Paginator->sort('start_time'); ?> | 15 |Paginator->sort('end_time'); ?> | 16 |Paginator->sort('cpu_limit'); ?> | 17 |Paginator->sort('is_restricted'); ?> | 18 |Paginator->sort('priority'); ?> | 19 |Paginator->sort('status'); ?> | 20 |Paginator->sort('type'); ?> | 21 |Paginator->sort('command'); ?> | 22 |Paginator->sort('result'); ?> | 23 |24 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
30 | | 31 | | 32 | | 33 | | 34 | | 35 | | 36 | | 37 | | 38 | | 39 | | 40 | | 41 | | 42 | | 43 | | 44 | | 45 | | 46 | | 47 | Html->link(__('View'), array('action' => 'view', $queueTask['QueueTask']['id'])); ?> 48 | Html->link(__('Edit'), array('action' => 'edit', $queueTask['QueueTask']['id'])); ?> 49 | Form->postLink(__('Delete'), array('action' => 'delete', $queueTask['QueueTask']['id']), array(), __('Are you sure you want to delete # %s?', $queueTask['QueueTask']['id'])); ?> 50 | | 51 |
56 | Paginator->counter(array( 58 | 'format' => __('Page {:page} of {:pages}, showing {:current} records out of {:count} total, starting on record {:start}, ending on {:end}') 59 | )); 60 | ?>
61 |