2012-08-08 22:48:36 +00:00
< ? php
2024-02-08 12:57:48 +00:00
declare ( strict_types = 1 );
2012-08-08 22:48:36 +00:00
/**
2016-07-21 15:07:57 +00:00
* @ copyright Copyright ( c ) 2016 , ownCloud , Inc .
*
2017-11-06 14:56:42 +00:00
* @ author Artem Sidorenko < artem @ posteo . de >
2015-03-26 10:44:34 +00:00
* @ author Christopher Schäpers < kondou @ ts . unde . re >
2020-03-31 08:49:10 +00:00
* @ author Christoph Wurst < christoph @ winzerhof - wurst . at >
2024-02-08 12:57:48 +00:00
* @ author Côme Chilliet < come . chilliet @ nextcloud . com >
2019-12-03 18:57:53 +00:00
* @ author Daniel Kesselberg < mail @ danielkesselberg . de >
2020-12-16 13:54:15 +00:00
* @ author hoellen < dev @ hoellen . eu >
2020-12-30 13:07:05 +00:00
* @ author J0WI < J0WI @ users . noreply . github . com >
2015-03-26 10:44:34 +00:00
* @ author Jakob Sack < mail @ jakobsack . de >
2016-07-21 15:07:57 +00:00
* @ author Joas Schilling < coding @ schilljs . com >
2015-03-26 10:44:34 +00:00
* @ author Jörn Friedrich Dreyer < jfd @ butonic . de >
2017-11-06 14:56:42 +00:00
* @ author Ko - < k . stoffelen @ cs . ru . nl >
2020-03-31 08:49:10 +00:00
* @ author Michael Kuhn < michael @ ikkoku . de >
2015-03-26 10:44:34 +00:00
* @ author Morris Jobke < hey @ morrisjobke . de >
* @ author Oliver Kohl D . Sc . < oliver @ kohl . bz >
2016-07-21 16:13:36 +00:00
* @ author Robin Appelman < robin @ icewind . nl >
2017-11-06 14:56:42 +00:00
* @ author Roeland Jago Douma < roeland @ famdouma . nl >
2015-03-26 10:44:34 +00:00
* @ author Steffen Lindner < mail @ steffen - lindner . de >
* @ author Thomas Müller < thomas . mueller @ tmit . eu >
2020-12-16 13:54:15 +00:00
* @ author Vincent Petry < vincent @ nextcloud . com >
2021-07-18 15:06:45 +00:00
* @ author Stephen Michel < git @ smichel . me >
2013-04-20 19:26:47 +00:00
*
2015-03-26 10:44:34 +00:00
* @ license AGPL - 3.0
2013-04-20 19:26:47 +00:00
*
2015-03-26 10:44:34 +00:00
* This code is free software : you can redistribute it and / or modify
* it under the terms of the GNU Affero General Public License , version 3 ,
* as published by the Free Software Foundation .
2013-04-20 19:26:47 +00:00
*
2015-03-26 10:44:34 +00:00
* This program is distributed in the hope that it will be useful ,
2013-04-20 19:26:47 +00:00
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
2015-03-26 10:44:34 +00:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Affero General Public License for more details .
2013-04-20 19:26:47 +00:00
*
2015-03-26 10:44:34 +00:00
* You should have received a copy of the GNU Affero General Public License , version 3 ,
2019-12-03 18:57:53 +00:00
* along with this program . If not , see < http :// www . gnu . org / licenses />
2013-04-20 19:26:47 +00:00
*
*/
2024-02-08 12:57:48 +00:00
2017-10-13 19:30:29 +00:00
require_once __DIR__ . '/lib/versioncheck.php' ;
2016-12-19 14:29:52 +00:00
2024-02-08 13:31:34 +00:00
use OCP\App\IAppManager ;
2024-02-08 12:57:48 +00:00
use OCP\BackgroundJob\IJobList ;
2024-02-08 13:16:44 +00:00
use OCP\IAppConfig ;
2024-02-08 12:57:48 +00:00
use OCP\IConfig ;
use OCP\ISession ;
use OCP\ITempManager ;
use OCP\Server ;
use OCP\Util ;
use Psr\Log\LoggerInterface ;
2013-06-10 11:45:19 +00:00
try {
2016-10-06 10:13:02 +00:00
require_once __DIR__ . '/lib/base.php' ;
2013-03-16 23:48:10 +00:00
2024-04-08 11:04:14 +00:00
if ( $argv [ 1 ] === '-h' || $argv [ 1 ] === '--help' ) {
echo ' Description :
Run the background job routine
Usage :
2024-04-11 08:55:39 +00:00
php - f cron . php -- [ - h ] [ < job - classes >... ]
2024-04-08 11:04:14 +00:00
Arguments :
2024-04-11 08:55:39 +00:00
job - classes Optional job class list to only run those jobs
2024-04-08 11:04:14 +00:00
Options :
- h , -- help Display this help message ' . PHP_EOL ;
exit ( 0 );
}
2024-02-08 12:57:48 +00:00
if ( Util :: needUpgrade ()) {
Server :: get ( LoggerInterface :: class ) -> debug ( 'Update required, skipping cron' , [ 'app' => 'cron' ]);
2015-03-12 20:03:26 +00:00
exit ;
}
2024-02-08 13:38:03 +00:00
$config = Server :: get ( IConfig :: class );
if ( $config -> getSystemValueBool ( 'maintenance' , false )) {
2024-02-08 12:57:48 +00:00
Server :: get ( LoggerInterface :: class ) -> debug ( 'We are in maintenance mode, skipping cron' , [ 'app' => 'cron' ]);
2015-03-12 20:03:26 +00:00
exit ;
2014-07-23 19:29:24 +00:00
}
2024-02-08 13:31:34 +00:00
// Don't do anything if Nextcloud has not been installed
if ( ! $config -> getSystemValueBool ( 'installed' , false )) {
exit ( 0 );
}
2014-02-18 16:17:08 +00:00
// load all apps to get all api routes properly setup
2024-02-08 13:31:34 +00:00
Server :: get ( IAppManager :: class ) -> loadApps ();
2014-02-18 16:17:08 +00:00
2024-02-08 12:57:48 +00:00
Server :: get ( ISession :: class ) -> close ();
2012-08-09 21:52:48 +00:00
2014-07-02 10:00:35 +00:00
// initialize a dummy memory session
2015-07-20 10:59:04 +00:00
$session = new \OC\Session\Memory ( '' );
$cryptoWrapper = \OC :: $server -> getSessionCryptoWrapper ();
$session = $cryptoWrapper -> wrapSession ( $session );
\OC :: $server -> setSession ( $session );
2014-07-02 09:52:45 +00:00
2024-02-08 12:57:48 +00:00
$logger = Server :: get ( LoggerInterface :: class );
2024-02-08 13:16:44 +00:00
$appConfig = Server :: get ( IAppConfig :: class );
2024-02-08 12:57:48 +00:00
$tempManager = Server :: get ( ITempManager :: class );
2012-08-11 15:18:49 +00:00
2022-05-30 16:01:51 +00:00
$tempManager -> cleanOld ();
2012-08-08 22:48:36 +00:00
2013-06-10 11:45:19 +00:00
// Exit if background jobs are disabled!
2024-02-08 13:16:44 +00:00
$appMode = $appConfig -> getValueString ( 'core' , 'backgroundjobs_mode' , 'ajax' );
2018-01-25 23:14:00 +00:00
if ( $appMode === 'none' ) {
2013-06-10 11:45:19 +00:00
if ( OC :: $CLI ) {
echo 'Background Jobs are disabled!' . PHP_EOL ;
} else {
2020-03-26 08:30:18 +00:00
OC_JSON :: error ([ 'data' => [ 'message' => 'Background jobs disabled!' ]]);
2013-06-10 11:45:19 +00:00
}
2013-04-20 19:26:47 +00:00
exit ( 1 );
2012-08-08 22:48:36 +00:00
}
2012-10-26 21:16:17 +00:00
2013-06-10 11:45:19 +00:00
if ( OC :: $CLI ) {
2015-03-11 00:09:12 +00:00
// set to run indefinitely if needed
2017-03-11 16:04:21 +00:00
if ( strpos ( @ ini_get ( 'disable_functions' ), 'set_time_limit' ) === false ) {
@ set_time_limit ( 0 );
}
2015-03-11 00:09:12 +00:00
2015-04-01 08:31:48 +00:00
// the cron job must be executed with the right user
2016-07-08 13:55:17 +00:00
if ( ! function_exists ( 'posix_getuid' )) {
2020-09-17 15:23:07 +00:00
echo " The posix extensions are required - see https://www.php.net/manual/en/book.posix.php " . PHP_EOL ;
2017-03-08 19:04:55 +00:00
exit ( 1 );
2016-07-08 13:55:17 +00:00
}
2019-08-17 15:18:17 +00:00
2020-10-03 14:32:49 +00:00
$user = posix_getuid ();
2021-06-22 18:25:14 +00:00
$dataDirectoryUser = fileowner ( $config -> getSystemValueString ( 'datadirectory' , \OC :: $SERVERROOT . '/data' ));
if ( $user !== $dataDirectoryUser ) {
2024-03-08 18:50:11 +00:00
echo " Cron has to be executed with the user that owns the data directory " . PHP_EOL ;
2020-10-03 14:32:49 +00:00
echo " Current user id: " . $user . PHP_EOL ;
2021-06-22 18:25:14 +00:00
echo " Owner id of the data directory: " . $dataDirectoryUser . PHP_EOL ;
2017-03-08 19:04:55 +00:00
exit ( 1 );
2015-04-01 08:31:48 +00:00
}
2020-10-03 14:32:49 +00:00
2018-01-25 23:14:00 +00:00
// We call Nextcloud from the CLI (aka cron)
if ( $appMode !== 'cron' ) {
2024-02-08 13:16:44 +00:00
$appConfig -> setValueString ( 'core' , 'backgroundjobs_mode' , 'cron' );
2013-06-10 11:45:19 +00:00
}
2022-01-31 16:59:09 +00:00
// Low-load hours
$onlyTimeSensitive = false ;
$startHour = $config -> getSystemValueInt ( 'maintenance_window_start' , 100 );
if ( $startHour <= 23 ) {
$date = new \DateTime ( 'now' , new \DateTimeZone ( 'UTC' ));
$currentHour = ( int ) $date -> format ( 'G' );
$endHour = $startHour + 4 ;
if ( $startHour <= 20 ) {
// Start time: 01:00
// End time: 05:00
// Only run sensitive tasks when it's before the start or after the end
$onlyTimeSensitive = $currentHour < $startHour || $currentHour > $endHour ;
} else {
// Start time: 23:00
// End time: 03:00
$endHour -= 24 ; // Correct the end time from 27:00 to 03:00
// Only run sensitive tasks when it's after the end and before the start
$onlyTimeSensitive = $currentHour > $endHour && $currentHour < $startHour ;
}
}
2013-06-10 11:45:19 +00:00
// Work
2024-02-08 12:57:48 +00:00
$jobList = Server :: get ( IJobList :: class );
2016-01-28 14:34:50 +00:00
2020-02-16 19:50:50 +00:00
// We only ask for jobs for 14 minutes, because after 5 minutes the next
// system cron task should spawn and we want to have at most three
// cron jobs running in parallel.
2016-04-21 08:33:44 +00:00
$endTime = time () + 14 * 60 ;
2016-01-28 14:34:50 +00:00
$executedJobs = [];
2024-04-11 08:55:39 +00:00
// a specific job class list can optionally be given as argument
$jobClasses = array_slice ( $argv , 1 );
$jobClasses = empty ( $jobClasses ) ? null : $jobClasses ;
2024-04-08 15:25:51 +00:00
while ( $job = $jobList -> getNext ( $onlyTimeSensitive , $jobClasses )) {
2016-01-28 14:34:50 +00:00
if ( isset ( $executedJobs [ $job -> getId ()])) {
2016-05-18 12:27:48 +00:00
$jobList -> unlockJob ( $job );
2016-01-28 14:34:50 +00:00
break ;
}
2024-01-10 14:51:22 +00:00
$jobDetails = get_class ( $job ) . ' (id: ' . $job -> getId () . ', arguments: ' . json_encode ( $job -> getArgument ()) . ')' ;
2023-12-20 14:35:40 +00:00
$logger -> debug ( 'CLI cron call has selected job ' . $jobDetails , [ 'app' => 'cron' ]);
2023-12-20 09:58:08 +00:00
$memoryBefore = memory_get_usage ();
$memoryPeakBefore = memory_get_peak_usage ();
2024-03-12 10:23:35 +00:00
/** @psalm-suppress DeprecatedMethod Calling execute until it is removed, then will switch to start */
2024-03-12 10:01:46 +00:00
$job -> execute ( $jobList );
2022-05-30 16:01:51 +00:00
2023-12-20 09:58:08 +00:00
$memoryAfter = memory_get_usage ();
$memoryPeakAfter = memory_get_peak_usage ();
if ( $memoryAfter - $memoryBefore > 10_000_000 ) {
2024-02-08 12:57:48 +00:00
$logger -> warning ( 'Used memory grew by more than 10 MB when executing job ' . $jobDetails . ': ' . Util :: humanFileSize ( $memoryAfter ) . ' (before: ' . Util :: humanFileSize ( $memoryBefore ) . ')' , [ 'app' => 'cron' ]);
2023-12-20 09:58:08 +00:00
}
if ( $memoryPeakAfter > 300_000_000 ) {
2024-02-08 12:57:48 +00:00
$logger -> warning ( 'Cron job used more than 300 MB of ram after executing job ' . $jobDetails . ': ' . Util :: humanFileSize ( $memoryPeakAfter ) . ' (before: ' . Util :: humanFileSize ( $memoryPeakBefore ) . ')' , [ 'app' => 'cron' ]);
2023-12-20 09:58:08 +00:00
}
2016-09-30 11:30:16 +00:00
// clean up after unclean jobs
2024-02-08 13:31:34 +00:00
Server :: get ( \OC\Files\SetupManager :: class ) -> tearDown ();
2022-05-30 16:01:51 +00:00
$tempManager -> clean ();
2016-01-28 14:34:50 +00:00
$jobList -> setLastJob ( $job );
$executedJobs [ $job -> getId ()] = true ;
unset ( $job );
2016-04-21 08:33:44 +00:00
if ( time () > $endTime ) {
break ;
}
2013-06-10 11:45:19 +00:00
}
} else {
// We call cron.php from some website
2017-05-30 10:10:10 +00:00
if ( $appMode === 'cron' ) {
2013-06-10 11:45:19 +00:00
// Cron is cron :-P
2020-03-26 08:30:18 +00:00
OC_JSON :: error ([ 'data' => [ 'message' => 'Backgroundjobs are using system cron!' ]]);
2013-06-10 11:45:19 +00:00
} else {
// Work and success :-)
2024-02-08 12:57:48 +00:00
$jobList = Server :: get ( IJobList :: class );
2013-06-10 11:45:19 +00:00
$job = $jobList -> getNext ();
2014-07-24 11:54:55 +00:00
if ( $job != null ) {
2022-04-23 13:42:37 +00:00
$logger -> debug ( 'WebCron call has selected job with ID ' . strval ( $job -> getId ()), [ 'app' => 'cron' ]);
2024-03-12 10:23:35 +00:00
/** @psalm-suppress DeprecatedMethod Calling execute until it is removed, then will switch to start */
2024-03-12 10:01:46 +00:00
$job -> execute ( $jobList );
2014-07-24 11:46:40 +00:00
$jobList -> setLastJob ( $job );
}
2013-06-10 11:45:19 +00:00
OC_JSON :: success ();
}
2012-08-09 21:49:20 +00:00
}
2012-10-26 21:16:17 +00:00
2014-10-17 10:08:31 +00:00
// Log the successful cron execution
2024-02-08 13:16:44 +00:00
$appConfig -> setValueInt ( 'core' , 'lastcron' , time ());
2013-06-10 11:45:19 +00:00
exit ();
} catch ( Exception $ex ) {
2024-02-08 12:57:48 +00:00
Server :: get ( LoggerInterface :: class ) -> error (
$ex -> getMessage (),
[ 'app' => 'cron' , 'exception' => $ex ]
);
2021-08-19 10:40:55 +00:00
echo $ex . PHP_EOL ;
2021-07-18 15:06:45 +00:00
exit ( 1 );
2016-04-20 16:01:47 +00:00
} catch ( Error $ex ) {
2024-02-08 12:57:48 +00:00
Server :: get ( LoggerInterface :: class ) -> error (
$ex -> getMessage (),
[ 'app' => 'cron' , 'exception' => $ex ]
);
2021-08-19 10:40:55 +00:00
echo $ex . PHP_EOL ;
2021-07-18 15:06:45 +00:00
exit ( 1 );
2013-08-18 09:02:08 +00:00
}