Make WordPress Core

Opened 3 years ago

Closed 3 years ago

#19700 closed defect (bug) (fixed)

Cron locking still not fixed in 3.3

Reported by: archon810 Owned by: ryan
Milestone: 3.4 Priority: normal
Severity: major Version: 3.3
Component: Cron API Keywords:
Focuses: Cc:


Re-opening the issue due to #17462 not fixing the problem once and for all.

This is what I posted as the last comment there before getting instructed to start a new ticket:

I don't think the bug is fixed. After posting a new post, I experienced a load spike (2 -> 20) and found this in the server status: http://minus.com/m1VuUQcxP

Additionally, today I stuck an error_log() statement into something that gets scheduled like this:

function my_publish_post($new_status, $old_status, $post) {
  wp_schedule_single_event(time()+150, 'my_feedburner_ping');
add_action( 'my_feedburner_ping', 'my_feedburner_ping' );
function my_feedburner_ping() {
  error_log(print_r(wp_remote_get("http://feedburner.google.com/fb/a/pingSubmit?bloglink=" . urlencode(home_url())), 1));

The log shows 2 events, on the exact same second. [Fri Dec 30 10:02:26 2011] [error] and so on. The HTTP headers are different, so I know 2 separate requests went out. And this is on a relatively slow eve of New Year's eve and a load of 2 on a quad-core machine. If the server was more loaded, we could probably see 5-10 of these.

The current solution doesn't seem to be truly atomic and multi-thread friendly.

Attachments (2)

19700.diff (1.4 KB) - added by ryan 3 years ago.
microtime( true )
19700.2.diff (1.9 KB) - added by ryan 3 years ago.
Preserve precision

Download all attachments as: .zip

Change History (9)

comment:1 @archon8103 years ago

  • Cc admin@… added

comment:2 @johnbillion3 years ago

  • Cc johnbillion@… added

comment:3 @dd323 years ago

It looks like we're still using time() for the unique cron lock? Perhaps changing this to microtime(true) (to get a float with milliseconds) or some other unique hash will help limit the occurrences of this happening. I'm thinking perhaps a Hash of some environmental variables unique to each user..

comment:4 @archon8103 years ago

Finer than a second resolution is definitely needed. Another option would be to look into mutexes using something like flock or semaphores (http://stackoverflow.com/questions/2921469/php-mutual-exclusion-mutex), but really, what I found working great before is microsecond time stored in a database, then doing an update on that time with a WHERE clause that takes the microsecond value from the SELECT and seeing how many rows are updated. If 1, then WHERE matched and you were the first one to grab the row. If 0, some other process already updated, and you shouldn't do anything. I'm sure the WP team can figure out the best solution.

comment:5 @ryan3 years ago

  • Milestone changed from Awaiting Review to 3.4

Using microtime and perhaps adding something unique to distinguish requests is on the todo for 3.4. Let's track that work with this ticket. Patches welcome.

A mutex gets messy when there is more than one server involved. I'd rather invest effort in allowing WP to use outside jobs systems. see #15148

@ryan3 years ago

microtime( true )

@ryan3 years ago

Preserve precision

comment:6 @ryan3 years ago

That patch results in a doing_cron transient that looks like: 1326050455.4191329479217529296875. The microtime float is cast to a string with sprintf() to avoid loss of resolution when passing it to db/cache and wp-cron.php. The lock tests compare doing_cron and doing_wp_cron as strings. We could add a few random digits to the end to make each request even more unique.

comment:7 @ryan3 years ago

  • Owner set to ryan
  • Resolution set to fixed
  • Status changed from new to closed

In [19722]:

Use microtime() for cron locks. fixes #19700

Note: See TracTickets for help on using tickets.