post_status = future and pseudo-cron

classic Classic list List threaded Threaded
13 messages Options
Reply | Threaded
Open this post in threaded view
|

post_status = future and pseudo-cron

Ryan Boren
Here's a quick brain storm.  I think we have this simply be a queue of
actions with timestamps.

wp_schedule_event($timestamp, $action) {
        global $wp_event_queue;
        $args = array_slice(func_get_args(), 2);
        ...
        push event on to $wp_event_queue, maybe sort by timestamp.
}

Example:

wp_schedule_event($in_a_future_age, 'publish_future_post', $post_ID);

wp_cron() would be called from somewhere.  It would do a quick timestamp
quick to see if it is scheduled to run.  If so, it will loop through the
event queue looking for events that are due.  It will issue a
do_action() for every event whose time is up.

do_action('publish_future_post', $post_ID);
wp_remove_event('publish_future_post', $post_ID);

In default-filters.php would be this:

add_action('publish_future_post', 'wp_publish_post', $post_ID);

wp_publish_post() would set the post_status to publish and make sure
pingbacks and such are issued.

Ryan
_______________________________________________
wp-hackers mailing list
[hidden email]
http://lists.automattic.com/mailman/listinfo/wp-hackers
Reply | Threaded
Open this post in threaded view
|

Re: post_status = future and pseudo-cron

Owen Winkler
Ryan Boren wrote:
> Here's a quick brain storm.  I think we have this simply be a queue of
> actions with timestamps.

<snip>

Rephrasing my understanding:

A user publishes a post for a future date.
The post page adds that as a post_type = 'future' and sets the date for
the future.
The post page calls wp_schedule_event($post_date_gmt,
'publish_future_post', $post_ID); to set up the event.

A few days later, elsewhere in the code...

wp_cron() gets called based on a check of a timestamp (against what?)
from a location that is yet to be determined (shutdown?).
wp_cron() gets a list of the scheduled events (where was this stored?)
that have an execution time <= time().
Foreach item in that list, call the assigned plugin hook, with the post_ID.
The plugin hook for 'publish_future_post' has a default sink function
that publishes the specified post.

Ok.

Is the third parameter of wp_schedule_event() an all-purpose value?  Can
it be things other than a post_ID?  Can there be more parameters
(please)?  (I might like to schedule a check to see if a Link needed
updating, rather than a post, for example.)

Will the pseudocron require that regularly recurring events be
rescheduled during each execution?  Calling wp_remove_event() as
described could be a problem for recurring events.

Also, while I'm thinking about it...  What existing hooks will be fired
during all of this?  My thought is that save_post should fire on every
save, whether on future posts whose time hasn't come or posts that have
been published already.  publish_post should only ever be called once
under normal circumstances - when changing from post_status 'draft' to
'publish'.  I know others have opinions on this, and although I'm not
personally concerned about it (thus not attached to this suggestion),
it's a point for discussion.

Owen
_______________________________________________
wp-hackers mailing list
[hidden email]
http://lists.automattic.com/mailman/listinfo/wp-hackers
Reply | Threaded
Open this post in threaded view
|

Re: post_status = future and pseudo-cron

Mark Jaquith
On Feb 9, 2006, at 9:08 PM, Owen Winkler wrote:

> Will the pseudocron require that regularly recurring events be  
> rescheduled during each execution?  Calling wp_remove_event() as  
> described could be a problem for recurring events.

Ick, I hope not.  every_X_minutes, every_X_hours, every_X_ days is  
the way to go.  It's a bit more work initially (writing the backend  
for it), but it will make it much easier for plugin authors... no  
need to keep re-adding things and calculating times and stuff.
--
Mark Jaquith
http://txfx.net/


_______________________________________________
wp-hackers mailing list
[hidden email]
http://lists.automattic.com/mailman/listinfo/wp-hackers
Reply | Threaded
Open this post in threaded view
|

Re: post_status = future and pseudo-cron

