Skip to content

Commit

Permalink
Merge pull request #7505 from konadave/flexiblejobs
Browse files Browse the repository at this point in the history
CRM-17669 and CRM-17686, flexible scheduled jobs
  • Loading branch information
colemanw committed Jan 1, 2016
2 parents 580e781 + 902e557 commit 1fd3516
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 32 deletions.
33 changes: 33 additions & 0 deletions CRM/Admin/Form/Job.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ public function buildQuickForm($check = FALSE) {

$this->add('select', 'run_frequency', ts('Run frequency'), CRM_Core_SelectValues::getJobFrequency());

// CRM-17686
$this->add('datepicker', 'scheduled_run_date', ts('Scheduled Run Date'), NULL, FALSE, array('minDate' => time()));

$this->add('textarea', 'parameters', ts('Command parameters'),
"cols=50 rows=6"
);
Expand Down Expand Up @@ -156,6 +159,12 @@ public function setDefaultValues() {

CRM_Core_DAO::storeValues($dao, $defaults);

// CRM-17686
if (!empty($dao->scheduled_run_date)) {
$ts = strtotime($dao->scheduled_run_date);
$defaults['scheduled_run_date'] = date("Y-m-d H:i:s", $ts);
}

// CRM-10708
// job entity thats shipped with core is all lower case.
// this makes sure camel casing is followed for proper working of default population.
Expand Down Expand Up @@ -194,6 +203,30 @@ public function postProcess() {
$dao->description = $values['description'];
$dao->is_active = CRM_Utils_Array::value('is_active', $values, 0);

// CRM-17686
$ts = strtotime($values['scheduled_run_date']);
// if a date/time is supplied and not in the past, then set the next scheduled run...
if ($ts > time()) {
$dao->scheduled_run_date = CRM_Utils_Date::currentDBDate($ts);
// warn about monthly/quarterly scheduling, if applicable
if (($dao->run_frequency == 'Monthly') || ($dao->run_frequency == 'Quarter')) {
$info = getdate($ts);
if ($info['mday'] > 28) {
CRM_Core_Session::setStatus(
ts('Relative month values are calculated based on the length of month(s) that they pass through.
The result will land on the same day of the month except for days 29-31 when the target month contains fewer days than the previous month.
For example, if a job is scheduled to run on August 31st, the following invocation will occur on October 1st, and then the 1st of every month thereafter.
To avoid this issue, please schedule Monthly and Quarterly jobs to run within the first 28 days of the month.'),
ts('Warning'), 'info', array('expires' => 0));
}
}
}
// ...otherwise, if this isn't a new scheduled job, clear the next scheduled run
elseif ($dao->id) {
$job = new CRM_Core_ScheduledJob(array('id' => $dao->id));
$job->clearScheduledRunDate();
}

$dao->save();

// CRM-11143 - Give warning message if update_greetings is Enabled (is_active) since it generally should not be run automatically via execute action or runjobs url.
Expand Down
75 changes: 46 additions & 29 deletions CRM/Core/ScheduledJob.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,33 @@ public function saveLastRun($date = NULL) {
$dao->save();
}

/**
* @return void
*/
public function clearScheduledRunDate() {
CRM_Core_DAO::executeQuery('UPDATE civicrm_job SET scheduled_run_date = NULL WHERE id = %1',
array(
'1' => array($this->id, 'Integer'),
));
}

/**
* @return bool
*/
public function needsRunning() {

// CRM-17686
// check if the job has a specific scheduled date/time
if (!empty($this->scheduled_run_date)) {
if (strtotime($this->scheduled_run_date) <= time()) {
$this->clearScheduledRunDate();
return TRUE;
}
else {
return FALSE;
}
}

// run if it was never run
if (empty($this->last_run)) {
return TRUE;
Expand All @@ -100,43 +123,37 @@ public function needsRunning() {
case 'Always':
return TRUE;

case 'Hourly':
$format = 'YmdH';
// CRM-17669
case 'Yearly':
$offset = '+1 year';
break;

case 'Quarter':
$offset = '+3 months';
break;

case 'Monthly':
$offset = '+1 month';
break;

case 'Weekly':
$offset = '+1 week';
break;

case 'Daily':
$format = 'Ymd';
$offset = '+1 day';
break;

case 'Mondays':
$now = CRM_Utils_Date::currentDBDate();
$dayAgo = strtotime('-1 day', strtotime($now));
$lastRun = strtotime($this->last_run);
$nowDayOfWeek = date('l', strtotime($now));
return ($lastRun < $dayAgo && $nowDayOfWeek == 'Monday');

case '1stOfMth':
$now = CRM_Utils_Date::currentDBDate();
$dayAgo = strtotime('-1 day', strtotime($now));
$lastRun = strtotime($this->last_run);
$nowDayOfMonth = date('j', strtotime($now));
return ($lastRun < $dayAgo && $nowDayOfMonth == '1');

case '1stOfQtr':
$now = CRM_Utils_Date::currentDBDate();
$dayAgo = strtotime('-1 day', strtotime($now));
$lastRun = strtotime($this->last_run);
$nowDayOfMonth = date('j', strtotime($now));
$nowMonth = date('n', strtotime($now));
$qtrMonths = array('1', '4', '7', '10');
return ($lastRun < $dayAgo && $nowDayOfMonth == '13' && in_array($nowMonth, $qtrMonths));
case 'Hourly':
$offset = '+1 hour';
break;
}

$now = CRM_Utils_Date::currentDBDate();
$lastTime = date($format, strtotime($this->last_run));
$thisTime = date($format, strtotime($now));
$now = strtotime(CRM_Utils_Date::currentDBDate());
$lastTime = strtotime($this->last_run);
$nextTime = strtotime($offset, $lastTime);

return ($lastTime <> $thisTime);
return ($now >= $nextTime);
}

public function __destruct() {
Expand Down
9 changes: 6 additions & 3 deletions CRM/Core/SelectValues.php
Original file line number Diff line number Diff line change
Expand Up @@ -893,9 +893,12 @@ public static function getExtensionTypes() {
*/
public static function getJobFrequency() {
return array(
'1stOfQtr' => ts('1st day of every quarter'),
'1stOfMth' => ts('1st day of every month'),
'Mondays' => ts('Monday of every week'),
// CRM-17669
'Yearly' => ts('Yearly'),
'Quarter' => ts('Quarterly'),
'Monthly' => ts('Monthly'),
'Weekly' => ts('Weekly'),

'Daily' => ts('Daily'),
'Hourly' => ts('Hourly'),
'Always' => ts('Every time cron job is run'),
Expand Down
28 changes: 28 additions & 0 deletions CRM/Upgrade/Incremental/php/FourSeven.php
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,16 @@ public function upgrade_4_7_beta2($rev) {
$this->addTask('Delete unused file', 'deleteVersionCheckCacheFile');
}

/**
* Upgrade function.
*
* @param string $rev
*/
public function upgrade_4_7_beta6($rev) {
$this->addTask(ts('Upgrade DB to %1: SQL', array(1 => $rev)), 'runSql', $rev);
$this->addTask('Disable flexible jobs extension', 'disableFlexibleJobsExtension');
}

/**
* CRM-16354
*
Expand Down Expand Up @@ -363,4 +373,22 @@ public function deleteVersionCheckCacheFile(CRM_Queue_TaskContext $ctx) {
return TRUE;
}

/**
* CRM-17669 and CRM-17686, make scheduled jobs more flexible, disable the 4.6 extension if installed
*
* @param \CRM_Queue_TaskContext $ctx
*
* @return bool
*/
public function disableFlexibleJobsExtension(CRM_Queue_TaskContext $ctx) {
try {
civicrm_api3('Extension', 'disable', array('key' => 'com.klangsoft.flexiblejobs'));
}
catch (CiviCRM_API3_Exception $e) {
// just ignore if the extension isn't installed
}

return TRUE;
}

}
4 changes: 4 additions & 0 deletions CRM/Upgrade/Incremental/sql/4.7.beta6.mysql.tpl
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
{* file to handle db changes in 4.7.beta6 during upgrade *}

-- CRM-17686
ALTER TABLE `civicrm_job`
ADD COLUMN `scheduled_run_date` timestamp NULL DEFAULT NULL COMMENT 'When is this cron entry scheduled to run' AFTER `last_run`;
8 changes: 8 additions & 0 deletions templates/CRM/Admin/Form/Job.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,14 @@ CRM.$(function($) {
<td class="label">{$form.parameters.label}<br />{docURL page="Managing Scheduled Jobs" resource="wiki"}</td>
<td>{$form.parameters.html}</td>
</tr>
<tr class="crm-job-form-block-scheduled-run-date">
<td class="label">{$form.scheduled_run_date.label}</td>
<td>{$form.scheduled_run_date.html}<br />
<div dlass="description">{ts}Do not run this job before this date / time. The run frequency selected above will apply thereafter.{/ts}<br />
{if $action eq 1}{ts}Leave blank to run as soon as possible.{/ts}{else}{ts}Leave blank to run at next run frequency.{/ts}{/if}
</div>
</td>
</tr>
<tr class="crm-job-form-block-is_active">
<td></td><td>{$form.is_active.html}&nbsp;{$form.is_active.label}</td>
</tr>
Expand Down
8 changes: 8 additions & 0 deletions xml/schema/Core/Job.xml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,14 @@
<comment>When was this cron entry last run</comment>
<add>4.1</add>
</field>
<field>
<name>scheduled_run_date</name>
<type>timestamp</type>
<default>NULL</default>
<required>false</required>
<comment>When is this cron entry scheduled to run</comment>
<add>4.7</add>
</field>
<field>
<name>name</name>
<title>Job Name</title>
Expand Down

0 comments on commit 1fd3516

Please sign in to comment.