SproutCMS

This is the code documentation for the SproutCMS project

source of /sprout/Controllers/CronJobController.php

  1. <?php
  2. /*
  3.  * Copyright (C) 2017 Karmabunny Pty Ltd.
  4.  *
  5.  * This file is a part of SproutCMS.
  6.  *
  7.  * SproutCMS is free software: you can redistribute it and/or modify it under the terms
  8.  * of the GNU General Public License as published by the Free Software Foundation, either
  9.  * version 2 of the License, or (at your option) any later version.
  10.  *
  11.  * For more information, visit <http://getsproutcms.com>.
  12.  */
  13.  
  14. namespace Sprout\Controllers;
  15.  
  16. use Kohana;
  17.  
  18. use Sprout\Helpers\Register;
  19. use Sprout\Helpers\Sprout;
  20.  
  21.  
  22. /**
  23.  * Runs scheduled tasks assigned by {@see Register::cronJob} on behalf of the UN*X cron utility
  24.  */
  25. class CronJobController extends Controller
  26. {
  27.  
  28. public function __construct()
  29. {
  30. if (PHP_SAPI !== 'cli') {
  31. die('Cron jobs must be run via CLI');
  32. }
  33. Kohana::closeBuffers();
  34. $_ENV['CRON'] = 1;
  35. }
  36.  
  37.  
  38. /**
  39.   * Run a given cron schedule
  40.   *
  41.   * Each individual job is run independently of the others using a php sub-process
  42.   * This means that *any* failure of a given job will be isolated and other
  43.   * jobs will continue to run
  44.   *
  45.   * @param string $schedule Cron job schedule, e.g. 'daily' or 'weekly'
  46.   * @return void Terminates script with exit status of number of failed jobs (0 = no failures)
  47.   */
  48. public function run($schedule)
  49. {
  50. $jobs = Register::getCronJobs($schedule);
  51. echo 'Num jobs: ', count($jobs), PHP_EOL;
  52.  
  53. $failed = 0;
  54. foreach ($jobs as $j) {
  55. echo PHP_EOL, $j[0] . '::' . $j[1], PHP_EOL;
  56.  
  57. // Build the shell command string using current interpreter name
  58. $php = escapeshellcmd($_SERVER['_']);
  59. $script = escapeshellarg($_SERVER['argv'][0]);
  60. $class = escapeshellarg($j[0]);
  61. $func = escapeshellarg($j[1]);
  62. $cmd = implode(' ', [$php, $script, 'cron_job/runJob', $class, $func, '2>&1']);
  63.  
  64. // Start process
  65. $spec= [
  66. 1 => ['pipe', 'w']
  67. ];
  68. $pipes = [];
  69. $proc = proc_open($cmd, $spec, $pipes);
  70. if (!is_resource($proc)) {
  71. echo ' !! Failed to start process', PHP_EOL;
  72. continue;
  73. }
  74.  
  75. // Output the PID, which may be useful to someone
  76. $status = proc_get_status($proc);
  77. echo ' PID ', $status['pid'], PHP_EOL;
  78.  
  79. // Stream the output pipe, with an indent of 4x spaces
  80. echo ' ';
  81. stream_set_blocking($pipes[1], 0);
  82. while (!feof($pipes[1])) {
  83. $response = fgets($pipes[1], 4096);
  84. $response = str_replace("\n", "\n ", $response);
  85. echo $response;
  86. flush();
  87. }
  88. echo PHP_EOL;
  89.  
  90. // Wait for process to exit
  91. fclose($pipes[1]);
  92. $return = proc_close($proc);
  93. echo ' EXIT ', $return, PHP_EOL;
  94.  
  95. if ($return !== 0) {
  96. $failed++;
  97. }
  98. }
  99.  
  100. echo PHP_EOL, 'Failures: ', $failed, PHP_EOL;
  101. exit($failed);
  102. }
  103.  
  104.  
  105. /**
  106.   * Internal job runner for cron jobs
  107.   *
  108.   * Just creates an instance of the class (must be a controller), then calls the method
  109.   *
  110.   * Parameters are passed by CLI argv array; 2 => class, 3 => function
  111.   */
  112. public function runJob()
  113. {
  114. $class = $_SERVER['argv'][2];
  115. $func = $_SERVER['argv'][3];
  116.  
  117. $inst = Sprout::instance(
  118. $class,
  119. ['Sprout\\Controllers\\Controller']
  120. );
  121.  
  122. call_user_func([$inst, $func]);
  123. }
  124.  
  125. }
  126.