Evan Broder
Mark Jaquith wrote:
> Ick, I hope not.  every_X_minutes, every_X_hours, every_X_ days is the
> way to go.  It's a bit more work initially (writing the backend for
> it), but it will make it much easier for plugin authors... no need to
> keep re-adding things and calculating times and stuff.
> --
> Mark Jaquith
> http://txfx.net/
If this is actually going to happen, would it not just be easier to
integrate Skippy's WP-Cron into wp-core? I mean, it sounds like that's
essentially what's being suggested, so why rewrite code that already exists?
_______________________________________________
wp-hackers mailing list
[hidden email]
http://lists.automattic.com/mailman/listinfo/wp-hackers
Reply | Threaded
Open this post in threaded view
|

Re: post_status = future and pseudo-cron

Peter Westwood
In reply to this post by Mark Jaquith
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Mark Jaquith wrote:

> On Feb 9, 2006, at 9:08 PM, Owen Winkler wrote:
>
>> Will the pseudocron require that regularly recurring events be
>> rescheduled during each execution?  Calling wp_remove_event() as
>> described could be a problem for recurring events.
>
> Ick, I hope not.  every_X_minutes, every_X_hours, every_X_ days is the
> way to go.  It's a bit more work initially (writing the backend for it),
> but it will make it much easier for plugin authors... no need to keep
> re-adding things and calculating times and stuff.

Indeed interval based pseudocron is much more powerful than only
allowing single events..

Single events are useful if you want to do something only once - maybe
schedule a theme change for your birthday perhaps?

Storing data with the cronjob itself e.g. post_ID or something else
seems a little dangerous - in the case of publishing future posts do we
really save that much by not querying the DB for the post_ID at publish
time - after all we will have to interact with the DB to do the publish
itself.

I like the idea of every_X_minutes but I think we also need to be able
to specify things like time of day for every_X_days - you want to be
able to schedule things for non-busy times.

An API more like the following may be more useful:

wp_schedule_single_event($unixtimestamp, 'function to call');

wp_schedule_repeating_event('interval-type','interval-amount','time-of-day/hour/week');

westi
- --
Peter Westwood
http://blog.ftwr.co.uk
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2 (MingW32)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFD7EQuVPRdzag0AcURAvLMAJ9FWmhx7o/ieTWgSD92rbk6Lk3rdgCgzvl3
+qHp3Se4uY1oMcKTzFcSsHo=
=mhpb
-----END PGP SIGNATURE-----

_______________________________________________
wp-hackers mailing list
[hidden email]
http://lists.automattic.com/mailman/listinfo/wp-hackers
Reply | Threaded
Open this post in threaded view
|

Re: post_status = future and pseudo-cron

Jeff Minard
Peter Westwood wrote:
> wp_schedule_repeating_event('interval-type','interval-amount','time-of-day/hour/week');


May I suggest we take a page from "The History of Every Unix Ever" and
at least make the psuedo cron scheduler something that people can learn
just once?

wp_schedule_repeating_event($minute, $hour, $dayofmonth, $month,
$dayofweek, $filter_to_activate);

The whole "* * * * *" thing.

Jeff
_______________________________________________
wp-hackers mailing list
[hidden email]
http://lists.automattic.com/mailman/listinfo/wp-hackers
Reply | Threaded
Open this post in threaded view
|

Re: post_status = future and pseudo-cron

Ryan Boren
Jeff Minard wrote:
> May I suggest we take a page from "The History of Every Unix Ever" and
> at least make the psuedo cron scheduler something that people can learn
> just once?
>
> wp_schedule_repeating_event($minute, $hour, $dayofmonth, $month,
> $dayofweek, $filter_to_activate);
>
> The whole "* * * * *" thing.

Hah!  I'm with you there.  Even after over a decade of dealing with
crontab files I still have to scratch my head and look at man pages
whenever I edit one.

Ryan
_______________________________________________
wp-hackers mailing list
[hidden email]
http://lists.automattic.com/mailman/listinfo/wp-hackers
Reply | Threaded
Open this post in threaded view
|

Re: post_status = future and pseudo-cron

Scott Merrill
In reply to this post by Jeff Minard
Jeff Minard wrote:

> Peter Westwood wrote:
>> wp_schedule_repeating_event('interval-type','interval-amount','time-of-day/hour/week');
>>
>
>
> May I suggest we take a page from "The History of Every Unix Ever" and
> at least make the psuedo cron scheduler something that people can learn
> just once?
>
> wp_schedule_repeating_event($minute, $hour, $dayofmonth, $month,
> $dayofweek, $filter_to_activate);
>
> The whole "* * * * *" thing.

If you need that level of precision, I think a real cron job is more
approrpiate.  Let's not re-invent the wheel.  Power users will know how
to use the system's cron facility, and non-power users are unlikely to
care about the elegance of any implementation we create.

My WP-Cron plugin is not at all precise.  It might be due to poor coding
on my part.  Everyone here is welcome to rip it apart and use whatever
bits they want for any future cron workalike.

--
[hidden email] | http://skippy.net/

gpg --keyserver pgp.mit.edu --recv-keys 9CFA4B35
506C F8BB 17AE 8A05 0B49  3544 476A 7DEC 9CFA 4B35
_______________________________________________
wp-hackers mailing list
[hidden email]
http://lists.automattic.com/mailman/listinfo/wp-hackers
Reply | Threaded
Open this post in threaded view
|

Re: post_status = future and pseudo-cron

Pete Prodoehl
In reply to this post by Jeff Minard
Jeff Minard wrote:

> Peter Westwood wrote:
>> wp_schedule_repeating_event('interval-type','interval-amount','time-of-day/hour/week');
>>
>
>
> May I suggest we take a page from "The History of Every Unix Ever" and
> at least make the psuedo cron scheduler something that people can learn
> just once?
>
> wp_schedule_repeating_event($minute, $hour, $dayofmonth, $month,
> $dayofweek, $filter_to_activate);
>
> The whole "* * * * *" thing.

+1 for reusing what exists...


Pete

_______________________________________________
wp-hackers mailing list
[hidden email]
http://lists.automattic.com/mailman/listinfo/wp-hackers
Reply | Threaded
Open this post in threaded view
|

Re: post_status = future and pseudo-cron

Jeff Minard
In reply to this post by Scott Merrill
Scott Merrill wrote:
> Power users will know how
> to use the system's cron facility, and non-power users are unlikely to
> care about the elegance of any implementation we create.

True, but this isn't for power users, it's for plugin authors. Unless
we're providing some kind of front end interface for scheduling generic
events to trigger. And even in those cases, we'd never present anything
more than:

------------------------------------------
Repeat Every:
  - Hour
  - Day
  - Mon, Tues, Weds, Thurs, Fri, Sat, Sun
  - 1st, 2nd, (etc) of month
------------------------------------------

Which is then up to the author to parse (easily) into a valid format for
repition.

Plus, it would allow us to create REAL crontab files out of actions,
should that ever become an option, with little hassle.

As for the precision, perhaps the minutely thing might be a little much
(mostly cause it's hard to guarantee a hit every single minute of the
day.) but I would still leave that in with a warning to authors that a *
rules on the minute option is not likely to work -- it'd still be handy,
though, for every hour, on the hour "0 * * * *"

Mostly I suggest doing it this way because then there is no confusion
about how to schedule events -- we can just say "It's exactly like a
cronjob definition."

Jeff
_______________________________________________
wp-hackers mailing list
[hidden email]
http://lists.automattic.com/mailman/listinfo/wp-hackers
Reply | Threaded
Open this post in threaded view
|

Re: post_status = future and pseudo-cron

Owen Winkler
In reply to this post by Ryan Boren
Ryan Boren wrote:

