• Hello,

    I think I may have found a possible race condition in ajax_frontend_timing().

    The table wp_speedix_responses has a unique index on:

    • time_bucket
    • request_uri
    • request_type

    However, ajax_frontend_timing() currently does:

    $updated = $wpdb->query( ... UPDATE ... );
    
    if ( $updated === 0 ) {
        $wpdb->insert(...);
    }
    

    Occasionally I get the following database error:

    Duplicate entry '...' for key 'unique_bucket_uri'
    

    The stack trace points to:

    do_action('wp_ajax_nopriv_speedix_frontend_timing')
    WP_Hook->do_action()
    WP_Hook->apply_filters()
    Speedix->ajax_frontend_timing()
    

    I noticed that save_response_data() already uses INSERT ... ON DUPLICATE KEY UPDATE, while ajax_frontend_timing() uses an UPDATE followed by an INSERT.

    Could this be a race condition? For example:

    1. Two frontend timing beacons arrive almost simultaneously.
    2. Both UPDATE statements affect 0 rows.
    3. The first request performs the INSERT.
    4. The second request attempts the same INSERT and fails with the duplicate key error.

    I’m not certain this is the root cause, but it seems like a possible explanation.

    Has anyone else seen this, or is there a reason why ajax_frontend_timing() does not use an atomic upsert like save_response_data()?

You must be logged in to reply to this topic.