First commit
This commit is contained in:
commit
c6e2478c40
13918 changed files with 2303184 additions and 0 deletions
67
sites/all/modules/civicrm/CRM/Queue/BAO/QueueItem.php
Normal file
67
sites/all/modules/civicrm/CRM/Queue/BAO/QueueItem.php
Normal file
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
/*
|
||||
+--------------------------------------------------------------------+
|
||||
| CiviCRM version 4.7 |
|
||||
+--------------------------------------------------------------------+
|
||||
| Copyright CiviCRM LLC (c) 2004-2017 |
|
||||
+--------------------------------------------------------------------+
|
||||
| This file is a part of CiviCRM. |
|
||||
| |
|
||||
| CiviCRM is free software; you can copy, modify, and distribute it |
|
||||
| under the terms of the GNU Affero General Public License |
|
||||
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
|
||||
| |
|
||||
| CiviCRM is distributed in the hope that it will be useful, but |
|
||||
| WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|
||||
| See the GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| You should have received a copy of the GNU Affero General Public |
|
||||
| License and the CiviCRM Licensing Exception along |
|
||||
| with this program; if not, contact CiviCRM LLC |
|
||||
| at info[AT]civicrm[DOT]org. If you have questions about the |
|
||||
| GNU Affero General Public License or the licensing of CiviCRM, |
|
||||
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
|
||||
+--------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @package CRM
|
||||
* @copyright CiviCRM LLC (c) 2004-2017
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Helpers for managing SQL-backed queue items
|
||||
*
|
||||
* @see CRM_Queue_Queue_Sql
|
||||
*/
|
||||
class CRM_Queue_BAO_QueueItem extends CRM_Queue_DAO_QueueItem {
|
||||
|
||||
/**
|
||||
* Ensure that the required SQL table exists.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if table now exists
|
||||
*/
|
||||
public static function findCreateTable() {
|
||||
$checkTableSql = "show tables like 'civicrm_queue_item'";
|
||||
$foundName = CRM_Core_DAO::singleValueQuery($checkTableSql);
|
||||
if ($foundName == 'civicrm_queue_item') {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// civicrm/sql/civicrm_queue_item.mysql
|
||||
$fileName = dirname(__FILE__) . '/../../../sql/civicrm_queue_item.mysql';
|
||||
|
||||
$config = CRM_Core_Config::singleton();
|
||||
CRM_Utils_File::sourceSQLFile($config->dsn, $fileName);
|
||||
|
||||
// Make sure it succeeded
|
||||
$foundName = CRM_Core_DAO::singleValueQuery($checkTableSql);
|
||||
return ($foundName == 'civicrm_queue_item');
|
||||
}
|
||||
|
||||
}
|
251
sites/all/modules/civicrm/CRM/Queue/DAO/QueueItem.php
Normal file
251
sites/all/modules/civicrm/CRM/Queue/DAO/QueueItem.php
Normal file
|
@ -0,0 +1,251 @@
|
|||
<?php
|
||||
/*
|
||||
+--------------------------------------------------------------------+
|
||||
| CiviCRM version 4.7 |
|
||||
+--------------------------------------------------------------------+
|
||||
| Copyright CiviCRM LLC (c) 2004-2017 |
|
||||
+--------------------------------------------------------------------+
|
||||
| This file is a part of CiviCRM. |
|
||||
| |
|
||||
| CiviCRM is free software; you can copy, modify, and distribute it |
|
||||
| under the terms of the GNU Affero General Public License |
|
||||
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
|
||||
| |
|
||||
| CiviCRM is distributed in the hope that it will be useful, but |
|
||||
| WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|
||||
| See the GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| You should have received a copy of the GNU Affero General Public |
|
||||
| License and the CiviCRM Licensing Exception along |
|
||||
| with this program; if not, contact CiviCRM LLC |
|
||||
| at info[AT]civicrm[DOT]org. If you have questions about the |
|
||||
| GNU Affero General Public License or the licensing of CiviCRM, |
|
||||
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
|
||||
+--------------------------------------------------------------------+
|
||||
*/
|
||||
/**
|
||||
* @package CRM
|
||||
* @copyright CiviCRM LLC (c) 2004-2017
|
||||
*
|
||||
* Generated from xml/schema/CRM/Queue/QueueItem.xml
|
||||
* DO NOT EDIT. Generated by CRM_Core_CodeGen
|
||||
* (GenCodeChecksum:6ca85e3a41502dda3e60a1c53a83c67f)
|
||||
*/
|
||||
require_once 'CRM/Core/DAO.php';
|
||||
require_once 'CRM/Utils/Type.php';
|
||||
/**
|
||||
* CRM_Queue_DAO_QueueItem constructor.
|
||||
*/
|
||||
class CRM_Queue_DAO_QueueItem extends CRM_Core_DAO {
|
||||
/**
|
||||
* Static instance to hold the table name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
static $_tableName = 'civicrm_queue_item';
|
||||
/**
|
||||
* Should CiviCRM log any modifications to this table in the civicrm_log table.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
static $_log = false;
|
||||
/**
|
||||
*
|
||||
* @var int unsigned
|
||||
*/
|
||||
public $id;
|
||||
/**
|
||||
* Name of the queue which includes this item
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $queue_name;
|
||||
/**
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $weight;
|
||||
/**
|
||||
* date on which this item was submitted to the queue
|
||||
*
|
||||
* @var datetime
|
||||
*/
|
||||
public $submit_time;
|
||||
/**
|
||||
* date on which this job becomes available; null if ASAP
|
||||
*
|
||||
* @var datetime
|
||||
*/
|
||||
public $release_time;
|
||||
/**
|
||||
* Serialized queue
|
||||
*
|
||||
* @var text
|
||||
*/
|
||||
public $data;
|
||||
/**
|
||||
* Class constructor.
|
||||
*/
|
||||
function __construct() {
|
||||
$this->__table = 'civicrm_queue_item';
|
||||
parent::__construct();
|
||||
}
|
||||
/**
|
||||
* Returns all the column names of this table
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
static function &fields() {
|
||||
if (!isset(Civi::$statics[__CLASS__]['fields'])) {
|
||||
Civi::$statics[__CLASS__]['fields'] = array(
|
||||
'id' => array(
|
||||
'name' => 'id',
|
||||
'type' => CRM_Utils_Type::T_INT,
|
||||
'title' => ts('Queue ID') ,
|
||||
'required' => true,
|
||||
'table_name' => 'civicrm_queue_item',
|
||||
'entity' => 'QueueItem',
|
||||
'bao' => 'CRM_Queue_BAO_QueueItem',
|
||||
'localizable' => 0,
|
||||
) ,
|
||||
'queue_name' => array(
|
||||
'name' => 'queue_name',
|
||||
'type' => CRM_Utils_Type::T_STRING,
|
||||
'title' => ts('Queue Name') ,
|
||||
'description' => 'Name of the queue which includes this item',
|
||||
'required' => true,
|
||||
'maxlength' => 64,
|
||||
'size' => CRM_Utils_Type::BIG,
|
||||
'table_name' => 'civicrm_queue_item',
|
||||
'entity' => 'QueueItem',
|
||||
'bao' => 'CRM_Queue_BAO_QueueItem',
|
||||
'localizable' => 0,
|
||||
'html' => array(
|
||||
'type' => 'Text',
|
||||
) ,
|
||||
) ,
|
||||
'weight' => array(
|
||||
'name' => 'weight',
|
||||
'type' => CRM_Utils_Type::T_INT,
|
||||
'title' => ts('Order') ,
|
||||
'required' => true,
|
||||
'table_name' => 'civicrm_queue_item',
|
||||
'entity' => 'QueueItem',
|
||||
'bao' => 'CRM_Queue_BAO_QueueItem',
|
||||
'localizable' => 0,
|
||||
'html' => array(
|
||||
'type' => 'Text',
|
||||
) ,
|
||||
) ,
|
||||
'submit_time' => array(
|
||||
'name' => 'submit_time',
|
||||
'type' => CRM_Utils_Type::T_DATE + CRM_Utils_Type::T_TIME,
|
||||
'title' => ts('Submit Time') ,
|
||||
'description' => 'date on which this item was submitted to the queue',
|
||||
'required' => true,
|
||||
'table_name' => 'civicrm_queue_item',
|
||||
'entity' => 'QueueItem',
|
||||
'bao' => 'CRM_Queue_BAO_QueueItem',
|
||||
'localizable' => 0,
|
||||
'html' => array(
|
||||
'type' => 'Select Date',
|
||||
) ,
|
||||
) ,
|
||||
'release_time' => array(
|
||||
'name' => 'release_time',
|
||||
'type' => CRM_Utils_Type::T_DATE + CRM_Utils_Type::T_TIME,
|
||||
'title' => ts('Release Time') ,
|
||||
'description' => 'date on which this job becomes available; null if ASAP',
|
||||
'table_name' => 'civicrm_queue_item',
|
||||
'entity' => 'QueueItem',
|
||||
'bao' => 'CRM_Queue_BAO_QueueItem',
|
||||
'localizable' => 0,
|
||||
'html' => array(
|
||||
'type' => 'Select Date',
|
||||
) ,
|
||||
) ,
|
||||
'data' => array(
|
||||
'name' => 'data',
|
||||
'type' => CRM_Utils_Type::T_TEXT,
|
||||
'title' => ts('Queue item datas') ,
|
||||
'description' => 'Serialized queue',
|
||||
'table_name' => 'civicrm_queue_item',
|
||||
'entity' => 'QueueItem',
|
||||
'bao' => 'CRM_Queue_BAO_QueueItem',
|
||||
'localizable' => 0,
|
||||
) ,
|
||||
);
|
||||
CRM_Core_DAO_AllCoreTables::invoke(__CLASS__, 'fields_callback', Civi::$statics[__CLASS__]['fields']);
|
||||
}
|
||||
return Civi::$statics[__CLASS__]['fields'];
|
||||
}
|
||||
/**
|
||||
* Return a mapping from field-name to the corresponding key (as used in fields()).
|
||||
*
|
||||
* @return array
|
||||
* Array(string $name => string $uniqueName).
|
||||
*/
|
||||
static function &fieldKeys() {
|
||||
if (!isset(Civi::$statics[__CLASS__]['fieldKeys'])) {
|
||||
Civi::$statics[__CLASS__]['fieldKeys'] = array_flip(CRM_Utils_Array::collect('name', self::fields()));
|
||||
}
|
||||
return Civi::$statics[__CLASS__]['fieldKeys'];
|
||||
}
|
||||
/**
|
||||
* Returns the names of this table
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
static function getTableName() {
|
||||
return self::$_tableName;
|
||||
}
|
||||
/**
|
||||
* Returns if this table needs to be logged
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
function getLog() {
|
||||
return self::$_log;
|
||||
}
|
||||
/**
|
||||
* Returns the list of fields that can be imported
|
||||
*
|
||||
* @param bool $prefix
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
static function &import($prefix = false) {
|
||||
$r = CRM_Core_DAO_AllCoreTables::getImports(__CLASS__, 'queue_item', $prefix, array());
|
||||
return $r;
|
||||
}
|
||||
/**
|
||||
* Returns the list of fields that can be exported
|
||||
*
|
||||
* @param bool $prefix
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
static function &export($prefix = false) {
|
||||
$r = CRM_Core_DAO_AllCoreTables::getExports(__CLASS__, 'queue_item', $prefix, array());
|
||||
return $r;
|
||||
}
|
||||
/**
|
||||
* Returns the list of indices
|
||||
*/
|
||||
public static function indices($localize = TRUE) {
|
||||
$indices = array(
|
||||
'index_queueids' => array(
|
||||
'name' => 'index_queueids',
|
||||
'field' => array(
|
||||
0 => 'queue_name',
|
||||
1 => 'weight',
|
||||
2 => 'id',
|
||||
) ,
|
||||
'localizable' => false,
|
||||
'sig' => 'civicrm_queue_item::0::queue_name::weight::id',
|
||||
) ,
|
||||
);
|
||||
return ($localize && !empty($indices)) ? CRM_Core_DAO_AllCoreTables::multilingualize(__CLASS__, $indices) : $indices;
|
||||
}
|
||||
}
|
201
sites/all/modules/civicrm/CRM/Queue/ErrorPolicy.php
Normal file
201
sites/all/modules/civicrm/CRM/Queue/ErrorPolicy.php
Normal file
|
@ -0,0 +1,201 @@
|
|||
<?php
|
||||
/*
|
||||
+--------------------------------------------------------------------+
|
||||
| CiviCRM version 4.7 |
|
||||
+--------------------------------------------------------------------+
|
||||
| Copyright CiviCRM LLC (c) 2004-2017 |
|
||||
+--------------------------------------------------------------------+
|
||||
| This file is a part of CiviCRM. |
|
||||
| |
|
||||
| CiviCRM is free software; you can copy, modify, and distribute it |
|
||||
| under the terms of the GNU Affero General Public License |
|
||||
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
|
||||
| |
|
||||
| CiviCRM is distributed in the hope that it will be useful, but |
|
||||
| WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|
||||
| See the GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| You should have received a copy of the GNU Affero General Public |
|
||||
| License and the CiviCRM Licensing Exception along |
|
||||
| with this program; if not, contact CiviCRM LLC |
|
||||
| at info[AT]civicrm[DOT]org. If you have questions about the |
|
||||
| GNU Affero General Public License or the licensing of CiviCRM, |
|
||||
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
|
||||
+--------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/**
|
||||
* To ensure that PHP errors or unhandled exceptions are reported in JSON
|
||||
* format, wrap this around your code. For example:
|
||||
*
|
||||
* @code
|
||||
* $errorContainer = new CRM_Queue_ErrorPolicy();
|
||||
* $errorContainer->call(function() {
|
||||
* ...include some files, do some work, etc...
|
||||
* });
|
||||
* @endcode
|
||||
*
|
||||
* Note: Most of the code in this class is pretty generic vis-a-vis error
|
||||
* handling -- except for 'reportError', whose message format is only
|
||||
* appropriate for use with the CRM_Queue_Page_AJAX. Some kind of cleanup
|
||||
* will be necessary to get reuse from the other parts of this class.
|
||||
*/
|
||||
class CRM_Queue_ErrorPolicy {
|
||||
public $active;
|
||||
|
||||
/**
|
||||
* @param null|int $level
|
||||
* PHP error level to capture (e.g. E_PARSE|E_USER_ERROR).
|
||||
*/
|
||||
public function __construct($level = NULL) {
|
||||
register_shutdown_function(array($this, 'onShutdown'));
|
||||
if ($level === NULL) {
|
||||
$level = E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR;
|
||||
}
|
||||
$this->level = $level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the error policy.
|
||||
*/
|
||||
public function activate() {
|
||||
$this->active = TRUE;
|
||||
$this->backup = array();
|
||||
foreach (array(
|
||||
'display_errors',
|
||||
'html_errors',
|
||||
'xmlrpc_errors',
|
||||
) as $key) {
|
||||
$this->backup[$key] = ini_get($key);
|
||||
ini_set($key, 0);
|
||||
}
|
||||
set_error_handler(array($this, 'onError'), $this->level);
|
||||
// FIXME make this temporary/reversible
|
||||
$this->errorScope = CRM_Core_TemporaryErrorScope::useException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the error policy.
|
||||
*/
|
||||
public function deactivate() {
|
||||
$this->errorScope = NULL;
|
||||
restore_error_handler();
|
||||
foreach (array(
|
||||
'display_errors',
|
||||
'html_errors',
|
||||
'xmlrpc_errors',
|
||||
) as $key) {
|
||||
ini_set($key, $this->backup[$key]);
|
||||
}
|
||||
$this->active = FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the callable. Activate and deactivate the error policy
|
||||
* automatically.
|
||||
*
|
||||
* @param callable|array|string $callable
|
||||
* A callback function.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function call($callable) {
|
||||
$this->activate();
|
||||
try {
|
||||
$result = $callable();
|
||||
}
|
||||
catch (Exception$e) {
|
||||
$this->reportException($e);
|
||||
}
|
||||
$this->deactivate();
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive (semi) recoverable error notices.
|
||||
*
|
||||
* @see set_error_handler
|
||||
*
|
||||
* @param string $errno
|
||||
* @param string $errstr
|
||||
* @param string $errfile
|
||||
* @param int $errline
|
||||
*
|
||||
* @return bool
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function onError($errno, $errstr, $errfile, $errline) {
|
||||
if (!(error_reporting() & $errno)) {
|
||||
return TRUE;
|
||||
}
|
||||
throw new Exception(sprintf('PHP Error %s at %s:%s: %s', $errno, $errfile, $errline, $errstr));
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive non-recoverable error notices
|
||||
*
|
||||
* @see register_shutdown_function
|
||||
* @see error_get_last
|
||||
*/
|
||||
public function onShutdown() {
|
||||
if (!$this->active) {
|
||||
return;
|
||||
}
|
||||
$error = error_get_last();
|
||||
if (is_array($error) && ($error['type'] & $this->level)) {
|
||||
$this->reportError($error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print a fatal error.
|
||||
*
|
||||
* @param array $error
|
||||
* The PHP error (with "type", "message", etc).
|
||||
*/
|
||||
public function reportError($error) {
|
||||
$response = array(
|
||||
'is_error' => 1,
|
||||
'is_continue' => 0,
|
||||
'exception' => htmlentities(sprintf('Error %s: %s in %s, line %s', $error['type'], $error['message'], $error['file'], $error['line'])),
|
||||
);
|
||||
global $activeQueueRunner;
|
||||
if (is_object($activeQueueRunner)) {
|
||||
$response['last_task_title'] = $activeQueueRunner->lastTaskTitle;
|
||||
}
|
||||
CRM_Core_Error::debug_var('CRM_Queue_ErrorPolicy_reportError', $response);
|
||||
echo json_encode($response);
|
||||
// civiExit() is unnecessary -- we're only called as part of abend
|
||||
}
|
||||
|
||||
/**
|
||||
* Print an unhandled exception.
|
||||
*
|
||||
* @param Exception $e
|
||||
* The unhandled exception.
|
||||
*/
|
||||
public function reportException(Exception $e) {
|
||||
CRM_Core_Error::debug_var('CRM_Queue_ErrorPolicy_reportException', CRM_Core_Error::formatTextException($e));
|
||||
|
||||
$response = array(
|
||||
'is_error' => 1,
|
||||
'is_continue' => 0,
|
||||
);
|
||||
|
||||
$config = CRM_Core_Config::singleton();
|
||||
if ($config->backtrace || CRM_Core_Config::isUpgradeMode()) {
|
||||
$response['exception'] = CRM_Core_Error::formatHtmlException($e);
|
||||
}
|
||||
else {
|
||||
$response['exception'] = htmlentities($e->getMessage());
|
||||
}
|
||||
|
||||
global $activeQueueRunner;
|
||||
if (is_object($activeQueueRunner)) {
|
||||
$response['last_task_title'] = $activeQueueRunner->lastTaskTitle;
|
||||
}
|
||||
CRM_Utils_JSON::output($response);
|
||||
}
|
||||
|
||||
}
|
91
sites/all/modules/civicrm/CRM/Queue/Menu.php
Normal file
91
sites/all/modules/civicrm/CRM/Queue/Menu.php
Normal file
|
@ -0,0 +1,91 @@
|
|||
<?php
|
||||
/*
|
||||
+--------------------------------------------------------------------+
|
||||
| CiviCRM version 4.7 |
|
||||
+--------------------------------------------------------------------+
|
||||
| Copyright CiviCRM LLC (c) 2004-2017 |
|
||||
+--------------------------------------------------------------------+
|
||||
| This file is a part of CiviCRM. |
|
||||
| |
|
||||
| CiviCRM is free software; you can copy, modify, and distribute it |
|
||||
| under the terms of the GNU Affero General Public License |
|
||||
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
|
||||
| |
|
||||
| CiviCRM is distributed in the hope that it will be useful, but |
|
||||
| WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|
||||
| See the GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| You should have received a copy of the GNU Affero General Public |
|
||||
| License and the CiviCRM Licensing Exception along |
|
||||
| with this program; if not, contact CiviCRM LLC |
|
||||
| at info[AT]civicrm[DOT]org. If you have questions about the |
|
||||
| GNU Affero General Public License or the licensing of CiviCRM, |
|
||||
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
|
||||
+--------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/**
|
||||
* This file hard-codes the path entries for the queueing UI, which
|
||||
* allows us to use these paths during upgrades.
|
||||
*
|
||||
* @package CRM
|
||||
* @copyright CiviCRM LLC (c) 2004-2017
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
require_once 'CRM/Core/I18n.php';
|
||||
|
||||
/**
|
||||
* Class CRM_Queue_Menu
|
||||
*/
|
||||
class CRM_Queue_Menu {
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* The path for which we are trying to locate the route.
|
||||
* @param array $menuPath
|
||||
* The route.
|
||||
*/
|
||||
public static function alter($path, &$menuPath) {
|
||||
switch ($path) {
|
||||
case 'civicrm/queue/runner':
|
||||
case 'civicrm/upgrade/queue/runner':
|
||||
$menuPath['path'] = $path;
|
||||
$menuPath['title'] = 'Queue Runner';
|
||||
$menuPath['page_callback'] = 'CRM_Queue_Page_Runner';
|
||||
$menuPath['access_arguments'][0][] = 'access CiviCRM';
|
||||
$menuPath['access_callback'] = array('CRM_Core_Permission', 'checkMenu');
|
||||
break;
|
||||
|
||||
case 'civicrm/queue/ajax/runNext':
|
||||
case 'civicrm/upgrade/queue/ajax/runNext':
|
||||
$menuPath['path'] = $path;
|
||||
$menuPath['page_callback'] = array('CRM_Queue_Page_AJAX', 'runNext');
|
||||
$menuPath['access_arguments'][0][] = 'access CiviCRM';
|
||||
$menuPath['access_callback'] = array('CRM_Core_Permission', 'checkMenu');
|
||||
break;
|
||||
|
||||
case 'civicrm/queue/ajax/skipNext':
|
||||
case 'civicrm/upgrade/queue/ajax/skipNext':
|
||||
$menuPath['path'] = $path;
|
||||
$menuPath['page_callback'] = array('CRM_Queue_Page_AJAX', 'skipNext');
|
||||
$menuPath['access_arguments'][0][] = 'access CiviCRM';
|
||||
$menuPath['access_callback'] = array('CRM_Core_Permission', 'checkMenu');
|
||||
break;
|
||||
|
||||
case 'civicrm/queue/ajax/onEnd':
|
||||
case 'civicrm/upgrade/queue/ajax/onEnd':
|
||||
$menuPath['path'] = $path;
|
||||
$menuPath['page_callback'] = array('CRM_Queue_Page_AJAX', 'onEnd');
|
||||
$menuPath['access_arguments'][0][] = 'access CiviCRM';
|
||||
$menuPath['access_callback'] = array('CRM_Core_Permission', 'checkMenu');
|
||||
break;
|
||||
|
||||
default:
|
||||
// unrecognized
|
||||
}
|
||||
}
|
||||
|
||||
}
|
131
sites/all/modules/civicrm/CRM/Queue/Page/AJAX.php
Normal file
131
sites/all/modules/civicrm/CRM/Queue/Page/AJAX.php
Normal file
|
@ -0,0 +1,131 @@
|
|||
<?php
|
||||
/*
|
||||
+--------------------------------------------------------------------+
|
||||
| CiviCRM version 4.7 |
|
||||
+--------------------------------------------------------------------+
|
||||
| Copyright CiviCRM LLC (c) 2004-2017 |
|
||||
+--------------------------------------------------------------------+
|
||||
| This file is a part of CiviCRM. |
|
||||
| |
|
||||
| CiviCRM is free software; you can copy, modify, and distribute it |
|
||||
| under the terms of the GNU Affero General Public License |
|
||||
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
|
||||
| |
|
||||
| CiviCRM is distributed in the hope that it will be useful, but |
|
||||
| WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|
||||
| See the GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| You should have received a copy of the GNU Affero General Public |
|
||||
| License and the CiviCRM Licensing Exception along |
|
||||
| with this program; if not, contact CiviCRM LLC |
|
||||
| at info[AT]civicrm[DOT]org. If you have questions about the |
|
||||
| GNU Affero General Public License or the licensing of CiviCRM, |
|
||||
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
|
||||
+--------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class CRM_Queue_Page_AJAX
|
||||
*/
|
||||
class CRM_Queue_Page_AJAX {
|
||||
|
||||
/**
|
||||
* Run the next task and return status information.
|
||||
*
|
||||
* Outputs JSON: array(
|
||||
* is_error => bool,
|
||||
* is_continue => bool,
|
||||
* numberOfItems => int,
|
||||
* exception => htmlString
|
||||
* )
|
||||
*/
|
||||
public static function runNext() {
|
||||
$errorPolicy = new CRM_Queue_ErrorPolicy();
|
||||
$errorPolicy->call(function () {
|
||||
global $activeQueueRunner;
|
||||
$qrid = CRM_Utils_Request::retrieve('qrid', 'String', CRM_Core_DAO::$_nullObject, TRUE, NULL, 'POST');
|
||||
$activeQueueRunner = CRM_Queue_Runner::instance($qrid);
|
||||
if (!is_object($activeQueueRunner)) {
|
||||
throw new Exception('Queue runner must be configured before execution.');
|
||||
}
|
||||
$result = $activeQueueRunner->runNext(TRUE);
|
||||
CRM_Queue_Page_AJAX::_return('runNext', $result);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the next task and return status information.
|
||||
*
|
||||
* Outputs JSON: array(
|
||||
* is_error => bool,
|
||||
* is_continue => bool,
|
||||
* numberOfItems => int,
|
||||
* exception => htmlString
|
||||
* )
|
||||
*/
|
||||
public static function skipNext() {
|
||||
$errorPolicy = new CRM_Queue_ErrorPolicy();
|
||||
$errorPolicy->call(function () {
|
||||
global $activeQueueRunner;
|
||||
$qrid = CRM_Utils_Request::retrieve('qrid', 'String', CRM_Core_DAO::$_nullObject, TRUE, NULL, 'POST');
|
||||
$activeQueueRunner = CRM_Queue_Runner::instance($qrid);
|
||||
if (!is_object($activeQueueRunner)) {
|
||||
throw new Exception('Queue runner must be configured before execution.');
|
||||
}
|
||||
$result = $activeQueueRunner->skipNext(TRUE);
|
||||
CRM_Queue_Page_AJAX::_return('skipNext', $result);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the next task and return status information.
|
||||
*
|
||||
* Outputs JSON: array(
|
||||
* is_error => bool,
|
||||
* is_continue => bool,
|
||||
* numberOfItems => int,
|
||||
* exception => htmlString
|
||||
* )
|
||||
*/
|
||||
public static function onEnd() {
|
||||
$errorPolicy = new CRM_Queue_ErrorPolicy();
|
||||
$errorPolicy->call(function () {
|
||||
global $activeQueueRunner;
|
||||
$qrid = CRM_Utils_Request::retrieve('qrid', 'String', CRM_Core_DAO::$_nullObject, TRUE, NULL, 'POST');
|
||||
$activeQueueRunner = CRM_Queue_Runner::instance($qrid);
|
||||
if (!is_object($activeQueueRunner)) {
|
||||
throw new Exception('Queue runner must be configured before execution. - onEnd');
|
||||
}
|
||||
$result = $activeQueueRunner->handleEnd(FALSE);
|
||||
CRM_Queue_Page_AJAX::_return('onEnd', $result);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Performing any view-layer filtering on result and send to client.
|
||||
*
|
||||
* @param string $op
|
||||
* @param array $result
|
||||
*/
|
||||
public static function _return($op, $result) {
|
||||
if ($result['is_error']) {
|
||||
if (is_object($result['exception'])) {
|
||||
CRM_Core_Error::debug_var("CRM_Queue_Page_AJAX_{$op}_error", CRM_Core_Error::formatTextException($result['exception']));
|
||||
|
||||
$config = CRM_Core_Config::singleton();
|
||||
if ($config->backtrace || CRM_Core_Config::isUpgradeMode()) {
|
||||
$result['exception'] = CRM_Core_Error::formatHtmlException($result['exception']);
|
||||
}
|
||||
else {
|
||||
$result['exception'] = $result['exception']->getMessage();
|
||||
}
|
||||
}
|
||||
else {
|
||||
CRM_Core_Error::debug_var("CRM_Queue_Page_AJAX_{$op}_error", $result);
|
||||
}
|
||||
}
|
||||
CRM_Utils_JSON::output($result);
|
||||
}
|
||||
|
||||
}
|
83
sites/all/modules/civicrm/CRM/Queue/Page/Runner.php
Normal file
83
sites/all/modules/civicrm/CRM/Queue/Page/Runner.php
Normal file
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
/*
|
||||
+--------------------------------------------------------------------+
|
||||
| CiviCRM version 4.7 |
|
||||
+--------------------------------------------------------------------+
|
||||
| Copyright CiviCRM LLC (c) 2004-2017 |
|
||||
+--------------------------------------------------------------------+
|
||||
| This file is a part of CiviCRM. |
|
||||
| |
|
||||
| CiviCRM is free software; you can copy, modify, and distribute it |
|
||||
| under the terms of the GNU Affero General Public License |
|
||||
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
|
||||
| |
|
||||
| CiviCRM is distributed in the hope that it will be useful, but |
|
||||
| WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|
||||
| See the GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| You should have received a copy of the GNU Affero General Public |
|
||||
| License and the CiviCRM Licensing Exception along |
|
||||
| with this program; if not, contact CiviCRM LLC |
|
||||
| at info[AT]civicrm[DOT]org. If you have questions about the |
|
||||
| GNU Affero General Public License or the licensing of CiviCRM, |
|
||||
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
|
||||
+--------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
|
||||
require_once 'CRM/Core/Page.php';
|
||||
|
||||
/**
|
||||
* The queue-runner page provides an interactive, web-based system
|
||||
* running the tasks in a queue and monitoring its progression.
|
||||
*
|
||||
* Do not link or redirect to this page directly -- go through
|
||||
* CRM_Queue_Runner::runAllViaWeb().
|
||||
*
|
||||
* Note: The queue runner only requires 'access CiviCRM' permission.
|
||||
* To ensure that malicious parties don't use this feature to
|
||||
* run queues on the wrong schedule, the queue-runner has an
|
||||
* extra authorization step: it checks for a session variable named
|
||||
* $_SESSION['queueRunners][$qrid]. This variable is properly setup
|
||||
* if you use the CRM_Queue_Runner::runAllViaWeb() interface.
|
||||
*/
|
||||
class CRM_Queue_Page_Runner extends CRM_Core_Page {
|
||||
|
||||
/**
|
||||
*
|
||||
* POST Param 'qrid': string, usually the name of the queue
|
||||
*/
|
||||
public function run() {
|
||||
$qrid = CRM_Utils_Request::retrieve('qrid', 'String', $this, TRUE);
|
||||
$runner = CRM_Queue_Runner::instance($qrid);
|
||||
if (!is_object($runner)) {
|
||||
CRM_Core_Error::fatal('Queue runner must be configured before execution.');
|
||||
}
|
||||
|
||||
CRM_Utils_System::setTitle($runner->title);
|
||||
$this->assign('queueRunnerData', array(
|
||||
'qrid' => $runner->qrid,
|
||||
'runNextAjax' => CRM_Utils_System::url($runner->pathPrefix . '/ajax/runNext', NULL, FALSE, NULL, FALSE),
|
||||
'skipNextAjax' => CRM_Utils_System::url($runner->pathPrefix . '/ajax/skipNext', NULL, FALSE, NULL, FALSE),
|
||||
'onEndAjax' => CRM_Utils_System::url($runner->pathPrefix . '/ajax/onEnd', NULL, FALSE, NULL, FALSE),
|
||||
'completed' => 0,
|
||||
'numberOfItems' => $runner->queue->numberOfItems(),
|
||||
'buttons' => $runner->buttons,
|
||||
));
|
||||
|
||||
if ($runner->isMinimal) {
|
||||
// Render page header
|
||||
if (!defined('CIVICRM_UF_HEAD') && $region = CRM_Core_Region::instance('html-header', FALSE)) {
|
||||
CRM_Utils_System::addHTMLHead($region->render(''));
|
||||
}
|
||||
$smarty = CRM_Core_Smarty::singleton();
|
||||
$content = $smarty->fetch('CRM/Queue/Page/Runner.tpl');
|
||||
echo CRM_Utils_System::theme($content, $this->_print, TRUE);
|
||||
}
|
||||
else {
|
||||
parent::run();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
149
sites/all/modules/civicrm/CRM/Queue/Queue.php
Normal file
149
sites/all/modules/civicrm/CRM/Queue/Queue.php
Normal file
|
@ -0,0 +1,149 @@
|
|||
<?php
|
||||
/*
|
||||
+--------------------------------------------------------------------+
|
||||
| CiviCRM version 4.7 |
|
||||
+--------------------------------------------------------------------+
|
||||
| Copyright CiviCRM LLC (c) 2004-2017 |
|
||||
+--------------------------------------------------------------------+
|
||||
| This file is a part of CiviCRM. |
|
||||
| |
|
||||
| CiviCRM is free software; you can copy, modify, and distribute it |
|
||||
| under the terms of the GNU Affero General Public License |
|
||||
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
|
||||
| |
|
||||
| CiviCRM is distributed in the hope that it will be useful, but |
|
||||
| WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|
||||
| See the GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| You should have received a copy of the GNU Affero General Public |
|
||||
| License and the CiviCRM Licensing Exception along |
|
||||
| with this program; if not, contact CiviCRM LLC |
|
||||
| at info[AT]civicrm[DOT]org. If you have questions about the |
|
||||
| GNU Affero General Public License or the licensing of CiviCRM, |
|
||||
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
|
||||
+--------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/**
|
||||
* A queue is an object (usually backed by some persistent data store)
|
||||
* which stores a list of tasks or messages for use by other processes.
|
||||
*
|
||||
* This would ideally be an interface, but it's handy to specify the
|
||||
* "function __construct()" and the "$name" handling
|
||||
*
|
||||
* Note: This interface closely parallels the DrupalQueueInterface.
|
||||
*/
|
||||
abstract class CRM_Queue_Queue {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $_name;
|
||||
|
||||
/**
|
||||
* Create a reference to queue. After constructing the queue, one should
|
||||
* usually call createQueue (if it's a new queue) or loadQueue (if it's
|
||||
* known to be an existing queue).
|
||||
*
|
||||
* @param array $queueSpec
|
||||
* Array with keys:
|
||||
* - type: string, required, e.g. "interactive", "immediate", "stomp",
|
||||
* "beanstalk"
|
||||
* - name: string, required, e.g. "upgrade-tasks"
|
||||
* - reset: bool, optional; if a queue is found, then it should be
|
||||
* flushed; default to TRUE
|
||||
* - (additional keys depending on the queue provider).
|
||||
*/
|
||||
public function __construct($queueSpec) {
|
||||
$this->_name = $queueSpec['name'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the string name of this queue.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName() {
|
||||
return $this->_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform any registation or resource-allocation for a new queue
|
||||
*/
|
||||
public abstract function createQueue();
|
||||
|
||||
/**
|
||||
* Perform any loading or pre-fetch for an existing queue.
|
||||
*/
|
||||
public abstract function loadQueue();
|
||||
|
||||
/**
|
||||
* Release any resources claimed by the queue (memory, DB rows, etc)
|
||||
*/
|
||||
public abstract function deleteQueue();
|
||||
|
||||
/**
|
||||
* Check if the queue exists.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public abstract function existsQueue();
|
||||
|
||||
/**
|
||||
* Add a new item to the queue.
|
||||
*
|
||||
* @param mixed $data
|
||||
* Serializable PHP object or array.
|
||||
* @param array $options
|
||||
* Queue-dependent options; for example, if this is a
|
||||
* priority-queue, then $options might specify the item's priority.
|
||||
*/
|
||||
public abstract function createItem($data, $options = array());
|
||||
|
||||
/**
|
||||
* Determine number of items remaining in the queue.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public abstract function numberOfItems();
|
||||
|
||||
/**
|
||||
* Get the next item.
|
||||
*
|
||||
* @param int $lease_time
|
||||
* Seconds.
|
||||
*
|
||||
* @return object
|
||||
* with key 'data' that matches the inputted data
|
||||
*/
|
||||
public abstract function claimItem($lease_time = 3600);
|
||||
|
||||
/**
|
||||
* Get the next item, even if there's an active lease
|
||||
*
|
||||
* @param int $lease_time
|
||||
* Seconds.
|
||||
*
|
||||
* @return object
|
||||
* with key 'data' that matches the inputted data
|
||||
*/
|
||||
public abstract function stealItem($lease_time = 3600);
|
||||
|
||||
/**
|
||||
* Remove an item from the queue.
|
||||
*
|
||||
* @param object $item
|
||||
* The item returned by claimItem.
|
||||
*/
|
||||
public abstract function deleteItem($item);
|
||||
|
||||
/**
|
||||
* Return an item that could not be processed.
|
||||
*
|
||||
* @param object $item
|
||||
* The item returned by claimItem.
|
||||
*/
|
||||
public abstract function releaseItem($item);
|
||||
|
||||
}
|
197
sites/all/modules/civicrm/CRM/Queue/Queue/Memory.php
Normal file
197
sites/all/modules/civicrm/CRM/Queue/Queue/Memory.php
Normal file
|
@ -0,0 +1,197 @@
|
|||
<?php
|
||||
/*
|
||||
+--------------------------------------------------------------------+
|
||||
| CiviCRM version 4.7 |
|
||||
+--------------------------------------------------------------------+
|
||||
| Copyright CiviCRM LLC (c) 2004-2017 |
|
||||
+--------------------------------------------------------------------+
|
||||
| This file is a part of CiviCRM. |
|
||||
| |
|
||||
| CiviCRM is free software; you can copy, modify, and distribute it |
|
||||
| under the terms of the GNU Affero General Public License |
|
||||
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
|
||||
| |
|
||||
| CiviCRM is distributed in the hope that it will be useful, but |
|
||||
| WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|
||||
| See the GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| You should have received a copy of the GNU Affero General Public |
|
||||
| License and the CiviCRM Licensing Exception along |
|
||||
| with this program; if not, contact CiviCRM LLC |
|
||||
| at info[AT]civicrm[DOT]org. If you have questions about the |
|
||||
| GNU Affero General Public License or the licensing of CiviCRM, |
|
||||
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
|
||||
+--------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/**
|
||||
* A queue implementation which stores items in the CiviCRM SQL database
|
||||
*/
|
||||
class CRM_Queue_Queue_Memory extends CRM_Queue_Queue {
|
||||
|
||||
/**
|
||||
* @var array
|
||||
* array(queueItemId => queueItemData)
|
||||
*/
|
||||
public $items;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
* array(queueItemId => releaseTime), expressed in seconds since epoch.
|
||||
*/
|
||||
public $releaseTimes;
|
||||
|
||||
public $nextQueueItemId = 1;
|
||||
|
||||
/**
|
||||
* Create a reference to queue. After constructing the queue, one should
|
||||
* usually call createQueue (if it's a new queue) or loadQueue (if it's
|
||||
* known to be an existing queue).
|
||||
*
|
||||
* @param array $queueSpec
|
||||
* Array with keys:
|
||||
* - type: string, required, e.g. "interactive", "immediate", "stomp",
|
||||
* "beanstalk"
|
||||
* - name: string, required, e.g. "upgrade-tasks"
|
||||
* - reset: bool, optional; if a queue is found, then it should be
|
||||
* flushed; default to TRUE
|
||||
* - (additional keys depending on the queue provider).
|
||||
*/
|
||||
public function __construct($queueSpec) {
|
||||
parent::__construct($queueSpec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform any registation or resource-allocation for a new queue
|
||||
*/
|
||||
public function createQueue() {
|
||||
$this->items = array();
|
||||
$this->releaseTimes = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform any loading or pre-fetch for an existing queue.
|
||||
*/
|
||||
public function loadQueue() {
|
||||
// $this->createQueue();
|
||||
throw new Exception('Unsupported: CRM_Queue_Queue_Memory::loadQueue');
|
||||
}
|
||||
|
||||
/**
|
||||
* Release any resources claimed by the queue (memory, DB rows, etc)
|
||||
*/
|
||||
public function deleteQueue() {
|
||||
$this->items = NULL;
|
||||
$this->releaseTimes = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the queue exists.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function existsQueue() {
|
||||
return is_array($this->items);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new item to the queue.
|
||||
*
|
||||
* @param mixed $data
|
||||
* Serializable PHP object or array.
|
||||
* @param array $options
|
||||
* Queue-dependent options; for example, if this is a
|
||||
* priority-queue, then $options might specify the item's priority.
|
||||
*/
|
||||
public function createItem($data, $options = array()) {
|
||||
$id = $this->nextQueueItemId++;
|
||||
// force copy, no unintendedsharing effects from pointers
|
||||
$this->items[$id] = serialize($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine number of items remaining in the queue.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function numberOfItems() {
|
||||
return count($this->items);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get and remove the next item.
|
||||
*
|
||||
* @param int $leaseTime
|
||||
* Seconds.
|
||||
*
|
||||
* @return object
|
||||
* Includes key 'data' that matches the inputted data.
|
||||
*/
|
||||
public function claimItem($leaseTime = 3600) {
|
||||
// foreach hits the items in order -- but we short-circuit after the first
|
||||
foreach ($this->items as $id => $data) {
|
||||
$nowEpoch = CRM_Utils_Time::getTimeRaw();
|
||||
if (empty($this->releaseTimes[$id]) || $this->releaseTimes[$id] < $nowEpoch) {
|
||||
$this->releaseTimes[$id] = $nowEpoch + $leaseTime;
|
||||
|
||||
$item = new stdClass();
|
||||
$item->id = $id;
|
||||
$item->data = unserialize($data);
|
||||
return $item;
|
||||
}
|
||||
else {
|
||||
// item in queue is reserved
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
// nothing in queue
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next item.
|
||||
*
|
||||
* @param int $leaseTime
|
||||
* Seconds.
|
||||
*
|
||||
* @return object
|
||||
* With key 'data' that matches the inputted data.
|
||||
*/
|
||||
public function stealItem($leaseTime = 3600) {
|
||||
// foreach hits the items in order -- but we short-circuit after the first
|
||||
foreach ($this->items as $id => $data) {
|
||||
$nowEpoch = CRM_Utils_Time::getTimeRaw();
|
||||
$this->releaseTimes[$id] = $nowEpoch + $leaseTime;
|
||||
|
||||
$item = new stdClass();
|
||||
$item->id = $id;
|
||||
$item->data = unserialize($data);
|
||||
return $item;
|
||||
}
|
||||
// nothing in queue
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an item from the queue.
|
||||
*
|
||||
* @param object $item
|
||||
* The item returned by claimItem.
|
||||
*/
|
||||
public function deleteItem($item) {
|
||||
unset($this->items[$item->id]);
|
||||
unset($this->releaseTimes[$item->id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an item that could not be processed.
|
||||
*
|
||||
* @param CRM_Core_DAO $item
|
||||
* The item returned by claimItem.
|
||||
*/
|
||||
public function releaseItem($item) {
|
||||
unset($this->releaseTimes[$item->id]);
|
||||
}
|
||||
|
||||
}
|
220
sites/all/modules/civicrm/CRM/Queue/Queue/Sql.php
Normal file
220
sites/all/modules/civicrm/CRM/Queue/Queue/Sql.php
Normal file
|
@ -0,0 +1,220 @@
|
|||
<?php
|
||||
/*
|
||||
+--------------------------------------------------------------------+
|
||||
| CiviCRM version 4.7 |
|
||||
+--------------------------------------------------------------------+
|
||||
| Copyright CiviCRM LLC (c) 2004-2017 |
|
||||
+--------------------------------------------------------------------+
|
||||
| This file is a part of CiviCRM. |
|
||||
| |
|
||||
| CiviCRM is free software; you can copy, modify, and distribute it |
|
||||
| under the terms of the GNU Affero General Public License |
|
||||
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
|
||||
| |
|
||||
| CiviCRM is distributed in the hope that it will be useful, but |
|
||||
| WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|
||||
| See the GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| You should have received a copy of the GNU Affero General Public |
|
||||
| License and the CiviCRM Licensing Exception along |
|
||||
| with this program; if not, contact CiviCRM LLC |
|
||||
| at info[AT]civicrm[DOT]org. If you have questions about the |
|
||||
| GNU Affero General Public License or the licensing of CiviCRM, |
|
||||
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
|
||||
+--------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/**
|
||||
* A queue implementation which stores items in the CiviCRM SQL database
|
||||
*/
|
||||
class CRM_Queue_Queue_Sql extends CRM_Queue_Queue {
|
||||
|
||||
/**
|
||||
* Create a reference to queue. After constructing the queue, one should
|
||||
* usually call createQueue (if it's a new queue) or loadQueue (if it's
|
||||
* known to be an existing queue).
|
||||
*
|
||||
* @param array $queueSpec
|
||||
* Array with keys:
|
||||
* - type: string, required, e.g. "interactive", "immediate", "stomp",
|
||||
* "beanstalk"
|
||||
* - name: string, required, e.g. "upgrade-tasks"
|
||||
* - reset: bool, optional; if a queue is found, then it should be
|
||||
* flushed; default to TRUE
|
||||
* - (additional keys depending on the queue provider).
|
||||
*/
|
||||
public function __construct($queueSpec) {
|
||||
parent::__construct($queueSpec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform any registation or resource-allocation for a new queue
|
||||
*/
|
||||
public function createQueue() {
|
||||
// nothing to do -- just start CRUDing items in the appropriate table
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform any loading or pre-fetch for an existing queue.
|
||||
*/
|
||||
public function loadQueue() {
|
||||
// nothing to do -- just start CRUDing items in the appropriate table
|
||||
}
|
||||
|
||||
/**
|
||||
* Release any resources claimed by the queue (memory, DB rows, etc)
|
||||
*/
|
||||
public function deleteQueue() {
|
||||
return CRM_Core_DAO::singleValueQuery("
|
||||
DELETE FROM civicrm_queue_item
|
||||
WHERE queue_name = %1
|
||||
", array(
|
||||
1 => array($this->getName(), 'String'),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the queue exists.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function existsQueue() {
|
||||
return ($this->numberOfItems() > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new item to the queue.
|
||||
*
|
||||
* @param mixed $data
|
||||
* Serializable PHP object or array.
|
||||
* @param array $options
|
||||
* Queue-dependent options; for example, if this is a
|
||||
* priority-queue, then $options might specify the item's priority.
|
||||
*/
|
||||
public function createItem($data, $options = array()) {
|
||||
$dao = new CRM_Queue_DAO_QueueItem();
|
||||
$dao->queue_name = $this->getName();
|
||||
$dao->submit_time = CRM_Utils_Time::getTime('YmdHis');
|
||||
$dao->data = serialize($data);
|
||||
$dao->weight = CRM_Utils_Array::value('weight', $options, 0);
|
||||
$dao->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine number of items remaining in the queue.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function numberOfItems() {
|
||||
return CRM_Core_DAO::singleValueQuery("
|
||||
SELECT count(*)
|
||||
FROM civicrm_queue_item
|
||||
WHERE queue_name = %1
|
||||
", array(
|
||||
1 => array($this->getName(), 'String'),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next item.
|
||||
*
|
||||
* @param int $lease_time
|
||||
* Seconds.
|
||||
*
|
||||
* @return object
|
||||
* With key 'data' that matches the inputted data.
|
||||
*/
|
||||
public function claimItem($lease_time = 3600) {
|
||||
$sql = "
|
||||
SELECT id, queue_name, submit_time, release_time, data
|
||||
FROM civicrm_queue_item
|
||||
WHERE queue_name = %1
|
||||
ORDER BY weight ASC, id ASC
|
||||
LIMIT 1
|
||||
";
|
||||
$params = array(
|
||||
1 => array($this->getName(), 'String'),
|
||||
);
|
||||
$dao = CRM_Core_DAO::executeQuery($sql, $params, TRUE, 'CRM_Queue_DAO_QueueItem');
|
||||
if (is_a($dao, 'DB_Error')) {
|
||||
// FIXME - Adding code to allow tests to pass
|
||||
CRM_Core_Error::fatal();
|
||||
}
|
||||
|
||||
if ($dao->fetch()) {
|
||||
$nowEpoch = CRM_Utils_Time::getTimeRaw();
|
||||
if ($dao->release_time === NULL || strtotime($dao->release_time) < $nowEpoch) {
|
||||
CRM_Core_DAO::executeQuery("UPDATE civicrm_queue_item SET release_time = %1 WHERE id = %2", array(
|
||||
'1' => array(date('YmdHis', $nowEpoch + $lease_time), 'String'),
|
||||
'2' => array($dao->id, 'Integer'),
|
||||
));
|
||||
// work-around: inconsistent date-formatting causes unintentional breakage
|
||||
# $dao->submit_time = date('YmdHis', strtotime($dao->submit_time));
|
||||
# $dao->release_time = date('YmdHis', $nowEpoch + $lease_time);
|
||||
# $dao->save();
|
||||
$dao->data = unserialize($dao->data);
|
||||
return $dao;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next item, even if there's an active lease
|
||||
*
|
||||
* @param int $lease_time
|
||||
* Seconds.
|
||||
*
|
||||
* @return object
|
||||
* With key 'data' that matches the inputted data.
|
||||
*/
|
||||
public function stealItem($lease_time = 3600) {
|
||||
$sql = "
|
||||
SELECT id, queue_name, submit_time, release_time, data
|
||||
FROM civicrm_queue_item
|
||||
WHERE queue_name = %1
|
||||
ORDER BY weight ASC, id ASC
|
||||
LIMIT 1
|
||||
";
|
||||
$params = array(
|
||||
1 => array($this->getName(), 'String'),
|
||||
);
|
||||
$dao = CRM_Core_DAO::executeQuery($sql, $params, TRUE, 'CRM_Queue_DAO_QueueItem');
|
||||
if ($dao->fetch()) {
|
||||
$nowEpoch = CRM_Utils_Time::getTimeRaw();
|
||||
CRM_Core_DAO::executeQuery("UPDATE civicrm_queue_item SET release_time = %1 WHERE id = %2", array(
|
||||
'1' => array(date('YmdHis', $nowEpoch + $lease_time), 'String'),
|
||||
'2' => array($dao->id, 'Integer'),
|
||||
));
|
||||
$dao->data = unserialize($dao->data);
|
||||
return $dao;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an item from the queue.
|
||||
*
|
||||
* @param CRM_Core_DAO $dao
|
||||
* The item returned by claimItem.
|
||||
*/
|
||||
public function deleteItem($dao) {
|
||||
$dao->delete();
|
||||
$dao->free();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an item that could not be processed.
|
||||
*
|
||||
* @param CRM_Core_DAO $dao
|
||||
* The item returned by claimItem.
|
||||
*/
|
||||
public function releaseItem($dao) {
|
||||
$sql = "UPDATE civicrm_queue_item SET release_time = NULL WHERE id = %1";
|
||||
$params = array(
|
||||
1 => array($dao->id, 'Integer'),
|
||||
);
|
||||
CRM_Core_DAO::executeQuery($sql, $params);
|
||||
$dao->free();
|
||||
}
|
||||
|
||||
}
|
365
sites/all/modules/civicrm/CRM/Queue/Runner.php
Normal file
365
sites/all/modules/civicrm/CRM/Queue/Runner.php
Normal file
|
@ -0,0 +1,365 @@
|
|||
<?php
|
||||
/*
|
||||
+--------------------------------------------------------------------+
|
||||
| CiviCRM version 4.7 |
|
||||
+--------------------------------------------------------------------+
|
||||
| Copyright CiviCRM LLC (c) 2004-2017 |
|
||||
+--------------------------------------------------------------------+
|
||||
| This file is a part of CiviCRM. |
|
||||
| |
|
||||
| CiviCRM is free software; you can copy, modify, and distribute it |
|
||||
| under the terms of the GNU Affero General Public License |
|
||||
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
|
||||
| |
|
||||
| CiviCRM is distributed in the hope that it will be useful, but |
|
||||
| WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|
||||
| See the GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| You should have received a copy of the GNU Affero General Public |
|
||||
| License and the CiviCRM Licensing Exception along |
|
||||
| with this program; if not, contact CiviCRM LLC |
|
||||
| at info[AT]civicrm[DOT]org. If you have questions about the |
|
||||
| GNU Affero General Public License or the licensing of CiviCRM, |
|
||||
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
|
||||
+--------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/**
|
||||
* The queue runner is a helper which runs all jobs in a queue.
|
||||
*
|
||||
* The queue runner is most useful for one-off queues (such as an upgrade);
|
||||
* if the intention is to develop a dedicated, long-running worker thread,
|
||||
* then one should consider writing a new queue consumer.
|
||||
*/
|
||||
class CRM_Queue_Runner {
|
||||
|
||||
/**
|
||||
* The failed task should be discarded, and queue processing should continue.
|
||||
*/
|
||||
const ERROR_CONTINUE = 1;
|
||||
|
||||
/**
|
||||
* The failed task should be kept in the queue, and queue processing should
|
||||
* abort.
|
||||
*/
|
||||
const ERROR_ABORT = 2;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $title;
|
||||
|
||||
/**
|
||||
* @var CRM_Queue_Queue
|
||||
*/
|
||||
public $queue;
|
||||
public $errorMode;
|
||||
public $isMinimal;
|
||||
public $onEnd;
|
||||
public $onEndUrl;
|
||||
public $pathPrefix;
|
||||
// queue-runner id; used for persistence
|
||||
public $qrid;
|
||||
|
||||
/**
|
||||
* @var array whether to display buttons, eg ('retry' => TRUE, 'skip' => FALSE)
|
||||
*/
|
||||
public $buttons;
|
||||
|
||||
/**
|
||||
* @var CRM_Queue_TaskContext
|
||||
*/
|
||||
public $taskCtx;
|
||||
|
||||
/**
|
||||
* Locate a previously-created instance of the queue-runner.
|
||||
*
|
||||
* @param string $qrid
|
||||
* The queue-runner ID.
|
||||
*
|
||||
* @return CRM_Queue_Runner|NULL
|
||||
*/
|
||||
public static function instance($qrid) {
|
||||
if (!empty($_SESSION['queueRunners'][$qrid])) {
|
||||
return unserialize($_SESSION['queueRunners'][$qrid]);
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* FIXME: parameter validation
|
||||
* FIXME: document signature of onEnd callback
|
||||
*
|
||||
* @param array $runnerSpec
|
||||
* Array with keys:
|
||||
* - queue: CRM_Queue_Queue
|
||||
* - errorMode: int, ERROR_CONTINUE or ERROR_ABORT.
|
||||
* - onEnd: mixed, a callback to update the UI after running; should be
|
||||
* both callable and serializable.
|
||||
* - onEndUrl: string, the URL to which one redirects.
|
||||
* - pathPrefix: string, prepended to URLs for the web-runner;
|
||||
* default: 'civicrm/queue'.
|
||||
*/
|
||||
public function __construct($runnerSpec) {
|
||||
$this->title = CRM_Utils_Array::value('title', $runnerSpec, ts('Queue Runner'));
|
||||
$this->queue = $runnerSpec['queue'];
|
||||
$this->errorMode = CRM_Utils_Array::value('errorMode', $runnerSpec, self::ERROR_ABORT);
|
||||
$this->isMinimal = CRM_Utils_Array::value('isMinimal', $runnerSpec, FALSE);
|
||||
$this->onEnd = CRM_Utils_Array::value('onEnd', $runnerSpec, NULL);
|
||||
$this->onEndUrl = CRM_Utils_Array::value('onEndUrl', $runnerSpec, NULL);
|
||||
$this->pathPrefix = CRM_Utils_Array::value('pathPrefix', $runnerSpec, 'civicrm/queue');
|
||||
$this->buttons = CRM_Utils_Array::value('buttons', $runnerSpec, array('retry' => TRUE, 'skip' => TRUE));
|
||||
// perhaps this value should be randomized?
|
||||
$this->qrid = $this->queue->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function __sleep() {
|
||||
// exclude taskCtx
|
||||
return array(
|
||||
'title',
|
||||
'queue',
|
||||
'errorMode',
|
||||
'isMinimal',
|
||||
'onEnd',
|
||||
'onEndUrl',
|
||||
'pathPrefix',
|
||||
'qrid',
|
||||
'buttons',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to the web-based queue-runner and evaluate all tasks in a queue.
|
||||
*/
|
||||
public function runAllViaWeb() {
|
||||
$_SESSION['queueRunners'][$this->qrid] = serialize($this);
|
||||
$url = CRM_Utils_System::url($this->pathPrefix . '/runner', 'reset=1&qrid=' . urlencode($this->qrid));
|
||||
CRM_Utils_System::redirect($url);
|
||||
// TODO: evaluate items incrementally via AJAX polling, cleanup session
|
||||
}
|
||||
|
||||
/**
|
||||
* Immediately run all tasks in a queue (until either reaching the end
|
||||
* of the queue or encountering an error)
|
||||
*
|
||||
* If the runner has an onEndUrl, then this function will not return
|
||||
*
|
||||
* @return mixed
|
||||
* TRUE if all tasks complete normally; otherwise, an array describing the
|
||||
* failed task
|
||||
*/
|
||||
public function runAll() {
|
||||
$taskResult = $this->formatTaskResult(TRUE);
|
||||
while ($taskResult['is_continue']) {
|
||||
// setRaiseException should't be necessary here, but there's a bug
|
||||
// somewhere which causes this setting to be lost. Observed while
|
||||
// upgrading 4.0=>4.2. This preference really shouldn't be a global
|
||||
// setting -- it should be more of a contextual/stack-based setting.
|
||||
// This should be appropriate because queue-runners are not used with
|
||||
// basic web pages -- they're used with CLI/REST/AJAX.
|
||||
$errorScope = CRM_Core_TemporaryErrorScope::useException();
|
||||
$taskResult = $this->runNext();
|
||||
$errorScope = NULL;
|
||||
}
|
||||
|
||||
if ($taskResult['numberOfItems'] == 0) {
|
||||
$result = $this->handleEnd();
|
||||
if (!empty($result['redirect_url'])) {
|
||||
CRM_Utils_System::redirect($result['redirect_url']);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
else {
|
||||
return $taskResult;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Take the next item from the queue and attempt to run it.
|
||||
*
|
||||
* Individual tasks may also throw exceptions -- caller should watch for
|
||||
* exceptions.
|
||||
*
|
||||
* @param bool $useSteal
|
||||
* Whether to steal active locks.
|
||||
*
|
||||
* @return array
|
||||
* - is_error => bool,
|
||||
* - is_continue => bool,
|
||||
* - numberOfItems => int,
|
||||
* - 'last_task_title' => $,
|
||||
* - 'exception' => $
|
||||
*/
|
||||
public function runNext($useSteal = FALSE) {
|
||||
if ($useSteal) {
|
||||
$item = $this->queue->stealItem();
|
||||
}
|
||||
else {
|
||||
$item = $this->queue->claimItem();
|
||||
}
|
||||
|
||||
if ($item) {
|
||||
$this->lastTaskTitle = $item->data->title;
|
||||
|
||||
$exception = NULL;
|
||||
try {
|
||||
CRM_Core_Error::debug_log_message("Running task: " . $this->lastTaskTitle);
|
||||
$isOK = $item->data->run($this->getTaskContext());
|
||||
if (!$isOK) {
|
||||
$exception = new Exception('Task returned false');
|
||||
}
|
||||
}
|
||||
catch (Exception$e) {
|
||||
$isOK = FALSE;
|
||||
$exception = $e;
|
||||
}
|
||||
|
||||
if ($isOK) {
|
||||
$this->queue->deleteItem($item);
|
||||
}
|
||||
else {
|
||||
$this->releaseErrorItem($item);
|
||||
}
|
||||
|
||||
return $this->formatTaskResult($isOK, $exception);
|
||||
}
|
||||
else {
|
||||
return $this->formatTaskResult(FALSE, new Exception('Failed to claim next task'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Take the next item from the queue and attempt to run it.
|
||||
*
|
||||
* Individual tasks may also throw exceptions -- caller should watch for
|
||||
* exceptions.
|
||||
*
|
||||
* @param bool $useSteal
|
||||
* Whether to steal active locks.
|
||||
*
|
||||
* @return array
|
||||
* - is_error => bool,
|
||||
* - is_continue => bool,
|
||||
* - numberOfItems => int)
|
||||
*/
|
||||
public function skipNext($useSteal = FALSE) {
|
||||
if ($useSteal) {
|
||||
$item = $this->queue->stealItem();
|
||||
}
|
||||
else {
|
||||
$item = $this->queue->claimItem();
|
||||
}
|
||||
|
||||
if ($item) {
|
||||
$this->lastTaskTitle = $item->data->title;
|
||||
$this->queue->deleteItem($item);
|
||||
return $this->formatTaskResult(TRUE);
|
||||
}
|
||||
else {
|
||||
return $this->formatTaskResult(FALSE, new Exception('Failed to claim next task'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Release an item in keeping with the error mode.
|
||||
*
|
||||
* @param object $item
|
||||
* The item previously produced by Queue::claimItem.
|
||||
*/
|
||||
protected function releaseErrorItem($item) {
|
||||
switch ($this->errorMode) {
|
||||
case self::ERROR_CONTINUE:
|
||||
$this->queue->deleteItem($item);
|
||||
case self::ERROR_ABORT:
|
||||
default:
|
||||
$this->queue->releaseItem($item);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* - is_error => bool,
|
||||
* - is_continue => bool,
|
||||
* - numberOfItems => int,
|
||||
* - redirect_url => string
|
||||
*/
|
||||
public function handleEnd() {
|
||||
if (is_callable($this->onEnd)) {
|
||||
call_user_func($this->onEnd, $this->getTaskContext());
|
||||
}
|
||||
// Don't remove queueRunner until onEnd succeeds
|
||||
if (!empty($_SESSION['queueRunners'][$this->qrid])) {
|
||||
unset($_SESSION['queueRunners'][$this->qrid]);
|
||||
}
|
||||
|
||||
// Fallback; web UI does redirect in Javascript
|
||||
$result = array();
|
||||
$result['is_error'] = 0;
|
||||
$result['numberOfItems'] = 0;
|
||||
$result['is_continue'] = 0;
|
||||
if (!empty($this->onEndUrl)) {
|
||||
$result['redirect_url'] = $this->onEndUrl;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a result record which describes whether the task completed.
|
||||
*
|
||||
* @param bool $isOK
|
||||
* TRUE if the task completed successfully.
|
||||
* @param Exception|NULL $exception
|
||||
* If applicable, an unhandled exception that arose during execution.
|
||||
*
|
||||
* @return array
|
||||
* (is_error => bool, is_continue => bool, numberOfItems => int)
|
||||
*/
|
||||
public function formatTaskResult($isOK, $exception = NULL) {
|
||||
$numberOfItems = $this->queue->numberOfItems();
|
||||
|
||||
$result = array();
|
||||
$result['is_error'] = $isOK ? 0 : 1;
|
||||
$result['exception'] = $exception;
|
||||
$result['last_task_title'] = isset($this->lastTaskTitle) ? $this->lastTaskTitle : '';
|
||||
$result['numberOfItems'] = $this->queue->numberOfItems();
|
||||
if ($result['numberOfItems'] <= 0) {
|
||||
// nothing to do
|
||||
$result['is_continue'] = 0;
|
||||
}
|
||||
elseif ($isOK) {
|
||||
// more tasks remain, and this task succeeded
|
||||
$result['is_continue'] = 1;
|
||||
}
|
||||
elseif ($this->errorMode == CRM_Queue_Runner::ERROR_CONTINUE) {
|
||||
// more tasks remain, and we can disregard this error
|
||||
$result['is_continue'] = 1;
|
||||
}
|
||||
else {
|
||||
// more tasks remain, but we can't disregard the error
|
||||
$result['is_continue'] = 0;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return CRM_Queue_TaskContext
|
||||
*/
|
||||
protected function getTaskContext() {
|
||||
if (!is_object($this->taskCtx)) {
|
||||
$this->taskCtx = new CRM_Queue_TaskContext();
|
||||
$this->taskCtx->queue = $this->queue;
|
||||
// $this->taskCtx->log = CRM_Core_Config::getLog();
|
||||
$this->taskCtx->log = CRM_Core_Error::createDebugLogger();
|
||||
}
|
||||
return $this->taskCtx;
|
||||
}
|
||||
|
||||
}
|
172
sites/all/modules/civicrm/CRM/Queue/Service.php
Normal file
172
sites/all/modules/civicrm/CRM/Queue/Service.php
Normal file
|
@ -0,0 +1,172 @@
|
|||
<?php
|
||||
/*
|
||||
+--------------------------------------------------------------------+
|
||||
| CiviCRM version 4.7 |
|
||||
+--------------------------------------------------------------------+
|
||||
| Copyright CiviCRM LLC (c) 2004-2017 |
|
||||
+--------------------------------------------------------------------+
|
||||
| This file is a part of CiviCRM. |
|
||||
| |
|
||||
| CiviCRM is free software; you can copy, modify, and distribute it |
|
||||
| under the terms of the GNU Affero General Public License |
|
||||
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
|
||||
| |
|
||||
| CiviCRM is distributed in the hope that it will be useful, but |
|
||||
| WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|
||||
| See the GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| You should have received a copy of the GNU Affero General Public |
|
||||
| License and the CiviCRM Licensing Exception along |
|
||||
| with this program; if not, contact CiviCRM LLC |
|
||||
| at info[AT]civicrm[DOT]org. If you have questions about the |
|
||||
| GNU Affero General Public License or the licensing of CiviCRM, |
|
||||
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
|
||||
+--------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/**
|
||||
* The queue service provides an interface for creating or locating
|
||||
* queues. Note that this approach hides the details of data-storage:
|
||||
* different queue-providers may store the queue content in different
|
||||
* ways (in memory, in SQL, or in an external service).
|
||||
*
|
||||
* @code
|
||||
* $queue = CRM_Queue_Service::singleton()->create(array(
|
||||
* 'type' => 'interactive',
|
||||
* 'name' => 'upgrade-tasks',
|
||||
* ));
|
||||
* $queue->createItem($myData);
|
||||
*
|
||||
* // Some time later...
|
||||
* $item = $queue->claimItem();
|
||||
* if ($item) {
|
||||
* if (my_process($item->data)) {
|
||||
* $queue->deleteItem($item);
|
||||
* } else {
|
||||
* $queue->releaseItem($item);
|
||||
* }
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
class CRM_Queue_Service {
|
||||
|
||||
protected static $_singleton;
|
||||
|
||||
/**
|
||||
* FIXME: Singleton pattern should be removed when dependency-injection
|
||||
* becomes available.
|
||||
*
|
||||
* @param bool $forceNew
|
||||
* TRUE if a new instance must be created.
|
||||
*
|
||||
* @return \CRM_Queue_Service
|
||||
*/
|
||||
public static function &singleton($forceNew = FALSE) {
|
||||
if ($forceNew || !self::$_singleton) {
|
||||
self::$_singleton = new CRM_Queue_Service();
|
||||
}
|
||||
return self::$_singleton;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var array (string $queueName => CRM_Queue_Queue)
|
||||
*/
|
||||
public $queues;
|
||||
|
||||
/**
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->queues = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a queue. If one already exists, then it will be reused.
|
||||
*
|
||||
* @param array $queueSpec
|
||||
* Array with keys:
|
||||
* - type: string, required, e.g. "interactive", "immediate", "stomp",
|
||||
* "beanstalk"
|
||||
* - name: string, required, e.g. "upgrade-tasks"
|
||||
* - reset: bool, optional; if a queue is found, then it should be
|
||||
* flushed; default to TRUE
|
||||
* - (additional keys depending on the queue provider).
|
||||
*
|
||||
* @return CRM_Queue_Queue
|
||||
*/
|
||||
public function create($queueSpec) {
|
||||
if (@is_object($this->queues[$queueSpec['name']]) && empty($queueSpec['reset'])) {
|
||||
return $this->queues[$queueSpec['name']];
|
||||
}
|
||||
|
||||
$queue = $this->instantiateQueueObject($queueSpec);
|
||||
$exists = $queue->existsQueue();
|
||||
if (!$exists) {
|
||||
$queue->createQueue();
|
||||
}
|
||||
elseif (@$queueSpec['reset']) {
|
||||
$queue->deleteQueue();
|
||||
$queue->createQueue();
|
||||
}
|
||||
else {
|
||||
$queue->loadQueue();
|
||||
}
|
||||
$this->queues[$queueSpec['name']] = $queue;
|
||||
return $queue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up an existing queue.
|
||||
*
|
||||
* @param array $queueSpec
|
||||
* Array with keys:
|
||||
* - type: string, required, e.g. "interactive", "immediate", "stomp",
|
||||
* "beanstalk"
|
||||
* - name: string, required, e.g. "upgrade-tasks"
|
||||
* - (additional keys depending on the queue provider).
|
||||
*
|
||||
* @return CRM_Queue_Queue
|
||||
*/
|
||||
public function load($queueSpec) {
|
||||
if (is_object($this->queues[$queueSpec['name']])) {
|
||||
return $this->queues[$queueSpec['name']];
|
||||
}
|
||||
$queue = $this->instantiateQueueObject($queueSpec);
|
||||
$queue->loadQueue();
|
||||
$this->queues[$queueSpec['name']] = $queue;
|
||||
return $queue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a queue "type" name to a class name.
|
||||
*
|
||||
* @param string $type
|
||||
* E.g. "interactive", "immediate", "stomp", "beanstalk".
|
||||
*
|
||||
* @return string
|
||||
* Class-name
|
||||
*/
|
||||
protected function getQueueClass($type) {
|
||||
$type = preg_replace('/[^a-zA-Z0-9]/', '', $type);
|
||||
$className = 'CRM_Queue_Queue_' . $type;
|
||||
// FIXME: when used with class-autoloader, this may be unnecessary
|
||||
if (!class_exists($className)) {
|
||||
$classFile = 'CRM/Queue/Queue/' . $type . '.php';
|
||||
require_once $classFile;
|
||||
}
|
||||
return $className;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $queueSpec
|
||||
* See create().
|
||||
*
|
||||
* @return CRM_Queue_Queue
|
||||
*/
|
||||
protected function instantiateQueueObject($queueSpec) {
|
||||
// note: you should probably never do anything else here
|
||||
$class = new ReflectionClass($this->getQueueClass($queueSpec['type']));
|
||||
return $class->newInstance($queueSpec);
|
||||
}
|
||||
|
||||
}
|
96
sites/all/modules/civicrm/CRM/Queue/Task.php
Normal file
96
sites/all/modules/civicrm/CRM/Queue/Task.php
Normal file
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
/*
|
||||
+--------------------------------------------------------------------+
|
||||
| CiviCRM version 4.7 |
|
||||
+--------------------------------------------------------------------+
|
||||
| Copyright CiviCRM LLC (c) 2004-2017 |
|
||||
+--------------------------------------------------------------------+
|
||||
| This file is a part of CiviCRM. |
|
||||
| |
|
||||
| CiviCRM is free software; you can copy, modify, and distribute it |
|
||||
| under the terms of the GNU Affero General Public License |
|
||||
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
|
||||
| |
|
||||
| CiviCRM is distributed in the hope that it will be useful, but |
|
||||
| WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|
||||
| See the GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| You should have received a copy of the GNU Affero General Public |
|
||||
| License and the CiviCRM Licensing Exception along |
|
||||
| with this program; if not, contact CiviCRM LLC |
|
||||
| at info[AT]civicrm[DOT]org. If you have questions about the |
|
||||
| GNU Affero General Public License or the licensing of CiviCRM, |
|
||||
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
|
||||
+--------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/**
|
||||
* A task is an item that can be enqueued and later executed
|
||||
*/
|
||||
class CRM_Queue_Task {
|
||||
|
||||
/**
|
||||
* Task was performed successfully.
|
||||
*/
|
||||
const TASK_SUCCESS = 1;
|
||||
|
||||
/**
|
||||
* Task failed and should not be retried.
|
||||
*/
|
||||
const TASK_FAIL = 2;
|
||||
|
||||
/**
|
||||
* @var mixed, serializable
|
||||
*/
|
||||
public $callback;
|
||||
|
||||
/**
|
||||
* @var array, serializable
|
||||
*/
|
||||
public $arguments;
|
||||
|
||||
/**
|
||||
* @var string, NULL-able
|
||||
*/
|
||||
public $title;
|
||||
|
||||
/**
|
||||
* @param mixed $callback
|
||||
* Serializable, a callable PHP item; must accept at least one argument
|
||||
* (CRM_Queue_TaskContext).
|
||||
* @param array $arguments
|
||||
* Serializable, extra arguments to pass to the callback (in order).
|
||||
* @param string $title
|
||||
* A printable string which describes this task.
|
||||
*/
|
||||
public function __construct($callback, $arguments, $title = NULL) {
|
||||
$this->callback = $callback;
|
||||
$this->arguments = $arguments;
|
||||
$this->title = $title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the task.
|
||||
*
|
||||
* @param array $taskCtx
|
||||
* Array with keys:
|
||||
* - log: object 'Log'
|
||||
*
|
||||
* @throws Exception
|
||||
* @return bool, TRUE if task completes successfully
|
||||
*/
|
||||
public function run($taskCtx) {
|
||||
$args = $this->arguments;
|
||||
array_unshift($args, $taskCtx);
|
||||
|
||||
if (is_callable($this->callback)) {
|
||||
$result = call_user_func_array($this->callback, $args);
|
||||
return $result;
|
||||
}
|
||||
else {
|
||||
throw new Exception('Failed to call callback: ' . print_r($this->callback));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
43
sites/all/modules/civicrm/CRM/Queue/TaskContext.php
Normal file
43
sites/all/modules/civicrm/CRM/Queue/TaskContext.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
/*
|
||||
+--------------------------------------------------------------------+
|
||||
| CiviCRM version 4.7 |
|
||||
+--------------------------------------------------------------------+
|
||||
| Copyright CiviCRM LLC (c) 2004-2017 |
|
||||
+--------------------------------------------------------------------+
|
||||
| This file is a part of CiviCRM. |
|
||||
| |
|
||||
| CiviCRM is free software; you can copy, modify, and distribute it |
|
||||
| under the terms of the GNU Affero General Public License |
|
||||
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
|
||||
| |
|
||||
| CiviCRM is distributed in the hope that it will be useful, but |
|
||||
| WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|
||||
| See the GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| You should have received a copy of the GNU Affero General Public |
|
||||
| License and the CiviCRM Licensing Exception along |
|
||||
| with this program; if not, contact CiviCRM LLC |
|
||||
| at info[AT]civicrm[DOT]org. If you have questions about the |
|
||||
| GNU Affero General Public License or the licensing of CiviCRM, |
|
||||
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
|
||||
+--------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/**
|
||||
* Describe the runtime environment in which a queue task executes
|
||||
*/
|
||||
class CRM_Queue_TaskContext {
|
||||
|
||||
/**
|
||||
* @var CRM_Queue_Queue
|
||||
*/
|
||||
public $queue;
|
||||
|
||||
/**
|
||||
* @var Log
|
||||
*/
|
||||
public $log;
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue