如何使用cron作业调度动态函数?

时间:2021-03-31 01:08:57

I want to know how I can schedule a dynamic(auto populated data) function to auto run everyday at saved time?

我想知道如何安排动态(自动填充数据)功能在保存的时间每天自动运行?

Let's say I have a form that once the button is clicked it sends the data to the function, which the posts the data. I simply want to automate that so that I don't have to press the button.

假设我有一个表单,一旦单击该按钮,它就会将数据发送到函数,该函数会发布数据。我只是想自动化,所以我不必按下按钮。

<ul>
    <?php 
    foreach($Class->retrieveData as $data)
    {
        <form method="post" action="">
            <li>
                <input type="hidden" name="name">'.$data['name'].'<br/>
                <input type="hidden" name="description">'.$data['description'].'<br/>
                <input type="submit" name="post_data"  value="Post">
            </li>
        </form>
    }
    ?>
</ul>

Now, the form will pass the data to the function.

现在,表单将数据传递给函数。

if(isset($_POST['post_data'])) // if post_data button is clicked then it runs myFunction()
{
    myFunction();
}

myFunction()
{
    $name        = $_POST['name'];
    $description = $_POST['description'];
}

I tried doing the following but the problem is that Cron Job can only run the whole .php file, and I am retrieving the saved time to run from MySQL.

我尝试执行以下操作,但问题是Cron Job只能运行整个.php文件,而我正在检索从MySQL运行的已保存时间。

foreach($Class->getTime() as $timeData)
{
    $timeHour    = $timeData['timeHour'];
    $timeMinute = $timeData['timeMinute'];

    $hourMin    = date('H:i');
    $timeData   = ''.$timeHour.':'.$timeMinute.'';

    if($hourMin == $timeData)
    {
        run myFunction.
    }
}

$hourMin is the current hour:minute which is being matched against a saved time to auto run from Mysql. So if $hourMin == $timeData then the function will run.

$ hourMin是当前小时:分钟,它与从Mysql自动运行的已保存时间相匹配。因此,如果$ hourMin == $ timeData,那么该函数将运行。

How can I run Cron Job to auto run myFunction() if the $hourMin equals $timeData?

如果$ hourMin等于$ timeData,如何运行Cron Job来自动运行myFunction()?

So...

List 1 = is to be runned at 10am
List 2 = is to be runned at 12pm
List 3 = is to be runned at 2pm

The 10am, 12pm, 2pm is the $timeHour and $timeMinute that is retrieved from MySQL but based on each list id's.

上午10点,下午12点,下午2点是从MySQL检索的$ timeHour和$ timeMinute,但是基于每个列表id。

EDIT

@randomSeed,

1) I can schedule cron jobs.
2) $name and $description will all be arrays, so the following is what I am trying to accomplish.

$name = array(
    'Jon',
    'Steven',
    'Carter'
);

$description = array(
    'Jon is a great person.',
    'Steven has an outgoing character.',
    'Carter is a horrible person.'
);

I want to parse the first arrays from both $name and $description if the scheduled time is correct.

如果预定的时间是正确的,我想解析$ name和$ description中的第一个数组。

In database I have the following

在数据库中,我有以下内容

postDataTime table

+----+---------+----------+------------+--------+
| iD | timeDay | timeHour | timeMinute | postiD |
+--------------------------------------+--------+
| 1  | *       | 9        | 0          | 21     |
|----|---------|----------|------------|--------|
| 2  | *       | 10       | 30         | 22     |
|----|---------|----------|------------|--------|
| 3  | *       | 11       | 0          | 23     |
+----|---------+----------+------------+--------+

iD         = auto incremented on upload.
timeDay    = * is everyday (cron job style)
timeHour   = Hour of the day to run the script
timeMinute = minute of the hour to run script
postiD     = this is the id of the post that is located in another table (n+1 relationship)

If it's difficult to understand.. what is quinoa

如果难以理解......什么是藜麦

if(time() == 10:30(time from MySQL postiD = 22))
{
    // run myFunction with the data that is retrieved for that time ex:

    $postiD = '22';
    $name   = 'Steven';
    $description = 'Steven has an outgoing character.';

    // the above is what will be in the $_POST from the form and will be
    // sent to the myFunction()
}

I simply want to schedule everything according to the time that is saved to MySQL as I showed at the very top(postDataTime table). (I'd show what I have tried, but I have searched for countless hours for an example of what I am trying to accomplish but I cannot find anything and what I tried doesn't work.).

我只想根据保存到MySQL的时间来安排所有内容,就像我在最顶层显示的那样(postDataTime表)。 (我会展示我尝试过的东西,但是我已经搜索了无数个小时的例子来说明我想要完成的事情,但我找不到任何东西,我尝试的东西也不起作用。)

I thought I could use the exec() function but from what it seems that does not allow me to run functions, otherwise I would do the following..

我以为我可以使用exec()函数,但从它看起来不允许我运行函数,否则我会做以下..

$time = '10:30';
if($time == time())
{
    exec(myFunction());
}

5 个解决方案

#1


2  

you have 2 ways, although only one will do exactly what you want to do;

你有2种方法,虽然只有一种方法可以完成你想做的事情;

  • 1st way requires that you have access and privileges to change cron-jobs server side (example via PHP or other). Depending on what OS there are tutorials: Win , Nix

    第一种方式要求您具有更改cron-jobs服务器端的访问权限和权限(例如通过PHP或其他方式)。根据操作系统有什么教程:Win,Nix

  • 2nd way will do something close to what you want but without the minutes precision, you will loose at max 2 minutes each cycle. (see exaplanation below).

    第二种方式将做一些接近你想要的东西,但没有分钟精度,你将在每个周期最多2分钟松动。 (见下面的exaplanation)。

1st Way perfect way

  • As soon as the user hit the form create a unique cron-task for that user using the desired datatime.
  • 只要用户点击表单,就会使用所需的数据时间为该用户创建一个唯一的cron-task。

