creating schedule task without Cron job

前端 未结 5 1271
野趣味
野趣味 2020-12-30 17:29

Scheduled task needs to be created but its not possible to use Cron job (there is a warning from hosting provider that \"running the cron Job more than once within a 45-minu

相关标签:
5条回答
  • 2020-12-30 17:56

    There are multiple ways of doing repetitive jobs. Some of the ways that I can think about right away are:

    1. Using: https://www.setcronjob.com/

    Use an external site like this to fire off your url at set intervals

    1. Using meta refresh. More here. You'd to have to open the page and leave it running.

    2. Javascript/Ajax refresh. Similar to the above example.

    3. Setting up a cron job. Most shared hosting do provide a way to set up cron jobs. Have a look at the cPanel of your hosting.

    0 讨论(0)
  • 2020-12-30 17:57

    I understand that this question is bit old but I stumbled on it a week ago with this very question and the best and secure option we found was using a Web Service.

    Our context:

    We have our system in both shared hosting and private clouds.

    We need that a script is activated once in a month (there are plans to create more schedules and to allow users to create some predetermined actions)

    Our system provides access to many clients, so, when anyone uses the system it calls for a Web Service via Ajax and doesn't care about the response (after all everything is logged in our database and must run without user interaction)

    What we've done is:

    1 - An ajax call is called upon access in any major screen.

    2 - The Web Service reads a schedule table on our database and calls whatever needs calling

    3 - To avoid many stacked Web Service calls we check datetime with an interval of 10 mins before actually performing any actions

    That's also a way to distribute the load balance and the schedules doesn't affect the system with user interaction.

    0 讨论(0)
  • 2020-12-30 17:58

    if you have shell access you could execute a php script via the shell

    something like this would be an endless loop, that would sleep 60 seconds execute, collect garbage and repeat until the end of time.

    while(true) {
        sleep(60);
        //script here
    
    
        //end your script
    }
    

    or you could do a "poor mans cron" with ajax or meta refresh. i've done it before. basically, you just place a redirect with either javascript or html's meta refresh at the beggining of your script. access this script from your browser, and just leave it open. it'll refresh every 60 seconds, just like a cronjob.

    yet another alternative to a cronjob, would be a bash script such as:

    #!/bin/bash
    while :
    
    do
    sleep 60
     wget http://127.0.0.1/path/to/cronjob.php -O Temp --delete-after
    
    done
    

    all this being said, you probably will get caught by the host and get terminated anyway.

    So your best solution:

    go and sign up for a 5-10 dollar a month vps, and say good bye to shared hosting and hello to running your own little server.

    if you do this, you can even stop using crappy php and use facebook's hhvm instead and enjoy its awesome performance.

    0 讨论(0)
  • 2020-12-30 18:05

    Option A

    An easy way to realize it would be to create a file/database entry containing the execution time of your php script:

    <?php
    // crons.php
    return [
        'executebackup.php' => 1507979485,
        'sendnewsletter.php' => 1507999485
    ];
    ?>
    

    And on every request made through your visitors you check the current time and if its higher you include your php script:

    <?php
    // cronpixel.php
    $crons = @include 'cache/crons.php';
    foreach ($crons as $script => $time) {
        if ($time < time()) {
            // create lock to avoid race conditions
            $lock = 'cache/' . md5($script) . '.lock';
            if (file_exists($lock) || !mkdir($lock)) {
                continue;
            }
            // start your php script
            include($script);
            // now update crons.php
            $crons[ $script ] += 86400; // tomorrow
            file_put_contents('cache/crons.php', '<?php return ' . var_export($crons, true) . '; ?' . '>')
            // finally delete lock
            rmdir($lock);
        }
    }
    header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
    // image data
    $im = imagecreate(1, 1);
    $blk = imagecolorallocate($im, 0, 0, 0);
    imagecolortransparent($im, $blk);
    // image output
    header("Content-type: image/gif");
    imagegif($im);
    // free memory
    imagedestroy($im);
    ?>
    

    Note: It will be rarily called on the exact second, because you do not know when your visitor will open your page (maybe 2 seconds later). So it makes sense to set the new time for the next day not through adding 86400 seconds. Instead use mktime.

    Option B

    This is a little project I realized in the past, that is similar to @r3wt 's idea, but covers race conditions and works on exact times like a cronjob would do in a scheduler without hitting the max_execution_time. And it works most of the time without the need to resurrect it (as done through visitors in Option A).

    Explanation: The script writes a lock file (to avoid race conditions) for the 15th, 30th, 45th and 60th second of a minute:

    // cron monitoring
    foreach ($allowed_crons as $cron_second) {
        $cron_filename = 'cache/' . $cron_second . '_crnsec_lock';
        // start missing cron requests
        if (!file_exists($cron_filename)) {
            cron_request($cron_second);
        }
        // restart interrupted cron requests
        else if (filemtime($cron_filename) + 90 < time()) {
            rmdir($cron_filename);
            cron_request($cron_second);
        }
    }
    

    Every time a lock file is missing the script creates it and uses sleep() to reach the exact second:

    if (file_exists($cron_filename) || !mkdir($cron_filename)) {
        return;
    }
    // add one minute if necessary
    $date = new DateTime();
    $cron_date = new DateTime();
    $cron_date->setTime($cron_date->format('H'), $cron_date->format('i'), $sec);
    $diff = $date->diff($cron_date);
    if ($diff->invert && $diff->s > 0) {
        $cron_date->setTime($cron_date->format('H'), $cron_date->format('i') + 1, $sec);
    }
    $diff = $date->diff($cron_date);
    // we use sleep() as time_sleep_until() starts one second to early (https://bugs.php.net/bug.php?id=69044)
    sleep($diff->s);
    

    After waking up again, it sends a request to itself through fopen():

    // note: filter_input returns the unchanged SERVER var (http://php.net/manual/de/function.filter-input.php#99124)
    // note: filter_var is unsecure (http://www.d-mueller.de/blog/why-url-validation-with-filter_var-might-not-be-a-good-idea/)
    $url = 'http' . isSecure() . '://' . filter_input(INPUT_SERVER, 'HTTP_HOST', FILTER_SANITIZE_URL) . htmlspecialchars($request_uri, ENT_QUOTES, 'UTF-8');
    $context = stream_context_create(array(
        'http' => array(
            'timeout' => 1.0
        )
    ));
    // note: return "failed to open stream: HTTP request failed!" because timeout < time_sleep_until
    if ($fp = @fopen($url, 'r', false, $context)) {
        fclose($fp);
    }
    rmdir($cron_filename);
    

    By that it calls itself infinitely and you are able to define different starting times:

    if (isset($_GET['cron_second'])) {
        if ($cron_second === 0 && !(date('i') % 15)) {
            mycron('every 15 minutes');
        }
        if ($cron_second === 0 && !(date('i') % 60)) {
            mycron('every hour');
        }
    }
    

    Note: It produces 5760 requests per day (4 per minute). Not much, but a cronjob uses much less ressources. If your max_execution_time is high enough you could change it to calling itself only once per minute (1440 requests/day).

    0 讨论(0)
  • 2020-12-30 18:08

    There's a free service at

    http://cron-job.org

    That lets you set up a nice little alternative.

    0 讨论(0)
提交回复
热议问题