> Jeff Minard wrote:
>> May I suggest we take a page from "The History of Every Unix Ever" and
>> at least make the psuedo cron scheduler something that people can
>> learn just once?
>>
>> wp_schedule_repeating_event($minute, $hour, $dayofmonth, $month,
>> $dayofweek, $filter_to_activate);
>>
>> The whole "* * * * *" thing.
>
> Hah!  I'm with you there.  Even after over a decade of dealing with
> crontab files I still have to scratch my head and look at man pages
> whenever I edit one.

This is funny.

Ryan has assumed that the message is sarcastic; scheduling cron is
something he has to look up every time (me too!), and so should be made
simpler.

Skippy (in forked thread) has assumed that Jeff really meant to leverage
years of unix documentation to implement a wp_cron format that would be
familiar to unix users.  (And what is the crossover between unix admin
and PHP knowledge, I wonder?)

Personally, if I never have to look up how to do things like "Every 20
minutes on Saturday" in the cron man again, I'll be happier for it.

My vote - Forget the unix cron crap and make this simple:


function wp_schedule_event($timestamp, $hook)
{
        $args = array_slice(func_get_args(), 2);
        $crons = get_option('cron');
        $crons[$timestamp][$hook] = $args;
        ksort($crons);
        update_option('cron', $crons);
}

function wp_unschedule_event($timestamp, $hook)
{
        $crons = get_option('cron');
        unset($crons[$timestamp][$hook]);
        update_option('cron', $crons);
}

function wp_clear_scheduled_hook($hook)
{
        while($timestamp = next_scheduled('scheduled_hook'))
                wp_unschedule_event($timestamp, 'scheduled_hook');
}

function next_scheduled($hook)
{

        $crons = get_option('cron');
        foreach($crons as $timestamp => $cron) {
                if($timestamp <= time()) continue;
                if(isset($cron[$hook])) return $timestamp;
        }
        return false;
}