if you don't have those privileges you can use 3d part service like www.easycron.com they also offer a Free version with limited query. they also provide a REST API method to manage (CRUDE) cron-tasks.

如果你没有这些权限,你可以使用像www.easycron.com这样的3d部分服务,他们也提供有限查询的免费版本。他们还提供REST API方法来管理(CRUDE)cron-tasks。

2nd Way imperfect way

  • add a new VARCHAR column, i called it today with this we will ensure that the task will run only once per day.
  • 添加一个新的VARCHAR列,我今天调用它,我们将确保该任务每天只运行一次。

-

+----+---------+----------+------------+--------+----------+
| iD | timeDay | timeHour | timeMinute | postiD |   today  |
+--------------------------------------+--------+----------+
| 1  | *       | 9        | 0          | 21     | 30-05-04 |
|----|---------|----------|------------|--------|----------+
| 2  | *       | 10       | 30         | 22     |          |
|----|---------|----------|------------|--------|----------+
| 3  | *       | 11       | 0          | 23     |          |
+----|---------+----------+------------+--------+----------+
  • after that create a php file i called it crontask.php we will call it each 5 minutes

    之后创建一个我称之为crontask.php的php文件,我们将每隔5分钟调用一次

  • add this to your cronjob panel:

    将此添加到您的cronjob面板:

  • 0,5 * * * * /usr/bin/php /www/virtual/username/crontask.php > /dev/null 2>&1

    0,5 * * * * / usr / bin / php /www/virtual/username/crontask.php> / dev / null 2>&1

  • in the crontask.php file

    在crontask.php文件中

-

<?php
// include() Database Config file here with mysql_connect etc...
// include() the required files ex. the file where myFunction reside...

$cron_cycle = 5; // set it equal to what used in cron command-line
$today = date('Y-m-d');
if($result = mysql_query("SELECT * FROM postDataTime WHERE today != '{$today}'")){
    while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) { 
        $postID = $row['postID'];
        $timeHour = (int) $row['timeHour'];
        $current_hours = (int) date('H'); // current hours
        $current_minutes = (int) date('i'); // current minutes
        $timeMinute = (int) $row['timeMinute'];
        // force to run at the closest cycle
        $timeMinute = ($timeMinute % $cycle === 0) ? $timeMinute : toCloser($timeMinute, $cron_cycle); 
        if( $current_hours === $timeHour && $current_minutes === $timeMinute ){
            // ensure that we have already runned a cron for this user...
            mysql_query("UPDATE postDataTime SET today = '{$today}' WHERE postID = '{$postID}'");
            myFunction($postID);
        }
    }
}
function toCloser($n,$x=5) {
    $j = (round($n)%$x === 0) ? round($n) : (round(($n+$x/2)/$x)*$x);
    return ($j-$n) >= round($x/2) ? ($j-$x) : $j;
}

?>

Explanation of the function:

Assuming that the cron shedule runs each 5 minutes, lat's say we are at 20:00 o'clock, now the cron will run at 20:05, 20:10, 20:15, 20:20 and so on...

假设cron shedule每5分钟运行一次,lat表示我们在20:00,现在cron将在20:05,20:10,20:15,20:20运行,依此类推......

then assuming in our DB we have those time

然后在我们的数据库中假设我们有那些时间

Jonh  : 20:05, 
Mario : 20:32, 
luke  : 20:48, 
David : 20:57, 
Jimmy : 20:06, 
Eddy  : 20:16

when the script checks against those times it will run as below:

当脚本检查时,它将运行如下:

at 20:05 -> run 20:05 Jonh, 20:06 Jimmy
at 20:10 -> run null
at 20:15 -> run 20:16 Eddy
at 20:20 -> run null
and so on....

As you see you would loose in the worst case 2 minutes each time. I think it's fair enough! ;)

如你所见,在最糟糕的情况下你每次都会松开2分钟。我认为这很公平! ;)

#2


4  

Cron tasks require you to preset the times at which they run, they cannot (yes you could hack this by having a script which edits your crontab, but I would not say that is a very good idea) have their time to run decided dynamically. This means you essentially have two options:

Cron任务要求你预设他们运行的时间,他们不能(是的,你可以通过编写你的crontab的脚本来破解它,但我不会说这是一个非常好的主意)有时间运行决定动态。这意味着您基本上有两个选择:

1) Set a cronjob to run every minute and use a temp file which you touch to tell the last time that it ran one of the scheduled tasks Each time that it runs it checks if there was a task to run in between the last timestamp of your temp file and the current time, and if there is it runs the task. This is a gross but simple solution.

1)设置一个cronjob运行每分钟使用的触摸告诉最后一次,它跑的计划任务之一,它运行时,它会检查是否有到最后的时间戳之间运行任务每次临时文件你的临时文件和当前时间,如果有,它运行任务。这是一个粗略但简单的解决方案。

2) Don't use cron. Create a daemon which checks what times tasks need to be run and puts them into a priority queue, then it pops the earliest element and sleeps until it is time to run that task. It runs the task and reinserts it to be run 24 hours in the future and repeats. This solution is by far more elegant, but it also requires more work.

2)不要使用cron。创建一个守护程序,它检查需要运行任务的时间并将它们放入优先级队列,然后它会弹出最早的元素并休眠,直到运行该任务为止。它运行任务并重新插入它以便将来24小时运行并重复。这种解决方案更加优雅,但也需要更多的工作。

#3


2  

It is possible to set up a cron job that runs every minute and when triggered it checks what jobs are scheduled for that moment.

可以设置每分钟运行的cron作业,并在触发时检查当前计划的作业。

As a simple idea which could be easily modified to push through the run time details for a particular script if you wanted:-

作为一个简单的想法,可以很容易地修改,以便在需要时推送特定脚本的运行时详细信息: -

<?php

