├── .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('hi')); 452 | $result = $this->QueueTask->run(); 453 | 454 | $this->assertTrue($result); 455 | $this->assertEqual($this->QueueTask->field('result'), '"hi<\/title><\/head><\/html>"'); 456 | $this->assertEqual($this->QueueTask->field('status'), 3); 457 | $executed = $this->QueueTask->field('executed'); 458 | $this->assertTrue(!empty($executed)); 459 | $start_time = $this->QueueTask->field('start_time'); 460 | $this->assertTrue(!empty($start_time)); 461 | $end_time = $this->QueueTask->field('end_time'); 462 | $this->assertTrue(!empty($end_time)); 463 | } 464 | 465 | public function test_runPhpCmd(){ 466 | $this->QueueTask->id = '524b0c44-a3a0-4956-8428-dc3ee017215d'; 467 | $executed = $this->QueueTask->field('executed'); 468 | $this->assertTrue(empty($executed)); 469 | 470 | $result = $this->QueueTask->run(); 471 | 472 | $this->assertTrue($result); 473 | $this->assertEqual($this->QueueTask->field('result'), '7'); 474 | $this->assertEqual($this->QueueTask->field('status'), 3); 475 | $executed = $this->QueueTask->field('executed'); 476 | $this->assertTrue(!empty($executed)); 477 | $start_time = $this->QueueTask->field('start_time'); 478 | $this->assertTrue(!empty($start_time)); 479 | $end_time = $this->QueueTask->field('end_time'); 480 | $this->assertTrue(!empty($end_time)); 481 | } 482 | 483 | public function test_runShellCmd(){ 484 | $this->QueueTask->id = '524b0c44-a3a0-4956-8428-dc3ee017215e'; 485 | $executed = $this->QueueTask->field('executed'); 486 | $this->assertTrue(empty($executed)); 487 | 488 | $result = $this->QueueTask->run(); 489 | 490 | $this->assertTrue($result); 491 | $this->assertEqual($this->QueueTask->field('result'), '"hello\nworld\n"'); 492 | $this->assertEqual($this->QueueTask->field('status'), 3); 493 | $executed = $this->QueueTask->field('executed'); 494 | $this->assertTrue(!empty($executed)); 495 | $start_time = $this->QueueTask->field('start_time'); 496 | $this->assertTrue(!empty($start_time)); 497 | $end_time = $this->QueueTask->field('end_time'); 498 | $this->assertTrue(!empty($end_time)); 499 | } 500 | 501 | public function test_runNoShell(){ 502 | $this->QueueTask->id = 'invalid_id'; 503 | $result = $this->QueueTask->run(); 504 | $this->assertFalse($result); 505 | $this->assertEqual('QueueTask invalid_id not found.', $this->QueueTask->errors['invalid_id'][0]); 506 | } 507 | 508 | } 509 | -------------------------------------------------------------------------------- /Test/Case/View/Helper/empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webtechnick/CakePHP-Queue-Plugin/996623bc0265cee13d3ee17e3022457eb3d4f465/Test/Case/View/Helper/empty -------------------------------------------------------------------------------- /Test/Fixture/QueueTaskFixture.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * QueueTaskFixture 4 | * 5 | */ 6 | class QueueTaskFixture extends CakeTestFixture { 7 | 8 | /** 9 | * Fields 10 | * 11 | * @var array 12 | */ 13 | public $fields = array( 14 | 'id' => array('type' => 'string', 'null' => false, 'default' => null, 'length' => 36, 'key' => 'primary', 'collate' => 'utf8_general_ci', 'charset' => 'utf8'), 15 | 'user_id' => array('type' => 'biginteger', 'null' => true, 'default' => null, 'length' => 22, 'comment' => 'user_id of who created/modified this queue. optional'), 16 | 'created' => array('type' => 'datetime', 'null' => true, 'default' => null, 'key' => 'index'), 17 | 'modified' => array('type' => 'datetime', 'null' => true, 'default' => null), 18 | 'executed' => array('type' => 'datetime', 'null' => true, 'default' => null, 'key' => 'index', 'comment' => 'datetime when executed.'), 19 | '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.'), 20 | '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.'), 21 | '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'), 22 | 'start_time' => array('type' => 'biginteger', 'null' => true, 'default' => null, 'length' => 22, 'comment' => 'microtime start of execution.'), 23 | 'end_time' => array('type' => 'biginteger', 'null' => true, 'default' => null, 'length' => 22, 'comment' => 'microtime end of execution.'), 24 | '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)'), 25 | 'is_restricted' => array('type' => 'boolean', 'null' => false, 'default' => '0', 'key' => 'index', 'comment' => 'will be 1 if hour, day, or cpu_limit are not null.'), 26 | '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.'), 27 | 'status' => array('type' => 'integer', 'null' => false, 'default' => '1', 'length' => 2, 'key' => 'index', 'comment' => '1:queued,2:inprogress,3:finished,4:paused'), 28 | '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'), 29 | 'command' => array('type' => 'text', 'null' => false, 'default' => null, 'collate' => 'utf8_general_ci', 'charset' => 'utf8'), 30 | 'result' => array('type' => 'text', 'null' => true, 'default' => null, 'collate' => 'utf8_general_ci', 'charset' => 'utf8'), 31 | 'indexes' => array( 32 | 'PRIMARY' => array('column' => 'id', 'unique' => 1), 33 | 'status' => array('column' => 'status', 'unique' => 0), 34 | 'type' => array('column' => 'type', 'unique' => 0), 35 | 'created' => array('column' => 'created', 'unique' => 0), 36 | 'priority' => array('column' => 'priority', 'unique' => 0), 37 | 'is_restricted' => array('column' => 'is_restricted', 'unique' => 0), 38 | 'cpu_limit' => array('column' => 'cpu_limit', 'unique' => 0), 39 | 'executed' => array('column' => 'executed', 'unique' => 0), 40 | 'scheduled' => array('column' => 'scheduled', 'unique' => 0), 41 | 'scheduled_end' => array('column' => 'scheduled_end', 'unique' => 0) 42 | ), 43 | 'tableParameters' => array('charset' => 'utf8', 'collate' => 'utf8_general_ci', 'engine' => 'MyISAM') 44 | ); 45 | 46 | /** 47 | * Records 48 | * 49 | * @var array 50 | */ 51 | public $records = array( 52 | array( 53 | 'id' => '524b0c44-a3a0-4956-8428-dc3ee017215a', 54 | 'user_id' => null, 55 | 'created' => '2013-10-01 11:54:12', 56 | 'modified' => '2013-10-01 11:54:12', 57 | 'executed' => null, 58 | 'start_time' => null, 59 | 'end_time' => null, 60 | 'scheduled' => null, 61 | 'scheduled_end' => null, 62 | 'reschedule' => null, 63 | 'cpu_limit' => null, 64 | 'is_restricted' => 0, 65 | 'priority' => 100, 66 | 'status' => 1, 67 | 'type' => 1, //model 68 | 'command' => 'SomeModel::action("param","param2")', 69 | 'result' => '', 70 | ), 71 | array( 72 | 'id' => '524b0c44-a3a0-4956-8428-dc3ee017215b', 73 | 'user_id' => null, 74 | 'created' => '2013-10-01 11:54:12', 75 | 'modified' => '2013-10-01 11:54:12', 76 | 'executed' => null, 77 | 'start_time' => null, 78 | 'end_time' => null, 79 | 'scheduled' => null, 80 | 'scheduled_end' => null, 81 | 'reschedule' => null, 82 | 'cpu_limit' => null, 83 | 'is_restricted' => 0, 84 | 'priority' => 100, 85 | 'status' => 1, 86 | 'type' => 2, //shell 87 | 'command' => 'Queue.SomeShell command param1 param2', 88 | 'result' => '', 89 | ), 90 | array( 91 | 'id' => '524b0c44-a3a0-4956-8428-dc3ee017215c', 92 | 'user_id' => null, 93 | 'created' => '2013-10-01 11:54:12', 94 | 'modified' => '2013-10-01 11:54:12', 95 | 'executed' => null, 96 | 'start_time' => null, 97 | 'end_time' => null, 98 | 'scheduled' => null, 99 | 'scheduled_end' => null, 100 | 'reschedule' => null, 101 | 'cpu_limit' => null, 102 | 'is_restricted' => 0, 103 | 'priority' => 100, 104 | 'status' => 1, 105 | 'type' => 3, //shell 106 | 'command' => '/some/url/to/an/action', 107 | 'result' => '', 108 | ), 109 | array( 110 | 'id' => '524b0c44-a3a0-4956-8428-dc3ee017215d', 111 | 'user_id' => null, 112 | 'created' => '2013-10-01 11:54:12', 113 | 'modified' => '2013-10-01 11:54:12', 114 | 'executed' => null, 115 | 'start_time' => null, 116 | 'end_time' => null, 117 | 'scheduled' => null, 118 | 'scheduled_end' => null, 119 | 'reschedule' => null, 120 | 'cpu_limit' => null, 121 | 'is_restricted' => 0, 122 | 'priority' => 100, 123 | 'status' => 1, 124 | 'type' => 4, //php_command 125 | 'command' => '2 + 5', 126 | 'result' => '', 127 | ), 128 | array( 129 | 'id' => '524b0c44-a3a0-4956-8428-dc3ee017215e', 130 | 'user_id' => null, 131 | 'created' => '2013-10-01 11:54:12', 132 | 'modified' => '2013-10-01 11:54:12', 133 | 'executed' => null, 134 | 'start_time' => null, 135 | 'end_time' => null, 136 | 'priority' => 100, 137 | 'scheduled' => null, 138 | 'scheduled_end' => null, 139 | 'reschedule' => null, 140 | 'cpu_limit' => null, 141 | 'is_restricted' => 0, 142 | 'status' => 1, 143 | 'type' => 5, //shell_cmd 144 | 'command' => 'echo "hello" && echo "world"', 145 | 'result' => '', 146 | ), 147 | array( 148 | 'id' => '524b0c44-a3a0-4956-8428-dc3ee017215f', 149 | 'user_id' => null, 150 | 'created' => '2013-10-01 11:54:12', 151 | 'modified' => '2013-10-01 11:54:12', 152 | 'executed' => null, 153 | 'start_time' => null, 154 | 'end_time' => null, 155 | 'priority' => 1, 156 | 'scheduled' => null, 157 | 'scheduled_end' => null, 158 | 'reschedule' => null, 159 | 'cpu_limit' => '95', 160 | 'is_restricted' => 1, 161 | 'status' => 1, 162 | 'type' => 5, //shell_cmd 163 | 'command' => 'echo "hello" && echo "world"', 164 | 'result' => '', 165 | ), 166 | ); 167 | 168 | } 169 | -------------------------------------------------------------------------------- /Test/Fixture/QueueTaskLogFixture.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * QueueTaskLogFixture 4 | * 5 | */ 6 | class QueueTaskLogFixture extends CakeTestFixture { 7 | 8 | /** 9 | * Fields 10 | * 11 | * @var array 12 | */ 13 | public $fields = array( 14 | 'id' => array('type' => 'string', 'null' => false, 'default' => null, 'length' => 36, 'key' => 'primary', 'collate' => 'utf8_general_ci', 'charset' => 'utf8'), 15 | 'user_id' => array('type' => 'biginteger', 'null' => true, 'default' => null, 'length' => 22, 'comment' => 'user_id of who created/modified this queue. optional'), 16 | 'created' => array('type' => 'datetime', 'null' => true, 'default' => null, 'key' => 'index'), 17 | 'modified' => array('type' => 'datetime', 'null' => true, 'default' => null), 18 | 'executed' => array('type' => 'datetime', 'null' => true, 'default' => null, 'key' => 'index', 'comment' => 'datetime when executed.'), 19 | '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.'), 20 | '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.'), 21 | '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'), 22 | 'start_time' => array('type' => 'biginteger', 'null' => true, 'default' => null, 'length' => 22, 'comment' => 'microtime start of execution.'), 23 | 'end_time' => array('type' => 'biginteger', 'null' => true, 'default' => null, 'length' => 22, 'comment' => 'microtime end of execution.'), 24 | '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)'), 25 | 'is_restricted' => array('type' => 'boolean', 'null' => false, 'default' => '0', 'key' => 'index', 'comment' => 'will be 1 if hour, day, or cpu_limit are not null.'), 26 | '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.'), 27 | 'status' => array('type' => 'integer', 'null' => false, 'default' => '1', 'length' => 2, 'key' => 'index', 'comment' => '1:queued,2:inprogress,3:finished,4:paused'), 28 | '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'), 29 | 'command' => array('type' => 'text', 'null' => false, 'default' => null, 'collate' => 'utf8_general_ci', 'charset' => 'utf8'), 30 | 'result' => array('type' => 'text', 'null' => true, 'default' => null, 'collate' => 'utf8_general_ci', 'charset' => 'utf8'), 31 | 'indexes' => array( 32 | 'PRIMARY' => array('column' => 'id', 'unique' => 1), 33 | 'status' => array('column' => 'status', 'unique' => 0), 34 | 'type' => array('column' => 'type', 'unique' => 0), 35 | 'created' => array('column' => 'created', 'unique' => 0), 36 | 'priority' => array('column' => 'priority', 'unique' => 0), 37 | 'is_restricted' => array('column' => 'is_restricted', 'unique' => 0), 38 | 'cpu_limit' => array('column' => 'cpu_limit', 'unique' => 0), 39 | 'executed' => array('column' => 'executed', 'unique' => 0), 40 | 'scheduled' => array('column' => 'scheduled', 'unique' => 0), 41 | 'scheduled_end' => array('column' => 'scheduled_end', 'unique' => 0) 42 | ), 43 | 'tableParameters' => array('charset' => 'utf8', 'collate' => 'utf8_general_ci', 'engine' => 'MyISAM') 44 | ); 45 | 46 | /** 47 | * Records 48 | * 49 | * @var array 50 | */ 51 | public $records = array( 52 | ); 53 | 54 | } 55 | -------------------------------------------------------------------------------- /Test/Fixture/empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webtechnick/CakePHP-Queue-Plugin/996623bc0265cee13d3ee17e3022457eb3d4f465/Test/Fixture/empty -------------------------------------------------------------------------------- /Vendor/empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webtechnick/CakePHP-Queue-Plugin/996623bc0265cee13d3ee17e3022457eb3d4f465/Vendor/empty -------------------------------------------------------------------------------- /View/Helper/empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webtechnick/CakePHP-Queue-Plugin/996623bc0265cee13d3ee17e3022457eb3d4f465/View/Helper/empty -------------------------------------------------------------------------------- /View/QueueTasks/admin_add.ctp: -------------------------------------------------------------------------------- 1 | <div class="queueTasks form"> 2 | <?php echo $this->Form->create('QueueTask'); ?> 3 | <fieldset> 4 | <legend><?php echo __('Admin Add Queue Task'); ?></legend> 5 | <?php 6 | echo $this->Form->input('user_id'); 7 | echo $this->Form->input('executed'); 8 | echo $this->Form->input('scheduled'); 9 | echo $this->Form->input('scheduled_end'); 10 | echo $this->Form->input('reschedule'); 11 | echo $this->Form->input('start_time'); 12 | echo $this->Form->input('end_time'); 13 | echo $this->Form->input('cpu_limit'); 14 | echo $this->Form->input('is_restricted'); 15 | echo $this->Form->input('priority'); 16 | echo $this->Form->input('status'); 17 | echo $this->Form->input('type'); 18 | echo $this->Form->input('command'); 19 | echo $this->Form->input('result'); 20 | ?> 21 | </fieldset> 22 | <?php echo $this->Form->end(__('Submit')); ?> 23 | </div> 24 | <div class="actions"> 25 | <h3><?php echo __('Actions'); ?></h3> 26 | <ul> 27 | 28 | <li><?php echo $this->Html->link(__('List Queue Tasks'), array('action' => 'index')); ?></li> 29 | </ul> 30 | </div> 31 | -------------------------------------------------------------------------------- /View/QueueTasks/admin_edit.ctp: -------------------------------------------------------------------------------- 1 | <div class="queueTasks form"> 2 | <?php echo $this->Form->create('QueueTask'); ?> 3 | <fieldset> 4 | <legend><?php echo __('Admin Edit Queue Task'); ?></legend> 5 | <?php 6 | echo $this->Form->input('id'); 7 | echo $this->Form->input('user_id'); 8 | echo $this->Form->input('executed'); 9 | echo $this->Form->input('scheduled'); 10 | echo $this->Form->input('scheduled_end'); 11 | echo $this->Form->input('reschedule'); 12 | echo $this->Form->input('start_time'); 13 | echo $this->Form->input('end_time'); 14 | echo $this->Form->input('cpu_limit'); 15 | echo $this->Form->input('is_restricted'); 16 | echo $this->Form->input('priority'); 17 | echo $this->Form->input('status'); 18 | echo $this->Form->input('type'); 19 | echo $this->Form->input('command'); 20 | echo $this->Form->input('result'); 21 | ?> 22 | </fieldset> 23 | <?php echo $this->Form->end(__('Submit')); ?> 24 | </div> 25 | <div class="actions"> 26 | <h3><?php echo __('Actions'); ?></h3> 27 | <ul> 28 | 29 | <li><?php echo $this->Form->postLink(__('Delete'), array('action' => 'delete', $this->Form->value('QueueTask.id')), array(), __('Are you sure you want to delete # %s?', $this->Form->value('QueueTask.id'))); ?></li> 30 | <li><?php echo $this->Html->link(__('List Queue Tasks'), array('action' => 'index')); ?></li> 31 | </ul> 32 | </div> 33 | -------------------------------------------------------------------------------- /View/QueueTasks/admin_index.ctp: -------------------------------------------------------------------------------- 1 | <div class="queueTasks index"> 2 | <h2><?php echo __('Queue Tasks'); ?></h2> 3 | <table cellpadding="0" cellspacing="0"> 4 | <thead> 5 | <tr> 6 | <th><?php echo $this->Paginator->sort('id'); ?></th> 7 | <th><?php echo $this->Paginator->sort('user_id'); ?></th> 8 | <th><?php echo $this->Paginator->sort('created'); ?></th> 9 | <th><?php echo $this->Paginator->sort('modified'); ?></th> 10 | <th><?php echo $this->Paginator->sort('executed'); ?></th> 11 | <th><?php echo $this->Paginator->sort('scheduled'); ?></th> 12 | <th><?php echo $this->Paginator->sort('scheduled_end'); ?></th> 13 | <th><?php echo $this->Paginator->sort('reschedule'); ?></th> 14 | <th><?php echo $this->Paginator->sort('start_time'); ?></th> 15 | <th><?php echo $this->Paginator->sort('end_time'); ?></th> 16 | <th><?php echo $this->Paginator->sort('cpu_limit'); ?></th> 17 | <th><?php echo $this->Paginator->sort('is_restricted'); ?></th> 18 | <th><?php echo $this->Paginator->sort('priority'); ?></th> 19 | <th><?php echo $this->Paginator->sort('status'); ?></th> 20 | <th><?php echo $this->Paginator->sort('type'); ?></th> 21 | <th><?php echo $this->Paginator->sort('command'); ?></th> 22 | <th><?php echo $this->Paginator->sort('result'); ?></th> 23 | <th class="actions"><?php echo __('Actions'); ?></th> 24 | </tr> 25 | </thead> 26 | <tbody> 27 | <?php foreach ($queueTasks as $queueTask): ?> 28 | <tr> 29 | <td><?php echo h($queueTask['QueueTask']['id']); ?> </td> 30 | <td><?php echo h($queueTask['QueueTask']['user_id']); ?> </td> 31 | <td><?php echo h($queueTask['QueueTask']['created']); ?> </td> 32 | <td><?php echo h($queueTask['QueueTask']['modified']); ?> </td> 33 | <td><?php echo h($queueTask['QueueTask']['executed']); ?> </td> 34 | <td><?php echo h($queueTask['QueueTask']['scheduled']); ?> </td> 35 | <td><?php echo h($queueTask['QueueTask']['scheduled_end']); ?> </td> 36 | <td><?php echo h($queueTask['QueueTask']['reschedule']); ?> </td> 37 | <td><?php echo h($queueTask['QueueTask']['start_time']); ?> </td> 38 | <td><?php echo h($queueTask['QueueTask']['end_time']); ?> </td> 39 | <td><?php echo h($queueTask['QueueTask']['cpu_limit']); ?> </td> 40 | <td><?php echo h($queueTask['QueueTask']['is_restricted']); ?> </td> 41 | <td><?php echo h($queueTask['QueueTask']['priority']); ?> </td> 42 | <td><?php echo h($queueTask['QueueTask']['status']); ?> </td> 43 | <td><?php echo h($queueTask['QueueTask']['type']); ?> </td> 44 | <td><?php echo h($queueTask['QueueTask']['command']); ?> </td> 45 | <td><?php echo h($queueTask['QueueTask']['result']); ?> </td> 46 | <td class="actions"> 47 | <?php echo $this->Html->link(__('View'), array('action' => 'view', $queueTask['QueueTask']['id'])); ?> 48 | <?php echo $this->Html->link(__('Edit'), array('action' => 'edit', $queueTask['QueueTask']['id'])); ?> 49 | <?php echo $this->Form->postLink(__('Delete'), array('action' => 'delete', $queueTask['QueueTask']['id']), array(), __('Are you sure you want to delete # %s?', $queueTask['QueueTask']['id'])); ?> 50 | </td> 51 | </tr> 52 | <?php endforeach; ?> 53 | </tbody> 54 | </table> 55 | <p> 56 | <?php 57 | echo $this->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 | ?> </p> 61 | <div class="paging"> 62 | <?php 63 | echo $this->Paginator->prev('< ' . __('previous'), array(), null, array('class' => 'prev disabled')); 64 | echo $this->Paginator->numbers(array('separator' => '')); 65 | echo $this->Paginator->next(__('next') . ' >', array(), null, array('class' => 'next disabled')); 66 | ?> 67 | </div> 68 | </div> 69 | <div class="actions"> 70 | <h3><?php echo __('Actions'); ?></h3> 71 | <ul> 72 | <li><?php echo $this->Html->link(__('New Queue Task'), array('action' => 'add')); ?></li> 73 | </ul> 74 | </div> 75 | -------------------------------------------------------------------------------- /View/QueueTasks/admin_view.ctp: -------------------------------------------------------------------------------- 1 | <div class="queueTasks view"> 2 | <h2><?php echo __('Queue Task'); ?></h2> 3 | <dl> 4 | <dt><?php echo __('Id'); ?></dt> 5 | <dd> 6 | <?php echo h($queueTask['QueueTask']['id']); ?> 7 |   8 | </dd> 9 | <dt><?php echo __('User Id'); ?></dt> 10 | <dd> 11 | <?php echo h($queueTask['QueueTask']['user_id']); ?> 12 |   13 | </dd> 14 | <dt><?php echo __('Created'); ?></dt> 15 | <dd> 16 | <?php echo $this->Time->niceShort($queueTask['QueueTask']['created']); ?> 17 |   18 | </dd> 19 | <dt><?php echo __('Modified'); ?></dt> 20 | <dd> 21 | <?php echo $this->Time->niceShort($queueTask['QueueTask']['modified']); ?> 22 |   23 | </dd> 24 | <dt><?php echo __('Executed'); ?></dt> 25 | <dd> 26 | <?php if (!empty($queueTask['QueueTask']['executed'])) echo $this->Time->niceShort($queueTask['QueueTask']['executed']); ?> 27 |   28 | </dd> 29 | <dt><?php echo __('Scheduled'); ?></dt> 30 | <dd> 31 | <?php if (!empty($queueTask['QueueTask']['scheduled'])) echo $this->Time->niceShort($queueTask['QueueTask']['scheduled']); ?> 32 |   33 | </dd> 34 | <dt><?php echo __('Scheduled End'); ?></dt> 35 | <dd> 36 | <?php if (!empty($queueTask['QueueTask']['scheduled_end'])) echo $this->Time->niceShort($queueTask['QueueTask']['scheduled_end']); ?> 37 |   38 | </dd> 39 | <dt><?php echo __('Reschedule'); ?></dt> 40 | <dd> 41 | <?php if (!empty($queueTask['QueueTask']['reshcedule'])) echo $this->Time->niceShort($queueTask['QueueTask']['reschedule']); ?> 42 |   43 | </dd> 44 | <dt><?php echo __('Start Time'); ?></dt> 45 | <dd> 46 | <?php echo h($queueTask['QueueTask']['start_time']); ?> 47 |   48 | </dd> 49 | <dt><?php echo __('End Time'); ?></dt> 50 | <dd> 51 | <?php echo h($queueTask['QueueTask']['end_time']); ?> 52 |   53 | </dd> 54 | <dt><?php echo __('Cpu Limit'); ?></dt> 55 | <dd> 56 | <?php echo h($queueTask['QueueTask']['cpu_limit']); ?> 57 |   58 | </dd> 59 | <dt><?php echo __('Is Restricted'); ?></dt> 60 | <dd> 61 | <?php echo h($queueTask['QueueTask']['is_restricted']); ?> 62 |   63 | </dd> 64 | <dt><?php echo __('Priority'); ?></dt> 65 | <dd> 66 | <?php echo h($queueTask['QueueTask']['priority']); ?> 67 |   68 | </dd> 69 | <dt><?php echo __('Status'); ?></dt> 70 | <dd> 71 | <?php echo $statuses[$queueTask['QueueTask']['status']]; ?> 72 |   73 | </dd> 74 | <dt><?php echo __('Type'); ?></dt> 75 | <dd> 76 | <?php echo $types[$queueTask['QueueTask']['type']]; ?> 77 |   78 | </dd> 79 | <dt><?php echo __('Command'); ?></dt> 80 | <dd> 81 | <?php echo h($queueTask['QueueTask']['command']); ?> 82 |   83 | </dd> 84 | <dt><?php echo __('Result'); ?></dt> 85 | <dd> 86 | <?php echo h($queueTask['QueueTask']['result']); ?> 87 |   88 | </dd> 89 | </dl> 90 | </div> 91 | <div class="actions"> 92 | <h3><?php echo __('Actions'); ?></h3> 93 | <ul> 94 | <li><?php echo $this->Html->link(__('Edit Queue Task'), array('action' => 'edit', $queueTask['QueueTask']['id'])); ?> </li> 95 | <li><?php echo $this->Html->link(__('List Queue Tasks'), array('action' => 'index')); ?> </li> 96 | <li><?php echo $this->Html->link(__('New Queue Task'), array('action' => 'add')); ?> </li> 97 | </ul> 98 | </div> 99 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webtechnick/cakephp-queue-plugin", 3 | "description": "CakePHP Queue Plugin - Complete tool to background and schedule your time consuming tasks. Queue up almost anything from CakePHP shells, models, and actions to standard php commands or even shell commands.", 4 | "type": "cakephp-plugin", 5 | "keywords": ["cakephp", "background", "tasks", "crons", "plugin"], 6 | "homepage": "https://github.com/webtechnick/CakePHP-Queue-Plugin", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Nick Baker", 11 | "homepage": "http://www.webtechnick.com", 12 | "role": "Author" 13 | } 14 | ], 15 | "support": { 16 | "issues": "https://github.com/webtechnick/CakePHP-Queue-Plugin/issues", 17 | "irc": "irc://irc.freenode.org/cakephp", 18 | "source": "https://github.com/webtechnick/CakePHP-Queue-Plugin" 19 | }, 20 | "require": { 21 | "php": ">=5.3.0", 22 | "composer/installers": "*" 23 | }, 24 | "extra": { 25 | "branch-alias": { 26 | "dev-master": "2.x-dev" 27 | }, 28 | "installer-name": "Queue" 29 | } 30 | } -------------------------------------------------------------------------------- /readme.markdown: -------------------------------------------------------------------------------- 1 | # CakePHP Queue Plugin 2 | 3 | * Author: Nick Baker 4 | * Version: 1.0.0 5 | * License: MIT 6 | * Website: <http://www.webtechnick.com> 7 | 8 | ## Features 9 | 10 | Complete tool to background and schedule your time consuming tasks. Queue up almost anything from CakePHP shells, models, and actions to standard php commands or even shell commands. 11 | 12 | ## Changelog 13 | 14 | * 1.0.0 Initial release 15 | 16 | ## Install 17 | 18 | Clone the repository into your `app/Plugin/Queue` directory: 19 | 20 | git clone https://github.com/webtechnick/CakePHP-Queue-Plugin.git app/Plugin/Queue 21 | 22 | Or you can install via <http://getcomposer.org> 23 | 24 | Load the plugin in your `app/Config/bootstrap.php` file: 25 | 26 | CakePlugin::load('Queue'); 27 | 28 | Run the schema into your database to install the required tables. 29 | 30 | cake schema create --plugin Queue 31 | 32 | ## Setup 33 | 34 | Create the file `app/Config/queue.php` with the defaults from `app/Plugin/Queue/Config/queue.php.default`: 35 | 36 | $config = array( 37 | 'Queue' => array( 38 | 'log' => true, //logs every task run in a log file. 39 | 'limit' => 1, //limit how many queues can run at a time. (default 1). 40 | 'allowedTypes' => array( //restrict what type of command can be queued. 41 | 1, //model 42 | 2, //shell 43 | 3, //url 44 | //4, //php_cmd 45 | //5, //shell_cmd 46 | ), 47 | 'archiveAfterExecute' => true, //will archive the task once finished executing for quicker queues 48 | 'cache' => '+5 minute', //how long to cache cpu usage and list. (false disables cache) 49 | 'cores' => '8', //number of cpu cores to correctly gauge current CPU load. 50 | ) 51 | ); 52 | 53 | ## Cron Setup (optional) 54 | 55 | Once you start adding things to your queue you need to process it. You can do it a few ways. 56 | 57 | 1) By setting up a cron (recommended) 58 | 59 | crontab -e 60 | */1 * * * * /path/to/app/Plugin/Queue/scripts/process_queue.sh 61 | 62 | **Note:** The cron script assumes Console/cake is executable from the root of your app directory. 63 | 64 | 2) By processing the Queue via the built in shell 65 | 66 | cake Queue.queue process 67 | 68 | 3) By processing the Queue via the built in library 69 | 70 | App::uses('Queue','Queue.Lib'); 71 | Queue::process(); 72 | 73 | 4) By navigating to the queue plugin admin web interface and processing the Queue (feature not available yet) 74 | 75 | 76 | ## Quick Start Guide (Shell) 77 | 78 | Add a Task to the queue. 79 | 80 | $ cake Queue.queue add "Queue.QueueTask::find('first')" 81 | 82 | Task succesfully added. 83 | 525387a1-2dd0-4100-a48f-4f4be017215a queued model 84 | Command: Queue.QueueTask::find('first') 85 | Priority: 100 86 | 87 | Process the Queue. 88 | 89 | $ cake Queue.queue process 90 | 91 | Processing Queue. 92 | Success. 93 | 94 | View the Task added. 95 | 96 | $ cake Queue.queue view 525387a1-2dd0-4100-a48f-4f4be017215a 97 | 98 | 525387a1-2dd0-4100-a48f-4f4be017215a finished model 99 | Command: Queue.QueueTask::find('first') 100 | Priority: 100 101 | Executed on Monday 7th of October 2013 10:19:10 PM. And took 0 ms. 102 | Result: {"QueueTask":{"id":"525387a1-2dd0-4100-a48f-4f4be017215a","user_id":null,"created":"2013-10-07 22:18:41","modified":"2013-10-07 22:19:10","executed":null,"scheduled":null,"scheduled_end":null,"reschedule":null,"start_time":"1381205950","end_time":null,"cpu_limit":null,"is_restricted":false,"priority":"100","status":"2","type":"1","command":"Queue.QueueTask::find('first')","result":null,"execution_time":null,"type_human":"model","status_human":"in progress"}} 103 | 104 | ## Quick Start Guide (Library) 105 | 106 | Adding a Task to the queue. 107 | 108 | App::uses('Queue', 'Queue.Lib'); 109 | $task = Queue::add("Queue.QueueTask::find('first')"); 110 | /* $task = 111 | 'QueueTask' => array( 112 | 'priority' => (int) 100, 113 | 'command' => 'Queue.QueueTask::find('first')', 114 | 'type' => (int) 1, 115 | 'scheduled' => null, 116 | 'scheduled_end' => null, 117 | 'reschedule' => null, 118 | 'cpu_limit' => null, 119 | 'modified' => '2013-10-07 22:22:36', 120 | 'created' => '2013-10-07 22:22:36', 121 | 'user_id' => null, 122 | 'id' => '5253888c-ae18-4ffd-991a-4436e017215a' 123 | ) */ 124 | 125 | Process the queue. 126 | 127 | $result = Queue::process(); 128 | /* $result will be boolean true */ 129 | 130 | View the Task. 131 | 132 | $task = Queue::view('5253888c-ae18-4ffd-991a-4436e017215a'); 133 | /* $task is the string representation, same as queue view. Not as useful */ 134 | 135 | $task = Queue::findById('5253888c-ae18-4ffd-991a-4436e017215a'); 136 | /* $task is now an associative array, much more useful. 137 | array( 138 | 'id' => '52538a36-df1c-4186-a50a-4076e017215a', 139 | 'user_id' => null, 140 | 'created' => '2013-10-07 22:29:42', 141 | 'modified' => '2013-10-07 22:29:42', 142 | 'executed' => '2013-10-07 22:29:42', 143 | 'scheduled' => null, 144 | 'scheduled_end' => null, 145 | 'reschedule' => null, 146 | 'start_time' => '1381206582', 147 | 'end_time' => '1381206582', 148 | 'cpu_limit' => null, 149 | 'is_restricted' => false, 150 | 'priority' => '100', 151 | 'status' => '3', 152 | 'type' => '1', 153 | 'command' => 'Queue.QueueTask::find('first')', 154 | 'result' => '{"QueueTask":{"id":"524b0c44-a3a0-4956-8428-dc3ee017215a","user_id":null,"created":"2013-10-01 11:54:12","modified":"2013-10-01 11:54:12","executed":null,"scheduled":null,"scheduled_end":null,"reschedule":null,"start_time":null,"end_time":null,"cpu_limit":null,"is_restricted":false,"priority":"100","status":"1","type":"1","command":"SomeModel::action(\"param\",\"param2\")","result":"","execution_time":null,"type_human":"model","status_human":"queued"}}', 155 | 'execution_time' => '0', 156 | 'type_human' => 'model', 157 | 'status_human' => 'finished' 158 | ) */ 159 | 160 | 161 | ## Adding Tasks to Queue Types and Commands 162 | 163 | Once you've decided how you're going to process your queue it's time to start adding tasks to your queue. 164 | 165 | To add tasks use the built in shell or library. 166 | 167 | Queue::add($command, $type, $options = array()); 168 | cake Queue.queue add "command" -t type 169 | 170 | There are *5 types* of commands you can use. The default is *model*. 171 | 172 | 1) **Model** : Model function to execute. Examples: 173 | 174 | #Command strings 175 | Model::action() 176 | Plugin.Model::action("param1","pararm2") 177 | 178 | #Adding the command to the queue. 179 | Queue::add("Plugin.Model::action('param1','pararm2')"); 180 | cake Queue.queue add "Plugin.Model::action('param1','pararm2')" 181 | 182 | Models are setup via ClassRegistry::init() and methods executed on the model object as public method calls. 183 | 184 | 2) **Shell** : CakePHP shell to execute. Examples: 185 | 186 | #Command strings 187 | ClearCache.clear_cache 188 | shell_command -f flag arg1 arg2 189 | 190 | #Adding the command to the queue. 191 | Queue::add("shell_command -f flag arg1 arg2", 'shell'); 192 | cake Queue.queue add "shell_command -f flag arg1 arg2" -t shell 193 | 194 | 3) **Url** : A URL to requestAction. Example: 195 | 196 | #Command string 197 | /path/to/url 198 | 199 | #Adding the command to the queue. 200 | Queue::add("/path/to/url", 'url'); 201 | cake Queue.queue add "/path/to/url" -t url 202 | 203 | 4) **php_cmd** : PHP Command, a simple or complex php command. Examples: 204 | 205 | #Command strings 206 | 3 + 5 207 | mail('nick@example.com','subject','message') 208 | 209 | #Adding the command to the queue. 210 | Queue::add("mail('nick@example.com','subject','message')", 'php_cmd'); 211 | cake Queue.queue add "mail('nick@example.com','subject','message')" -t php_cmd 212 | 213 | 5) **shell_cmd** : Basic Bash shell command. Examples: 214 | 215 | #Command string 216 | echo 'hello' && echo 'world' 217 | 218 | #Adding the command to the queue. 219 | Queue::add("echo 'hello' && echo 'world'", 'shell_cmd'); 220 | cake Queue.queue add "echo 'hello' && echo 'world'" -t shell_cmd 221 | 222 | **NOTE** `php_cmd` and `shell_cmd` are not allowed by default. You have to turn them on in `app/Config/queue.php`. 223 | 224 | ## Viewing Your Queue 225 | 226 | You can see what is in the queue at any given time and what is up next by calling `Queue::next($limit);` or the shell 227 | 228 | cake Queue.queue next 10 229 | 230 | Retrieving Queue List. 231 | 1) 52537d35-95d0-48aa-a48d-416de017215a queued url 232 | Command: /path/to/url 233 | Priority: 100 234 | Restricted By: 235 | Start: 2013-10-11 03:00:00 236 | CPU <= 95% 237 | 2) 52537d09-6bf0-4961-94f0-4201e017215a queued model 238 | Command: Model::action() 239 | Priority: 100 240 | 3) 52535ab8-6298-4ab3-9fc6-4b49e017215a queued shell_cmd 241 | Command: echo 'hello' && echo 'world' 242 | Priority: 100 243 | Restricted By: 244 | Start: 2013-10-07 23:00:00 245 | 4) 52537d35-95d0-48aa-a48d-416de017215a queued url 246 | Command: /path/to/url 247 | Priority: 100 248 | Restricted By: 249 | Start: 2013-10-11 03:00:00 250 | CPU <= 95% 251 | 252 | You'll see a list of your upcomming queues including restrictions you set on your tasks. 253 | 254 | ## Task Restrictions 255 | 256 | There are a number of restrictions you can assign to Tasks that will modify their order in the queue and affect when the task executes. 257 | Restricted Tasks gain priority over Non-restriction tasks (basic queued tasks). The Queue process will look for restricted tasks that match 258 | the current state of the server before it looks for non-restriction tasks as non-restriction tasks are by defination not time sensitive. 259 | 260 | #### Task Options 261 | 262 | 1) **Scheduled Start** Restriction: you can schedule a task to not execute until a certain scheduled time has passed. 263 | 264 | Queue::add($command, $type, $options = array( 265 | 'start' => 'Friday 11pm', 266 | )); 267 | 268 | # Queue Shell 269 | cake Queue.queue add "command" -t type --start "Friday 11pm" 270 | 271 | 2) **Schedule End** Restriciton: you can specify an end time to make a "window" of execution time. When using this option you must also specify a reschedule option that will go into affect if the "window" is missed. 272 | 273 | Queue::add($command, $type, $options = array( 274 | 'start' => 'Friday 11pm', 275 | 'end' => 'Saturday 5am', 276 | 'reschedule' => '+1 week' //if window is missed, will add '+1 week' to 'Friday 11pm' and 'Saturday 5am' 277 | )); 278 | 279 | # Queue Shell 280 | cake Queue.queue add "command" -t type --start "Friday 11pm" --end "Saturday 5am" --reschedule "+1 week" 281 | 282 | 3) **Cpu Load** Restriction: you can specify a CPU load restriction to only execute task when CPU is below a certain threshold. 283 | 284 | # Task will execute when the current CPU load is less than 95% 285 | Queue::add($command, $type, $options = array( 286 | 'cpu' => '95', 287 | )); 288 | 289 | # Queue Shell 290 | cake Queue.queue add "command" -t type --cpu "95" 291 | 292 | 4) **Priority** Restriction: by default all Tasks added are given 100 in priority. You can change this priority when adding and will allow you to jump ahead of the line. The lower the number the closer to the top of the queue it becomes. 293 | 294 | # This will jump the task to the top of the queue (after restrictions tasks) 295 | Queue::add($command, $type, $options = array( 296 | 'priority' => '1', 297 | )); 298 | 299 | # Queue Shell 300 | cake Queue.queue add "command" -t type -p 1 301 | 302 | Mix and match your restrictions to have total control over when your tasks execute and where they're placed in the queue. 303 | 304 | ## Running A Task Manually 305 | 306 | You can bypass the queue process and explicicty run a task manually. This will bypass any restrictions execute the command and return the result. 307 | 308 | //Queue::run($id); 309 | #cake Queue.queue run <id> 310 | 311 | $ cake Queue.queue run 52535ab8-6298-4ab3-9fc6-4b49e017215a 312 | 313 | Running 52535ab8-6298-4ab3-9fc6-4b49e017215a 314 | Success. 315 | 52535ab8-6298-4ab3-9fc6-4b49e017215a finished shell_cmd 316 | Command: echo 'hello' && echo 'world' 317 | Priority: 100 318 | Restricted By: 319 | Start: 2013-10-07 23:00:00 320 | Executed on Monday 7th of October 2013 10:06:27 PM. And took 0 ms. 321 | Result: "hello\nworld\n" 322 | 323 | ## Viewing A Task 324 | 325 | You can view any task, in the queue or in the queue log (archive after execution) at anytime. 326 | You'll see all the meta data and if it's a finished task you'll see the result of the task as well as the execution time and how long it took to complete. 327 | 328 | //$task = Queue::view($id); 329 | #cake Queue.queue view <id> 330 | 331 | $ cake Queue.queue view 52535ab8-6298-4ab3-9fc6-4b49e017215a 332 | 333 | 52535ab8-6298-4ab3-9fc6-4b49e017215a finished shell_cmd 334 | Command: echo 'hello' && echo 'world' 335 | Priority: 100 336 | Restricted By: 337 | Start: 2013-10-07 23:00:00 338 | Executed on Monday 7th of October 2013 10:06:27 PM. And took 0 ms. 339 | Result: "hello\nworld\n" 340 | 341 | ## Viewing Tasks in Progress 342 | 343 | You can view the current tasks in progress via the library or shell. 344 | 345 | $queue = Queue::inProgress(); 346 | cake Queue.queue in_progress 347 | 348 | **NOTE:** You can also get just the progress count by running `cake Queue.queue in_progress_count` or `Queue::inProgressCount();` 349 | 350 | ## Removing Tasks from Queue 351 | 352 | Remove tasks from the queue. Note this will not remove tasks that are currently in progress by default. 353 | 354 | //Queue::remove($id); 355 | cake Queue.queue remove <id> 356 | 357 | **NOTE:** You can force a task to be removed even if it's in progress by passing `true` into `Queue::remove($id, true);` or `cake queue.queue remove <id> -f` 358 | 359 | # Enjoy 360 | 361 | Enjoy the plugin! 362 | -------------------------------------------------------------------------------- /scripts/process.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 3 | cd $DIR/.. 4 | Console/cake queue.queue process >> /tmp/queue_process_outpt.log 5 | -------------------------------------------------------------------------------- /webroot/empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webtechnick/CakePHP-Queue-Plugin/996623bc0265cee13d3ee17e3022457eb3d4f465/webroot/empty --------------------------------------------------------------------------------