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