include '/core/config.php');

// Test script to allow jobs to be set up (cron style) on a database, but with the addition that jobs can be made
// dependent on other jobs completing first.
// Currently does not support jobs being dependent on more than one parent job.
// It uses a database of 2 tables. One for servers and the other for jobs.
// The server is selected as the one that matches the value of php_uname('n') (hence this can be run on many servers accessing a single database and only executing jobs for the particular server an instance is running on)
// Time ranges are specified in the same way as on CRON jobs:-
//  *   = no restriction based on that field
//  x   = when the value of that time parameter matches x
//  /x  = every x of that field (ie, mod current of that field by x and match if result is 0)
//  x-y = when the value of that time parameter is between x and y
//  x,y = when the value of the time parameter matches x or y (or z, etc)
// The script field on the scheduling table contains the script / command to be executed. For example if a php script then it might be 'php /usr/webdata/cron_scripts/some_script.php
// Parentid is the id of a job that must have finished before the job is executed.

class scheduling extends core_class
{

    public $connections;
    private $db;

    private $year;
    private $month;
    private $day;
    private $hour;
    private $minute;
    private $second;
    private $day_of_week;
    private $background_kick_off = true;

    private $completed_jobs = array();

    function __construct($connections, $background_kick_off = true) 
    {
        parent::__construct($connections);

        $this->background_kick_off = $background_kick_off;

        $this->debug_time_start();

        $this->connections = $connections;
        $this->db = new database($connections['EO'], 'em_scheduling');
        if (!$this->db->no_error)
            $this->error('E_ERROR', $this->db->error());

        $run_date = date('Y/m/d H:i:s w');

        list($date_part, $time_part, $this->day_of_week) = explode(' ', $run_date);
        list($this->year, $this->month, $this->day) = explode('/', $date_part);
        list($this->hour, $this->minute, $this->second) = explode(':', $time_part);     

        $this->find_jobs(0);
    }

    function find_jobs($parent_id)
    {
        $sql = "SELECT a.id, a.script, a.parent_id, a.minutes, a.hours, a.day_of_month, a.months, a.day_of_week, a.script_description, COUNT(DISTINCT b.id) AS child_count
                FROM scheduling a
                ON s.id = a.server_id
                LEFT OUTER JOIN scheduling b
                ON a.id = b.parent_id
                AND b.enabled = 1
                AND (b.minutes = '*' OR FIND_IN_SET('".$this->minute."', b.minutes) OR (SUBSTR(b.minutes, 1, 1) = '/' AND (".$this->minute." % CAST(SUBSTR(b.minutes, 2) AS UNSIGNED)) = 0) OR (b.minutes LIKE '%-%' AND ".$this->minute." BETWEEN CAST(SUBSTRING_INDEX(b.minutes, '-', 1) AS UNSIGNED) AND CAST(SUBSTRING_INDEX(b.minutes, '-', -1) AS UNSIGNED)))
                AND (b.hours = '*' OR FIND_IN_SET('".$this->hour."', b.hours) OR (SUBSTR(b.hours, 1, 1) = '/' AND (".$this->hour." % CAST(SUBSTR(b.hours, 2) AS UNSIGNED)) = 0) OR (b.hours LIKE '%-%' AND ".$this->hour." BETWEEN CAST(SUBSTRING_INDEX(b.hours, '-', 1) AS UNSIGNED) AND CAST(SUBSTRING_INDEX(b.hours, '-', -1) AS UNSIGNED)))
                AND (b.months = '*' OR FIND_IN_SET('".$this->month."', b.months) OR (SUBSTR(b.months, 1, 1) = '/' AND (".$this->month." % CAST(SUBSTR(b.months, 2) AS UNSIGNED)) = 0) OR (b.months LIKE '%-%' AND ".$this->month." BETWEEN CAST(SUBSTRING_INDEX(b.months, '-', 1) AS UNSIGNED) AND CAST(SUBSTRING_INDEX(b.months, '-', -1) AS UNSIGNED)))
                AND ((b.day_of_month = '*' OR FIND_IN_SET('".$this->day."', b.day_of_month) OR (SUBSTR(b.day_of_month, 1, 1) = '/' AND (".$this->day." % CAST(SUBSTR(b.day_of_month, 2) AS UNSIGNED)) = 0) OR (b.day_of_month LIKE '%-%' AND ".$this->day." BETWEEN CAST(SUBSTRING_INDEX(b.day_of_month, '-', 1) AS UNSIGNED) AND CAST(SUBSTRING_INDEX(b.day_of_month, '-', -1) AS UNSIGNED)))
                OR (b.day_of_week = '*' OR FIND_IN_SET('".$this->day_of_week."', b.day_of_week) OR (SUBSTR(b.day_of_week, 1, 1) = '/' AND (".$this->day_of_week." % CAST(SUBSTR(b.day_of_week, 2) AS UNSIGNED)) = 0) OR (b.day_of_week LIKE '%-%' AND ".$this->day_of_week." BETWEEN CAST(SUBSTRING_INDEX(b.day_of_week, '-', 1) AS UNSIGNED) AND CAST(SUBSTRING_INDEX(b.day_of_week, '-', -1) AS UNSIGNED))))
                WHERE a.parent_id = ".(int)$parent_id."
                AND a.enabled = 1
                AND (a.minutes = '*' OR FIND_IN_SET('".$this->minute."', a.minutes) OR (SUBSTR(a.minutes, 1, 1) = '/' AND (".$this->minute." % CAST(SUBSTR(a.minutes, 2) AS UNSIGNED)) = 0) OR (a.minutes LIKE '%-%' AND ".$this->minute." BETWEEN CAST(SUBSTRING_INDEX(a.minutes, '-', 1) AS UNSIGNED) AND CAST(SUBSTRING_INDEX(a.minutes, '-', -1) AS UNSIGNED)))
                AND (a.hours = '*' OR FIND_IN_SET('".$this->hour."', a.hours) OR (SUBSTR(a.hours, 1, 1) = '/' AND (".$this->hour." % CAST(SUBSTR(a.hours, 2) AS UNSIGNED)) = 0) OR (a.hours LIKE '%-%' AND ".$this->hour." BETWEEN CAST(SUBSTRING_INDEX(a.hours, '-', 1) AS UNSIGNED) AND CAST(SUBSTRING_INDEX(a.hours, '-', -1) AS UNSIGNED)))
                AND (a.months = '*' OR FIND_IN_SET('".$this->month."', a.months) OR (SUBSTR(a.months, 1, 1) = '/' AND (".$this->month." % CAST(SUBSTR(a.months, 2) AS UNSIGNED)) = 0) OR (a.months LIKE '%-%' AND ".$this->month." BETWEEN CAST(SUBSTRING_INDEX(a.months, '-', 1) AS UNSIGNED) AND CAST(SUBSTRING_INDEX(a.months, '-', -1) AS UNSIGNED)))
                AND ((a.day_of_month = '*' OR FIND_IN_SET('".$this->day."', a.day_of_month) OR (SUBSTR(a.day_of_month, 1, 1) = '/' AND (".$this->day." % CAST(SUBSTR(a.day_of_month, 2) AS UNSIGNED)) = 0) OR (a.day_of_month LIKE '%-%' AND ".$this->day." BETWEEN CAST(SUBSTRING_INDEX(a.day_of_month, '-', 1) AS UNSIGNED) AND CAST(SUBSTRING_INDEX(a.day_of_month, '-', -1) AS UNSIGNED)))
                OR (a.day_of_week = '*' OR FIND_IN_SET('".$this->day_of_week."', a.day_of_week) OR (SUBSTR(a.day_of_week, 1, 1) = '/' AND (".$this->day_of_week." % CAST(SUBSTR(a.day_of_week, 2) AS UNSIGNED)) = 0) OR (a.day_of_week LIKE '%-%' AND ".$this->day_of_week." BETWEEN CAST(SUBSTRING_INDEX(a.day_of_week, '-', 1) AS UNSIGNED) AND CAST(SUBSTRING_INDEX(a.day_of_week, '-', -1) AS UNSIGNED))))
                GROUP BY a.id, a.script, a.parent_id, a.minutes, a.hours, a.day_of_month, a.months, a.day_of_week
                ORDER BY child_count
                ";

        //echo "\r\n $sql \r\n";

        $this->db->query($sql) or die($this->db->error());

        $process_array = array();

        while ($row = $this->db->fetch_assoc())
        {
            $process_array[] = $row;
        }   

        foreach($process_array as $aProcess)
        {
            if ($this->background_kick_off and $aProcess['child_count'] == 0)
            {
                // No jobs to follow so just kick them off as a background task
                $this->launchBackgroundProcess($aProcess['script']);
                $completed_jobs[$aProcess['id']] = $aProcess['script_description'];
            }
            else
            {
                passthru($aProcess['script'].'', $return_var);
                if ($return_var == 0)
                {
                    $completed_jobs[$aProcess['id']] = $aProcess['script_description'];
                    $this->find_jobs($aProcess['id']);
                }
            }
        }
    }

