• I am editing to make a wordpress plugin made for ticket selling. It keeps track of the limit of a ticket with the help of options.

    If you buy a ticket and a payment is received add_action(processing_function) is called and the processing_function first retrieves the limit data with get_option, adds 1 to the desired itemID in the option and it will update it with update_option. The problem is however, if two people buy tickets at the same time, sometimes the limit is only updated with +1.

    I think this is because they retrieve the get_option at the same time and then we have a race condition since they both add +1 to the old value.

    How can you deal with this in WordPress? Is using options the correct way or is there another better way in which this can’t happen?

    Down here you can see a simplified version of the code (everything necessary except retrieving the POST data is in there)

    <?php
    
    function data_processing() {
    
      if ( (!$paid_not_necessary)) {
        return;
    }
    
    $current_item_limits = //POST DATA WITH THE AMOUNT THE CUSTOMER BOUGHT
    
    if (get_option('item_limits')) {
    
        $item_limits = unserialize(get_option('item_limits'));
    
        foreach ($current_item_limits as $key => $value) {
            $item_limits[$key] = isset($item_limits[$key]) ? $item_limits[$key] + $value['quantity'] : $value['quantity'];
        }
    
        update_option('item_limits', serialize($item_limits));
    }
    else {
    
        foreach ($current_item_limits as $key => $value) {
            $current_item_limits[$key] = $value['quantity'];
        }
    
        update_option('item_limits', serialize($current_item_limits));
    
    }
    
    }
    
    add_action('cust_after_submit', 'data_processing', 10, 0);
    
Viewing 1 replies (of 1 total)
  • Moderator Dion Hulse

    (@dd32)

    Meta Developer

    You should be able to look at the return value of the update_option() call to determine if the update was successful, however, using options to store things like number of tickets remaining isn’t likely the best option.

    update_option() returns false when $wpdb->update() returns a false-like value, $wpdb->update() returns the number of rows altered, so in the event of updating an option from 15 to 16, if the value is already 16 you should get a false value in response. You can detect that, decrease the count again and re-save.. but that’s not a fool-proof method either, you just end up with needing two requests to conflict to needing 3 or more.

    Using options to store these limits is probably not the ideal option though, you probably want to verify that there’s tickets available before processing the submission, so do something like counting the number of tickets sold and comparing it against the number that were avaialble. A custom database table would not be out of the question if you’re dealing with enough tickets or high enough request rate. If it’s for a low number of tickets or low request rate, you could also just not store a tickets_remaining counter but instead count the number of sold tickets and subtract that from the total tickets value on every page load.. not great, but combine that with a short-lived transient (effectively a time-limited option that automatically expires after x seconds) that gets deleted after every sale, it might not be a bad option.

    Also note, get_option() and update_option() handle the PHP serialization for you, you don’t need to serialize/unserialize the values first.. but save a serialized string, you’ll get a serialized string back (WordPress will double-seralize it in the database), so you can’t just remove it and expect it to work on an existing install.

Viewing 1 replies (of 1 total)
  • The topic ‘Race condition with add_action get_option set_option’ is closed to new replies.