2
0
mirror of https://github.com/ACSPRI/queXS synced 2024-04-02 12:12:16 +00:00

Added a "system sort" process which sorts cases and the sample file from enabled questionnaires periodically (based on SYSTEM_SORT_MINUTES config directive). Enabling this may improve performance where there is a large number of interviewers, a large sample or complex quotas as the sort doesn't need to be done for each interviewer at each case.

Allow for multiple background processes to run concurrently
This commit is contained in:
azammitdcarf
2011-02-01 05:27:55 +00:00
parent 5eb15f0450
commit 1ffb93df13
7 changed files with 428 additions and 82 deletions

194
admin/systemsortprocess.php Normal file
View File

@@ -0,0 +1,194 @@
<?
/**
* Run the system wide case sorting process
*
*
* This file is part of queXS
*
* queXS is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* queXS 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with queXS; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*
* @author Adam Zammit <adam.zammit@acspri.org.au>
* @copyright Australian Consortium for Social and Political Research Incorporated (ACSPRI) 2011
* @package queXS
* @subpackage admin
* @link http://www.acspri.org.au/ queXS was written for ACSPRI
* @license http://opensource.org/licenses/gpl-2.0.php The GNU General Public License (GPL) Version 2
*
*/
/**
* Configuration file
*/
include (dirname(__FILE__) . "/../config.inc.php");
/**
* Database file
*/
include (dirname(__FILE__) . "/../db.inc.php");
/**
* Process
*/
include (dirname(__FILE__) . "/../functions/functions.process.php");
/**
* Update the database with the new data from the running script
*
* @param string $buffer The data to append to the database
* @return string Return a blank string to empty the buffer
*/
function update_callback($buffer)
{
global $process_id;
process_append_data($process_id,"<p>" . $buffer . "</p>");
return ""; //empty buffer
}
/**
* Disable system sort on shutdown
*
* @author Adam Zammit <adam.zammit@acspri.org.au>
* @since 2011-01-31
*/
function disable_systemsort()
{
set_setting('systemsort',false);
}
//get the arguments from the command line (this process_id)
if ($argc != 2) exit();
$process_id = $argv[1];
//register an exit function which will tell the database we have ended
register_shutdown_function('end_process',$process_id);
register_shutdown_function('disable_systemsort');
//all output send to database instead of stdout
ob_start('update_callback',2);
print T_("Sorting cases process starting");
$sleepinterval = 10; // in seconds so we can monitor if the process has been killed
while (!is_process_killed($process_id)) //check if process killed every $sleepinterval
{
//Make sure that the system knows we are system sorting
set_setting('systemsort',true);
print date("Y-m-d H:i") . " : " . T_("Sorting cases");
$time_start = microtime(true);
$db->StartTrans();
//Sort current cases for all enabled questionnaires
$sql = "SELECT c.case_id
FROM `case` as c
LEFT JOIN `call` as a on (a.call_id = c.last_call_id)
JOIN (sample as s, sample_import as si) on (s.sample_id = c.sample_id and si.sample_import_id = s.import_id)
JOIN (questionnaire_sample as qs, questionnaire as q, outcome as ou) on (c.questionnaire_id = q.questionnaire_id and qs.sample_import_id = s.import_id and ou.outcome_id = c.current_outcome_id and q.enabled = 1)
LEFT JOIN shift as sh on (sh.questionnaire_id = q.questionnaire_id and (CONVERT_TZ(NOW(),'System','UTC') >= sh.start) AND (CONVERT_TZ(NOW(),'System','UTC') <= sh.end))
LEFT JOIN appointment as ap on (ap.case_id = c.case_id AND ap.completed_call_id is NULL AND (ap.start > CONVERT_TZ(NOW(),'System','UTC')))
LEFT JOIN appointment as apn on (apn.case_id = c.case_id AND apn.completed_call_id is NULL AND (CONVERT_TZ(NOW(),'System','UTC') >= apn.start) AND (CONVERT_TZ(NOW(),'System','UTC') <= apn.end))
LEFT JOIN call_restrict as cr on (cr.day_of_week = DAYOFWEEK(CONVERT_TZ(NOW(), 'System' , s.Time_zone_name)) and TIME(CONVERT_TZ(NOW(), 'System' , s.Time_zone_name)) >= cr.start and TIME(CONVERT_TZ(NOW(), 'System' , s.Time_zone_name)) <= cr.end)
LEFT JOIN questionnaire_sample_exclude_priority AS qsep ON (qsep.questionnaire_id = c.questionnaire_id AND qsep.sample_id = c.sample_id)
WHERE c.current_operator_id IS NULL
AND (a.call_id is NULL or (a.end < CONVERT_TZ(DATE_SUB(NOW(), INTERVAL ou.default_delay_minutes MINUTE),'System','UTC')))
AND ap.case_id is NULL
AND ((qsep.questionnaire_id is NULL) or qsep.exclude = 0)
AND !(q.restrict_work_shifts = 1 AND sh.shift_id IS NULL)
AND !(si.call_restrict = 1 AND cr.day_of_week IS NULL)
AND ((apn.appointment_id IS NOT NULL) or qs.call_attempt_max = 0 or ((SELECT count(*) FROM call_attempt WHERE case_id = c.case_id) < qs.call_attempt_max))
AND ((apn.appointment_id IS NOT NULL) or qs.call_max = 0 or ((SELECT count(*) FROM `call` WHERE case_id = c.case_id) < qs.call_max))
AND (SELECT count(*) FROM `questionnaire_sample_quota` WHERE questionnaire_id = c.questionnaire_id AND sample_import_id = s.import_id AND quota_reached = 1) = 0
GROUP BY c.case_id
ORDER BY apn.start DESC, a.start ASC, qsep.priority DESC";
$rs = $db->GetAll($sql);
$i = 1;
foreach ($rs as $r)
{
$sql = "UPDATE `case`
SET sortorder = '$i'
WHERE case_id = '{$r['case_id']}'";
$db->Execute($sql);
$i++;
}
//Sort sample list where attached to an enabled questionnaire
$sql = "SELECT s.sample_id as sample_id,qs.questionnaire_id as questionnaire_id
FROM sample as s
JOIN (questionnaire_sample as qs, questionnaire as q, sample_import as si) on (qs.sample_import_id = s.import_id and si.sample_import_id = s.import_id and q.questionnaire_id = qs.questionnaire_id AND q.enabled = 1)
LEFT JOIN `case` as c on (c.sample_id = s.sample_id and c.questionnaire_id = qs.questionnaire_id)
LEFT JOIN call_restrict as cr on (cr.day_of_week = DAYOFWEEK(CONVERT_TZ(NOW(), 'System' , s.Time_zone_name)) and TIME(CONVERT_TZ(NOW(), 'System' , s.Time_zone_name)) >= cr.start and TIME(CONVERT_TZ(NOW(), 'System' , s.Time_zone_name)) <= cr.end)
LEFT JOIN shift as sh on (sh.questionnaire_id = q.questionnaire_id and (CONVERT_TZ(NOW(),'System','UTC') >= sh.start) AND (CONVERT_TZ(NOW(),'System','UTC') <= sh.end))
LEFT JOIN questionnaire_sample_exclude_priority AS qsep ON (qsep.questionnaire_id = qs.questionnaire_id AND qsep.sample_id = s.sample_id)
WHERE c.case_id is NULL
AND ((qsep.questionnaire_id IS NULL) or qsep.exclude = 0)
AND !(q.restrict_work_shifts = 1 AND sh.shift_id IS NULL)
AND !(si.call_restrict = 1 AND cr.day_of_week IS NULL)
AND (SELECT count(*) FROM `questionnaire_sample_quota` WHERE questionnaire_id = qs.questionnaire_id AND sample_import_id = s.import_id AND quota_reached = 1) = 0
GROUP BY s.sample_id,qs.questionnaire_id
ORDER BY qsep.priority DESC, rand() * qs.random_select, s.sample_id";
$rs = $db->GetAll($sql);
$i = 1;
foreach ($rs as $r)
{
$sql = "INSERT INTO questionnaire_sample_exclude_priority (questionnaire_id,sample_id,exclude,priority,sortorder)
VALUES ('{$r['questionnaire_id']}', '{$r['sample_id']}', 0, 50,'$i')
ON DUPLICATE KEY UPDATE sortorder = '$i'";
$db->Execute($sql);
$i++;
}
$result = $db->CompleteTrans();
$time_end = microtime(true);
$timer = $time_end - $time_start;
if ($result)
print T_("Completed sort") . ". " . T_("This task took") . ": $timer " . T_("seconds");
else
print T_("Failed to complete sort") . ". " . T_("This task took") . ": $timer " . T_("seconds");
for ($i = 0; $i < (SYSTEM_SORT_MINUTES * 60); $i += $sleepinterval)
{
if (is_process_killed($process_id)){break;}
sleep($sleepinterval);
}
}
disable_systemsort();
ob_get_contents();
ob_end_clean();
?>