    private function launchBackgroundProcess($call) 
    {

        // Windows
        if($this->is_windows())
        {
            pclose(popen('start /b '.$call, 'r'));
        }

        // Some sort of UNIX
        else 
        {
            pclose(popen($call.' /dev/null &', 'r'));
        }
        return true;
    }

    private function is_windows()
    {
        if(PHP_OS == 'WINNT' || PHP_OS == 'WIN32')
        {
            return true;
        }
        return false;
    }
}

$Scheduling = new scheduling($connections, true);

?>

Tables like this:-

像这样的表: -

CREATE TABLE IF NOT EXISTS `scheduling` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `enabled` tinyint(1) NOT NULL DEFAULT '1',
  `script` varchar(255) DEFAULT NULL,
  `parent_id` int(11) DEFAULT NULL,
  `minutes` varchar(5) DEFAULT NULL,
  `hours` varchar(5) DEFAULT NULL,
  `day_of_month` varchar(5) DEFAULT NULL,
  `months` varchar(5) DEFAULT NULL,
  `day_of_week` varchar(5) DEFAULT NULL,
  `script_description` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `parent_id` (`server_id`,`parent_id`,`enabled`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=15 ;

--
-- Dumping data for table `scheduling`
--

INSERT INTO `scheduling` (`id`,  `enabled`, `script`, `parent_id`, `minutes`, `hours`, `day_of_month`, `months`, `day_of_week`, `script_description`) VALUES
(1, 1, 'php download.php', 0, '*', '*', '*', '*', '*', 'Download files'),
(2, 1, 'php load_data.php', 1, '*', '*', '*', '*', '*', 'Load files to database'),
(3, 1, 'php file_test.php', 1, '*', '*', '*', '*', '*', NULL),
(4, 1, 'php file_test.php', 1, '*', '*', '*', '*', '*', NULL),
(5, 1, 'php file_test.php', 1, '*', '*', '*', '*', '*', NULL),
(6, 1, 'php file_test.php', 1, '*', '*', '*', '*', '*', NULL),
(7, 1, 'php file_test.php', 1, '*', '*', '*', '*', '*', NULL),
(8, 1, 'php file_test.php', 1, '*', '*', '*', '*', '*', NULL),
(9, 1, 'php file_test.php', 1, '*', '*', '*', '*', '*', NULL),
(10, 1, 'php file_test.php', 1, '*', '*', '*', '*', '*', NULL),
(11, 1, 'php file_test.php', 1, '*', '*', '*', '*', '*', NULL),
(12, 1, 'php file_test.php', 1, '*', '*', '*', '*', '*', NULL),
(13, 1, 'php file_test.php', 1, '*', '*', '*', '*', '*', NULL),
(14, 1, 'php file_test.php', 1, '*', '*', '*', '*', '*', NULL);

#4


2  

I am suggesting you create Cron Entries dynamically through a wrapper script which configure the cron entry to run your particular function when you actually wanted it to run.

我建议您通过包装器脚本动态创建Cron条目,该脚本配置cron条目以在您真正希望它运行时运行您的特定功能。

For your specific case here Below is what I would suggest :

针对您的具体案例以下是我的建议:

  1. Create a wrapper script And schedule it in Cron to run every Second.
  2. 创建一个包装器脚本并在Cron中安排它以每秒运行一次。

  3. This wrapper script will talk to MySQL and fetch the time at which a specific function is to run.
  4. 这个包装器脚本将与MySQL通信并获取运行特定函数的时间。

  5. Then it will Dynamically create a Cron Entry to run that function at that specific retrieved timestamp. You can dynamically add and remove the Cron Entry using the shell script. Please see references below for details.
  6. 然后它将动态创建一个Cron Entry以在该特定检索的时间戳上运行该函数。您可以使用shell脚本动态添加和删除Cron Entry。请参阅以下参考资料。

  7. Once your function is completed, There should be some indication like status stored somewhere maybe in your DB, or some file, so that the wrapper can get/know the status and remove the respective cron entry.
  8. 一旦你的功能完成,应该有一些指示状态存储在你的数据库或某个文件的某个地方,以便包装器可以获取/知道状态并删除相应的cron条目。

References
1. Create Cron Using Bash
crontab -l | { cat; echo "0 0 0 0 0 some entry"; } | crontab -
2. Delete/Automate Cron
crontab -l -u | grep -v <unique command> | crontab -

参考资料1.使用Bash crontab -l创建Cron { 猫; echo“0 0 0 0 0 some entry”; } | crontab - 2.删除/自动化Cron crontab -l -u | grep -v <唯一命令> | crontab -

#5


-2  

If I understand correctly, I think something like this may work for you, using the hours as keys to the function you want run, in a cron set to run every two hours:

如果我理解正确的话,我觉得这样的事情可能对你有用,使用小时作为你想要运行的功能的键,在每两个小时运行一次的cron中:

$listArray = Array(8=>"list1_function",10=>"list2_function");//etc...
$hour = Date("G");

if(array_key_exists($hour,$listArray))
{
    $listArray[$hour]();
}

function list1_function()
{
     echo "do list 1 stuff";
}

function list2_function()
{
     echo "do list 2 stuff";
 }

#1


2  

you have 2 ways, although only one will do exactly what you want to do;

你有2种方法,虽然只有一种方法可以完成你想做的事情;

  • 1st way requires that you have access and privileges to change cron-jobs server side (example via PHP or other). Depending on what OS there are tutorials: Win , Nix

    第一种方式要求您具有更改cron-jobs服务器端的访问权限和权限(例如通过PHP或其他方式)。根据操作系统有什么教程:Win,Nix

  • 2nd way will do something close to what you want but without the minutes precision, you will loose at max 2 minutes each cycle. (see exaplanation below).

    第二种方式将做一些接近你想要的东西,但没有分钟精度,你将在每个周期最多2分钟松动。 (见下面的exaplanation)。

1st Way perfect way

  • As soon as the user hit the form create a unique cron-task for that user using the desired datatime.
  • 只要用户点击表单,就会使用所需的数据时间为该用户创建一个唯一的cron-task。

if you don't have those privileges you can use 3d part service like www.easycron.com they also offer a Free version with limited query. they also provide a REST API method to manage (CRUDE) cron-tasks.

如果你没有这些权限,你可以使用像www.easycron.com这样的3d部分服务,他们也提供有限查询的免费版本。他们还提供REST API方法来管理(CRUDE)cron-tasks。

2nd Way imperfect way

  • add a new VARCHAR column, i called it today with this we will ensure that the task will run only once per day.
  • 添加一个新的VARCHAR列,我今天调用它,我们将确保该任务每天只运行一次。

-

+----+---------+----------+------------+--------+----------+
| iD | timeDay | timeHour | timeMinute | postiD |   today  |
+--------------------------------------+--------+----------+
| 1  | *       | 9        | 0          | 21     | 30-05-04 |
|----|---------|----------|------------|--------|----------+
| 2  | *       | 10       | 30         | 22     |          |
|----|---------|----------|------------|--------|----------+
| 3  | *       | 11       | 0          | 23     |          |
+----|---------+----------+------------+--------+----------+
  • after that create a php file i called it crontask.php we will call it each 5 minutes

    之后创建一个我称之为crontask.php的php文件,我们将每隔5分钟调用一次

  • add this to your cronjob panel:

    将此添加到您的cronjob面板:

  • 0,5 * * * * /usr/bin/php /www/virtual/username/crontask.php > /dev/null 2>&1

    0,5 * * * * / usr / bin / php /www/virtual/username/crontask.php> / dev / null 2>&1

  • in the crontask.php file

    在crontask.php文件中

-

<?php
// include() Database Config file here with mysql_connect etc...
// include() the required files ex. the file where myFunction reside...

$cron_cycle = 5; // set it equal to what used in cron command-line
$today = date('Y-m-d');
if($result = mysql_query("SELECT * FROM postDataTime WHERE today != '{$today}'")){
    while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) { 
        $postID = $row['postID'];
        $timeHour = (int) $row['timeHour'];
        $current_hours = (int) date('H'); // current hours
        $current_minutes = (int) date('i'); // current minutes
        $timeMinute = (int) $row['timeMinute'];
        // force to run at the closest cycle
        $timeMinute = ($timeMinute % $cycle === 0) ? $timeMinute : toCloser($timeMinute, $cron_cycle); 
        if( $current_hours === $timeHour && $current_minutes === $timeMinute ){
            // ensure that we have already runned a cron for this user...
            mysql_query("UPDATE postDataTime SET today = '{$today}' WHERE postID = '{$postID}'");
            myFunction($postID);
        }
    }
}
function toCloser($n,$x=5) {
    $j = (round($n)%$x === 0) ? round($n) : (round(($n+$x/2)/$x)*$x);
    return ($j-$n) >= round($x/2) ? ($j-$x) : $j;
}

