diff --git a/core/dbobject.class.php b/core/dbobject.class.php
index 069b2503b..c2ca10ab3 100644
--- a/core/dbobject.class.php
+++ b/core/dbobject.class.php
@@ -26,6 +26,7 @@
require_once('metamodel.class.php');
require_once('deletionplan.class.inc.php');
+require_once('mutex.class.inc.php');
/**
diff --git a/datamodels/2.x/itop-tickets/datamodel.itop-tickets.xml b/datamodels/2.x/itop-tickets/datamodel.itop-tickets.xml
index 299030c2e..c397bd309 100755
--- a/datamodels/2.x/itop-tickets/datamodel.itop-tickets.xml
+++ b/datamodels/2.x/itop-tickets/datamodel.itop-tickets.xml
@@ -148,7 +148,22 @@
0
-
+
+
+ false
+ public
+ Overload-DBObject
+ Lock();
+ $iKey = parent::DBInsertNoReload();
+ $oMutex->Unlock();
+ return $iKey;
+ }
+ ]]>
+
+
diff --git a/readme.txt b/readme.txt
index fcada3385..3cb6f82f7 100644
--- a/readme.txt
+++ b/readme.txt
@@ -96,7 +96,7 @@ Flash version 8 or higher is required.
- data
- env-production
- log
-3) Point your web browser to the URL corresponding to the directory where the files
+4) Point your web browser to the URL corresponding to the directory where the files
have been unzipped and follow the indications on the screen.
If you wish to re-launch the installation process (for example in order to install
diff --git a/webservices/cron.php b/webservices/cron.php
index 43b5b01f5..a20b66767 100644
--- a/webservices/cron.php
+++ b/webservices/cron.php
@@ -40,13 +40,27 @@ if (!file_exists($sConfigFile))
require_once(APPROOT.'/application/startup.inc.php');
+function LogError($oP, $sErrorMessage, $sSeverity = 'ERROR')
+{
+ $bModeCLI = utils::IsModeCLI();
+
+ if ($bModeCLI)
+ {
+ error_log(ITOP_APPLICATION." cron.php $sSeverity: ".$sErrorMessage);
+ }
+ else
+ {
+ $oP->p("$sSeverity: $sMessage");
+ }
+
+}
function ReadMandatoryParam($oP, $sParam, $sSanitizationFilter = 'parameter')
{
$sValue = utils::ReadParam($sParam, null, true /* Allow CLI */, $sSanitizationFilter);
if (is_null($sValue))
{
- $oP->p("ERROR: Missing argument '$sParam'\n");
+ LogError($oP, "Missing argument '$sParam'");
UsageAndExit($oP);
}
return trim($sValue);
@@ -59,7 +73,7 @@ function UsageAndExit($oP)
if ($bModeCLI)
{
$oP->p("USAGE:\n");
- $oP->p("php cron.php --auth_user= --auth_pwd= [--param_file=] [--verbose=1] [--debug=1] [--status_only=1]\n");
+ $oP->p("php cron.php --auth_user= --auth_pwd= [--param_file=] [--verbose=1] [--status_only=1]\n");
}
else
{
@@ -69,7 +83,7 @@ function UsageAndExit($oP)
exit -2;
}
-function RunTask($oProcess, BackgroundTask $oTask, $oStartDate, $iTimeLimit)
+function RunTask($oP, $oProcess, BackgroundTask $oTask, $oStartDate, $iTimeLimit)
{
try
{
@@ -111,7 +125,7 @@ function RunTask($oProcess, BackgroundTask $oTask, $oStartDate, $iTimeLimit)
}
catch(Exception $e)
{
- $sMessage = 'Processing failed, the following exception occured: '.$e->getMessage();
+ LogError($oP, 'Processing failed, the following exception occured: '.$e->getMessage());
}
return $sMessage;
}
@@ -199,7 +213,7 @@ function CronExec($oP, $aProcesses, $bVerbose)
{
$oP->p(">> === ".$oNow->format('Y-m-d H:i:s').sprintf(" Starting:%-'=40s", ' '.$sTaskClass.' '));
}
- $sMessage = RunTask($oProcess, $aTasks[$sTaskClass], $oNow, $iTimeLimit);
+ $sMessage = RunTask($oP, $oProcess, $aTasks[$sTaskClass], $oNow, $iTimeLimit);
if ($bVerbose)
{
if(!empty($sMessage))
@@ -291,7 +305,7 @@ if (utils::IsModeCLI())
}
else
{
- $oP->p("Access wrong credentials ('$sAuthUser')");
+ LogError($oP, "Access wrong credentials ('$sAuthUser')");
$oP->output();
exit -1;
}
@@ -305,11 +319,19 @@ else
if (!UserRights::IsAdministrator())
{
- $oP->p("Access restricted to administrators");
- $oP->Output();
+ LogError($oP, 'Access restricted to administrators');
+ $oP->output();
exit -1;
}
+if (!MetaModel::DBHasAccess(ACCESS_ADMIN_WRITE))
+{
+ LogError($oP, 'A database maintenance is ongoing (read-only mode even for admins)', 'WARNING');
+ $oP->output();
+ exit -1;
+}
+
+
// Enumerate classes implementing BackgroundProcess
//
$aProcesses = array();
@@ -329,7 +351,6 @@ foreach(get_declared_classes() as $sPHPClass)
$bVerbose = utils::ReadParam('verbose', false, true /* Allow CLI */);
-$bDebug = utils::ReadParam('debug', false, true /* Allow CLI */);
if ($bVerbose)
{
@@ -348,44 +369,39 @@ if (utils::ReadParam('status_only', false, true /* Allow CLI */))
exit(0);
}
-require_once(APPROOT.'core/mutex.class.inc.php');
+// Compute the name of a lock for mysql
+// The name is server-wide
+$oConfig = utils::GetConfig();
+$sLockName = 'itop.cron.'.$oConfig->GetDBName().'_'.$oConfig->GetDBSubname();
+
$oP->p("Starting: ".time().' ('.date('Y-m-d H:i:s').')');
-try
+// CAUTION: using GET_LOCK anytime on the same connexion will RELEASE the lock
+// Todo: invoke GET_LOCK from a dedicated session (encapsulate that into a mutex class)
+$res = CMDBSource::QueryToScalar("SELECT GET_LOCK('$sLockName', 1)");// timeout = 1 second (see also IS_FREE_LOCK)
+if (is_null($res))
{
- $oConfig = utils::GetConfig();
- $oMutex = new iTopMutex('cron.'.$oConfig->GetDBName().'_'.$oConfig->GetDBSubname());
- if ($oMutex->TryLock())
+ LogError($oP, "Failed to acquire the lock '$sLockName'");
+}
+elseif ($res === '1')
+{
+ // The current session holds the lock
+ try
{
- // Note: testing this now in case some of the background processes forces the read-only mode for a while
- // in that case it is better to exit with the check on reentrance (mutex)
- if (!MetaModel::DBHasAccess(ACCESS_ADMIN_WRITE))
- {
- $oP->p("A database maintenance is ongoing (read-only mode even for admins).");
- $oP->Output();
- exit -1;
- }
-
CronExec($oP, $aProcesses, $bVerbose);
-
- $oMutex->Unlock();
}
- else
+ catch(Exception $e)
{
- // Exit silently
- $oP->p("Already running...");
+ LogError($oP, $e->getMessage()."\n".$e->getTraceAsString());
}
+ $res = CMDBSource::QueryToScalar("SELECT RELEASE_LOCK('$sLockName')");
}
-catch (Exception $e)
+else
{
- $oP->p("ERROR: '".$e->getMessage()."'");
- if ($bDebug)
- {
- // Might contain verb parameters such a password...
- $oP->p($e->getTraceAsString());
- }
+ // Lock already held by another session
+ // Exit silently
+ $oP->p("Already running...");
}
-
$oP->p("Exiting: ".time().' ('.date('Y-m-d H:i:s').')');
$oP->Output();