function spawn_crons()
// Executed frequently/periodically on page loads
{
        if (array_shift(array_keys(get_option('cron')) > time()) return;

// Mostly copied from spawn_pings()
        $ping_url = get_settings('siteurl')
                .'/wp-admin/execute-cron.php?check='
                .md5(DB_PASS . '187425');
        $parts = parse_url($ping_url);
        $argyle = @ fsockopen($parts['host'], $_SERVER['SERVER_PORT'], $errno,
$errstr, 0.01);
        if ( $argyle )
                fputs($argyle, "GET {$parts['path']}?time=".time()." HTTP/1.0\r\nHost:
{$_SERVER['HTTP_HOST']}\r\n\r\n");

}

... Then in execute-cron.php ...

require_once('../wp-config.php');
if (array_shift(array_keys(get_option('cron')) > time()) exit;
$crons = get_option('cron');
$newcrons = $crons;
foreach ($crons as $timestamp => $cronhooks) {
        if ($timestamp > time()) break;
        foreach($cronhooks as $hook => $args) {
                do_action($hook, $args);
        }
        unset($newcrons[$timestamp]);
}
update_option('cron', $newcrons);


Adding a new 20-minute repeating event would look like:

wp_schedule_event(time(), 'every_20_minutes', 0);
add_action('every_20_minutes', 'fn_every_20_minutes');
function fn_every_20_minutes($execount)
{
        // Do stuff.
        if (next_scheduled('every_20_minutes') !== false)
        wp_schedule_event(strtotime('+20 minutes'), 'every_20_minutes',
$execount++);
}


Or something.  (None of the above code has been shown to a parser.)

Owen

_______________________________________________
wp-hackers mailing list
[hidden email]
http://lists.automattic.com/mailman/listinfo/wp-hackers
Reply | Threaded
Open this post in threaded view
|

Re: post_status = future and pseudo-cron

Ryan Boren
Owen Winkler wrote:
> My vote - Forget the unix cron crap and make this simple:

Hear, hear.

I took what you provided and added some simple hourly and daily
recurrence.  More complicated recurrence can be done using the method
you suggested.  This was briefly tested and seemed to be fairly sane.

function wp_schedule_event($timestamp, $recurrence, $hook) {
        $args = array_slice(func_get_args(), 3);
        $crons = get_option('cron');
        $crons[$timestamp][$hook] = array('recur' => $recurrence, 'args' => $args);
        ksort($crons);
        update_option('cron', $crons);
}

function wp_unschedule_event($timestamp, $hook) {
        $crons = get_option('cron');
        unset($crons[$timestamp][$hook]);
        if ( empty($crons[$timestamp]) )
                unset($crons[$timestamp]);
        update_option('cron', $crons);
}

function wp_clear_scheduled_hook($hook) {
        while($timestamp = next_scheduled('scheduled_hook'))
                wp_unschedule_event($timestamp, 'scheduled_hook');
}

function next_scheduled($hook) {
        $crons = get_option('cron');
        if ( empty($crons) )
                return false;
        foreach($crons as $timestamp => $cron) {
                //if($timestamp <= time()) continue;
                if(isset($cron[$hook])) return $timestamp;
        }
        return false;
}

function spawn_cron() {
        if (array_shift(array_keys(get_option('cron'))) > time()) return;

        $cron_url = get_settings('siteurl') . '/wp-cron.php';
        $parts = parse_url($cron_url);
        $argyle = @ fsockopen($parts['host'], $_SERVER['SERVER_PORT'], $errno,
$errstr, 0.01);
        if ( $argyle )
                fputs($argyle, "GET {$parts['path']}?time=" . time() . '&check='
                . md5(DB_PASS . '187425') . " HTTP/1.0\r\nHost:
{$_SERVER['HTTP_HOST']}\r\n\r\n");
}

function wp_cron() {
        if (array_shift(array_keys(get_option('cron'))) > time())
                return;

        $crons = get_option('cron');
        $newcrons = $crons;
        foreach ($crons as $timestamp => $cronhooks) {
                if ($timestamp > time()) break;
                foreach($cronhooks as $hook => $args) {
                        do_action($hook, $args['args']);
                        $recurrence = $args['recur'];
                        if ( 'hourly' == $recurrence )
                                wp_schedule_event($timestamp + 3600, $recurrence, $hook, $args['args']);
                        else if ( 'daily' == $recurrence )
                                wp_schedule_event($timestamp + 86400, $recurrence, $hook,
$args['args']);

                        wp_unschedule_event($timestamp, $hook);
                }
        }
}

wp-cron.php looks like:

<?php
require_once('./wp-config.php');

if ( $_GET['check'] != md5(DB_PASS . '187425') )
        exit;

wp_cron();

?>

spawn_cron() causes some mischief on my server. Pages are slow to load
and apache2 sometimes bumps to 100% CPU until I kill it.  So, I'm just
calling wp_cron() from the shutdown hook for now.

Here's a sample plugin implementation:

add_action('test_cron', 'test_cron', 10, 2);

function test_cron($arg1, $arg2) {
         syslog(LOG_ERR, "Arg 1 is $arg1 and arg2 is $arg2");
}

if ( ! next_scheduled('test_cron') )
         wp_schedule_event(time(), 'hourly', 'test_cron', "hello", "world");
_______________________________________________
wp-hackers mailing list
[hidden email]
http://lists.automattic.com/mailman/listinfo/wp-hackers
Reply | Threaded
Open this post in threaded view
|

Re: post_status = future and pseudo-cron

Ryan Boren
future status:
http://trac.wordpress.org/ticket/2426

Pseudo-cron
http://trac.wordpress.org/ticket/2425

I already committed the first cut at pseudo-cron for #2425.  #2426 has
an in-the-works patch for post_status = future.

Ryan
_______________________________________________
wp-hackers mailing list
[hidden email]
http://lists.automattic.com/mailman/listinfo/wp-hackers