?>

Explanation of the function:

Assuming that the cron shedule runs each 5 minutes, lat's say we are at 20:00 o'clock, now the cron will run at 20:05, 20:10, 20:15, 20:20 and so on...

假设cron shedule每5分钟运行一次,lat表示我们在20:00,现在cron将在20:05,20:10,20:15,20:20运行,依此类推......

then assuming in our DB we have those time

然后在我们的数据库中假设我们有那些时间

Jonh  : 20:05, 
Mario : 20:32, 
luke  : 20:48, 
David : 20:57, 
Jimmy : 20:06, 
Eddy  : 20:16

when the script checks against those times it will run as below:

当脚本检查时,它将运行如下:

at 20:05 -> run 20:05 Jonh, 20:06 Jimmy
at 20:10 -> run null
at 20:15 -> run 20:16 Eddy
at 20:20 -> run null
and so on....

As you see you would loose in the worst case 2 minutes each time. I think it's fair enough! ;)

如你所见,在最糟糕的情况下你每次都会松开2分钟。我认为这很公平! ;)

#2


4  

Cron tasks require you to preset the times at which they run, they cannot (yes you could hack this by having a script which edits your crontab, but I would not say that is a very good idea) have their time to run decided dynamically. This means you essentially have two options:

Cron任务要求你预设他们运行的时间,他们不能(是的,你可以通过编写你的crontab的脚本来破解它,但我不会说这是一个非常好的主意)有时间运行决定动态。这意味着您基本上有两个选择:

1) Set a cronjob to run every minute and use a temp file which you touch to tell the last time that it ran one of the scheduled tasks Each time that it runs it checks if there was a task to run in between the last timestamp of your temp file and the current time, and if there is it runs the task. This is a gross but simple solution.

1)设置一个cronjob运行每分钟使用的触摸告诉最后一次,它跑的计划任务之一,它运行时,它会检查是否有到最后的时间戳之间运行任务每次临时文件你的临时文件和当前时间,如果有,它运行任务。这是一个粗略但简单的解决方案。

2) Don't use cron. Create a daemon which checks what times tasks need to be run and puts them into a priority queue, then it pops the earliest element and sleeps until it is time to run that task. It runs the task and reinserts it to be run 24 hours in the future and repeats. This solution is by far more elegant, but it also requires more work.

2)不要使用cron。创建一个守护程序,它检查需要运行任务的时间并将它们放入优先级队列,然后它会弹出最早的元素并休眠,直到运行该任务为止。它运行任务并重新插入它以便将来24小时运行并重复。这种解决方案更加优雅,但也需要更多的工作。

#3


2  

It is possible to set up a cron job that runs every minute and when triggered it checks what jobs are scheduled for that moment.

可以设置每分钟运行的cron作业,并在触发时检查当前计划的作业。

As a simple idea which could be easily modified to push through the run time details for a particular script if you wanted:-

作为一个简单的想法,可以很容易地修改,以便在需要时推送特定脚本的运行时详细信息: -

<?php

include '/core/config.php');

// Test script to allow jobs to be set up (cron style) on a database, but with the addition that jobs can be made
// dependent on other jobs completing first.
// Currently does not support jobs being dependent on more than one parent job.
// It uses a database of 2 tables. One for servers and the other for jobs.
// The server is selected as the one that matches the value of php_uname('n') (hence this can be run on many servers accessing a single database and only executing jobs for the particular server an instance is running on)
// Time ranges are specified in the same way as on CRON jobs:-
//  *   = no restriction based on that field
//  x   = when the value of that time parameter matches x
//  /x  = every x of that field (ie, mod current of that field by x and match if result is 0)
//  x-y = when the value of that time parameter is between x and y
//  x,y = when the value of the time parameter matches x or y (or z, etc)
// The script field on the scheduling table contains the script / command to be executed. For example if a php script then it might be 'php /usr/webdata/cron_scripts/some_script.php
// Parentid is the id of a job that must have finished before the job is executed.

class scheduling extends core_class
{

    public $connections;
    private $db;

    private $year;
    private $month;
    private $day;
    private $hour;
    private $minute;
    private $second;
    private $day_of_week;
    private $background_kick_off = true;

    private $completed_jobs = array();

    function __construct($connections, $background_kick_off = true) 
    {
        parent::__construct($connections);

        $this->background_kick_off = $background_kick_off;

        $this->debug_time_start();

        $this->connections = $connections;
        $this->db = new database($connections['EO'], 'em_scheduling');
        if (!$this->db->no_error)
            $this->error('E_ERROR', $this->db->error());

        $run_date = date('Y/m/d H:i:s w');

        list($date_part, $time_part, $this->day_of_week) = explode(' ', $run_date);
        list($this->year, $this->month, $this->day) = explode('/', $date_part);
        list($this->hour, $this->minute, $this->second) = explode(':', $time_part);     

        $this->find_jobs(0);
    }

    function find_jobs($parent_id)
    {
        $sql = "SELECT a.id, a.script, a.parent_id, a.minutes, a.hours, a.day_of_month, a.months, a.day_of_week, a.script_description, COUNT(DISTINCT b.id) AS child_count
                FROM scheduling a
                ON s.id = a.server_id
                LEFT OUTER JOIN scheduling b
                ON a.id = b.parent_id
                AND b.enabled = 1
                AND (b.minutes = '*' OR FIND_IN_SET('".$this->minute."', b.minutes) OR (SUBSTR(b.minutes, 1, 1) = '/' AND (".$this->minute." % CAST(SUBSTR(b.minutes, 2) AS UNSIGNED)) = 0) OR (b.minutes LIKE '%-%' AND ".$this->minute." BETWEEN CAST(SUBSTRING_INDEX(b.minutes, '-', 1) AS UNSIGNED) AND CAST(SUBSTRING_INDEX(b.minutes, '-', -1) AS UNSIGNED)))
                AND (b.hours = '*' OR FIND_IN_SET('".$this->hour."', b.hours) OR (SUBSTR(b.hours, 1, 1) = '/' AND (".$this->hour." % CAST(SUBSTR(b.hours, 2) AS UNSIGNED)) = 0) OR (b.hours LIKE '%-%' AND ".$this->hour." BETWEEN CAST(SUBSTRING_INDEX(b.hours, '-', 1) AS UNSIGNED) AND CAST(SUBSTRING_INDEX(b.hours, '-', -1) AS UNSIGNED)))
                AND (b.months = '*' OR FIND_IN_SET('".$this->month."', b.months) OR (SUBSTR(b.months, 1, 1) = '/' AND (".$this->month." % CAST(SUBSTR(b.months, 2) AS UNSIGNED)) = 0) OR (b.months LIKE '%-%' AND ".$this->month." BETWEEN CAST(SUBSTRING_INDEX(b.months, '-', 1) AS UNSIGNED) AND CAST(SUBSTRING_INDEX(b.months, '-', -1) AS UNSIGNED)))
                AND ((b.day_of_month = '*' OR FIND_IN_SET('".$this->day."', b.day_of_month) OR (SUBSTR(b.day_of_month, 1, 1) = '/' AND (".$this->day." % CAST(SUBSTR(b.day_of_month, 2) AS UNSIGNED)) = 0) OR (b.day_of_month LIKE '%-%' AND ".$this->day." BETWEEN CAST(SUBSTRING_INDEX(b.day_of_month, '-', 1) AS UNSIGNED) AND CAST(SUBSTRING_INDEX(b.day_of_month, '-', -1) AS UNSIGNED)))
                OR (b.day_of_week = '*' OR FIND_IN_SET('".$this->day_of_week."', b.day_of_week) OR (SUBSTR(b.day_of_week, 1, 1) = '/' AND (".$this->day_of_week." % CAST(SUBSTR(b.day_of_week, 2) AS UNSIGNED)) = 0) OR (b.day_of_week LIKE '%-%' AND ".$this->day_of_week." BETWEEN CAST(SUBSTRING_INDEX(b.day_of_week, '-', 1) AS UNSIGNED) AND CAST(SUBSTRING_INDEX(b.day_of_week, '-', -1) AS UNSIGNED))))
                WHERE a.parent_id = ".(int)$parent_id."
                AND a.enabled = 1
                AND (a.minutes = '*' OR FIND_IN_SET('".$this->minute."', a.minutes) OR (SUBSTR(a.minutes, 1, 1) = '/' AND (".$this->minute." % CAST(SUBSTR(a.minutes, 2) AS UNSIGNED)) = 0) OR (a.minutes LIKE '%-%' AND ".$this->minute." BETWEEN CAST(SUBSTRING_INDEX(a.minutes, '-', 1) AS UNSIGNED) AND CAST(SUBSTRING_INDEX(a.minutes, '-', -1) AS UNSIGNED)))
                AND (a.hours = '*' OR FIND_IN_SET('".$this->hour."', a.hours) OR (SUBSTR(a.hours, 1, 1) = '/' AND (".$this->hour." % CAST(SUBSTR(a.hours, 2) AS UNSIGNED)) = 0) OR (a.hours LIKE '%-%' AND ".$this->hour." BETWEEN CAST(SUBSTRING_INDEX(a.hours, '-', 1) AS UNSIGNED) AND CAST(SUBSTRING_INDEX(a.hours, '-', -1) AS UNSIGNED)))
                AND (a.months = '*' OR FIND_IN_SET('".$this->month."', a.months) OR (SUBSTR(a.months, 1, 1) = '/' AND (".$this->month." % CAST(SUBSTR(a.months, 2) AS UNSIGNED)) = 0) OR (a.months LIKE '%-%' AND ".$this->month." BETWEEN CAST(SUBSTRING_INDEX(a.months, '-', 1) AS UNSIGNED) AND CAST(SUBSTRING_INDEX(a.months, '-', -1) AS UNSIGNED)))
                AND ((a.day_of_month = '*' OR FIND_IN_SET('".$this->day."', a.day_of_month) OR (SUBSTR(a.day_of_month, 1, 1) = '/' AND (".$this->day." % CAST(SUBSTR(a.day_of_month, 2) AS UNSIGNED)) = 0) OR (a.day_of_month LIKE '%-%' AND ".$this->day." BETWEEN CAST(SUBSTRING_INDEX(a.day_of_month, '-', 1) AS UNSIGNED) AND CAST(SUBSTRING_INDEX(a.day_of_month, '-', -1) AS UNSIGNED)))
                OR (a.day_of_week = '*' OR FIND_IN_SET('".$this->day_of_week."', a.day_of_week) OR (SUBSTR(a.day_of_week, 1, 1) = '/' AND (".$this->day_of_week." % CAST(SUBSTR(a.day_of_week, 2) AS UNSIGNED)) = 0) OR (a.day_of_week LIKE '%-%' AND ".$this->day_of_week." BETWEEN CAST(SUBSTRING_INDEX(a.day_of_week, '-', 1) AS UNSIGNED) AND CAST(SUBSTRING_INDEX(a.day_of_week, '-', -1) AS UNSIGNED))))
                GROUP BY a.id, a.script, a.parent_id, a.minutes, a.hours, a.day_of_month, a.months, a.day_of_week
                ORDER BY child_count
                ";

        //echo "\r\n $sql \r\n";

        $this->db->query($sql) or die($this->db->error());

        $process_array = array();

        while ($row = $this->db->fetch_assoc())
        {
            $process_array[] = $row;
        }   

        foreach($process_array as $aProcess)
        {
            if ($this->background_kick_off and $aProcess['child_count'] == 0)
            {
                // No jobs to follow so just kick them off as a background task
                $this->launchBackgroundProcess($aProcess['script']);
                $completed_jobs[$aProcess['id']] = $aProcess['script_description'];
            }
            else
            {
                passthru($aProcess['script'].'', $return_var);
                if ($return_var == 0)
                {
                    $completed_jobs[$aProcess['id']] = $aProcess['script_description'];
                    $this->find_jobs($aProcess['id']);
                }
            }
        }
    }

    private function launchBackgroundProcess($call) 
    {

        // Windows
        if($this->is_windows())
        {
            pclose(popen('start /b '.$call, 'r'));
        }

        // Some sort of UNIX
        else 
        {
            pclose(popen($call.' /dev/null &', 'r'));
        }
        return true;
    }

    private function is_windows()
    {
        if(PHP_OS == 'WINNT' || PHP_OS == 'WIN32')
        {
            return true;
        }
        return false;
    }
}

$Scheduling = new scheduling($connections, true);

?>

Tables like this:-

像这样的表: -

CREATE TABLE IF NOT EXISTS `scheduling` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `enabled` tinyint(1) NOT NULL DEFAULT '1',
  `script` varchar(255) DEFAULT NULL,
  `parent_id` int(11) DEFAULT NULL,
  `minutes` varchar(5) DEFAULT NULL,
  `hours` varchar(5) DEFAULT NULL,
  `day_of_month` varchar(5) DEFAULT NULL,
  `months` varchar(5) DEFAULT NULL,
  `day_of_week` varchar(5) DEFAULT NULL,
  `script_description` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `parent_id` (`server_id`,`parent_id`,`enabled`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=15 ;

--
-- Dumping data for table `scheduling`
--

INSERT INTO `scheduling` (`id`,  `enabled`, `script`, `parent_id`, `minutes`, `hours`, `day_of_month`, `months`, `day_of_week`, `script_description`) VALUES
(1, 1, 'php download.php', 0, '*', '*', '*', '*', '*', 'Download files'),
(2, 1, 'php load_data.php', 1, '*', '*', '*', '*', '*', 'Load files to database'),
(3, 1, 'php file_test.php', 1, '*', '*', '*', '*', '*', NULL),
(4, 1, 'php file_test.php', 1, '*', '*', '*', '*', '*', NULL),
(5, 1, 'php file_test.php', 1, '*', '*', '*', '*', '*', NULL),
(6, 1, 'php file_test.php', 1, '*', '*', '*', '*', '*', NULL),
(7, 1, 'php file_test.php', 1, '*', '*', '*', '*', '*', NULL),
(8, 1, 'php file_test.php', 1, '*', '*', '*', '*', '*', NULL),
(9, 1, 'php file_test.php', 1, '*', '*', '*', '*', '*', NULL),
(10, 1, 'php file_test.php', 1, '*', '*', '*', '*', '*', NULL),
(11, 1, 'php file_test.php', 1, '*', '*', '*', '*', '*', NULL),
(12, 1, 'php file_test.php', 1, '*', '*', '*', '*', '*', NULL),
(13, 1, 'php file_test.php', 1, '*', '*', '*', '*', '*', NULL),
(14, 1, 'php file_test.php', 1, '*', '*', '*', '*', '*', NULL);

#4


2  

I am suggesting you create Cron Entries dynamically through a wrapper script which configure the cron entry to run your particular function when you actually wanted it to run.

我建议您通过包装器脚本动态创建Cron条目,该脚本配置cron条目以在您真正希望它运行时运行您的特定功能。

For your specific case here Below is what I would suggest :

针对您的具体案例以下是我的建议:

  1. Create a wrapper script And schedule it in Cron to run every Second.
  2. 创建一个包装器脚本并在Cron中安排它以每秒运行一次。

  3. This wrapper script will talk to MySQL and fetch the time at which a specific function is to run.
  4. 这个包装器脚本将与MySQL通信并获取运行特定函数的时间。

  5. Then it will Dynamically create a Cron Entry to run that function at that specific retrieved timestamp. You can dynamically add and remove the Cron Entry using the shell script. Please see references below for details.
  6. 然后它将动态创建一个Cron Entry以在该特定检索的时间戳上运行该函数。您可以使用shell脚本动态添加和删除Cron Entry。请参阅以下参考资料。

  7. Once your function is completed, There should be some indication like status stored somewhere maybe in your DB, or some file, so that the wrapper can get/know the status and remove the respective cron entry.
  8. 一旦你的功能完成,应该有一些指示状态存储在你的数据库或某个文件的某个地方,以便包装器可以获取/知道状态并删除相应的cron条目。

References
1. Create Cron Using Bash
crontab -l | { cat; echo "0 0 0 0 0 some entry"; } | crontab -
2. Delete/Automate Cron
crontab -l -u | grep -v <unique command> | crontab -

参考资料1.使用Bash crontab -l创建Cron { 猫; echo“0 0 0 0 0 some entry”; } | crontab - 2.删除/自动化Cron crontab -l -u | grep -v <唯一命令> | crontab -

#5


-2  

If I understand correctly, I think something like this may work for you, using the hours as keys to the function you want run, in a cron set to run every two hours:

如果我理解正确的话,我觉得这样的事情可能对你有用,使用小时作为你想要运行的功能的键,在每两个小时运行一次的cron中:

$listArray = Array(8=>"list1_function",10=>"list2_function");//etc...
$hour = Date("G");

if(array_key_exists($hour,$listArray))
{
    $listArray[$hour]();
}

function list1_function()
{
     echo "do list 1 stuff";
}

function list2_function()
{
     echo "do list 2 stuff";
 }