Webform submission limit does not work on multiple user submit

Created on 1 April 2025, 18 days ago

Problem/Motivation

When multiple users submit a submission limit webform at the same time ( a few 100 ms apart ) The submission limit is not respected.

Steps to reproduce

* Create a webform with a submission limit of lets say 3
* Use playwright or other script to simulate multiple users to submit on the same time. Or use multiple devices and click on the same time.
* You no have more submission than the limit

Enabling ajax on the webform makes it even worse

Proposed resolution

Maybe database locking to prevent exceeding the limit.

Remaining tasks

Research if we can use database locking, or something other to prevent exceeding the limit.

User interface changes

none

API changes

none

Data model changes

none

We can use a playwright script to simulate users clicking at the same time.
Even with logged in users this problem exists.

Here is a playwright example test that I use to test this.
I've only copied 2 users, but you can repeat this for many more users.
Users have to exist first.

Or you can make the webform public and leave out the logging in.

test.describe('Performance test webform', () => {
test(`Performance test 1`, async ({ page }) => {
await page.goto('/performance-webform');
await page.getByRole('textbox', { name: 'Username or email address. *' }).fill('user1');
await page.getByRole('textbox', { name: 'Password *' }).fill('#');
await page.getByRole('button', { name: 'login' }).click();
// await delay(5000);
await page.getByRole('button', { name: 'Submit' }).click();
});
test(`Performance test 2`, async ({ page }) => {
await page.goto('/performance-webform');
await page.getByRole('textbox', { name: 'Username or email address. *' }).fill('user2');
await page.getByRole('textbox', { name: 'Password *' }).fill('#');
await page.getByRole('button', { name: 'login' }).click();
await page.getByRole('button', { name: 'Submit' }).click();
});
});

I'm not using the latest webform as my site needs to be upgraded to D10+
I will test this on a clean install with the latest webform version and update this ticket today.
If I still can reproduce this I will try to make a patch for this.

🐛 Bug report
Status

Active

Version

6.2

Component

Code

Created by

🇳🇱Netherlands scuba_fly Netherlands, Vinkeveen

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @scuba_fly
  • 🇳🇱Netherlands scuba_fly Netherlands, Vinkeveen
  • 🇳🇱Netherlands scuba_fly Netherlands, Vinkeveen
  • 🇮🇳India abhishek@kumar

    Database-Level Locking

    // In WebformSubmissionForm.php or similar handler

    public function validateForm(array &$form, FormStateInterface $form_state) {
    $webform = $this->getWebform();

    // Get exclusive lock for this webform
    $lock_id = 'webform_submission_limit:' . $webform->id();
    if (!$this->lock->acquire($lock_id)) {
    $form_state->setErrorByName('', $this->t('Submission processing, please try again.'));
    return;
    }

    try {
    // Check submission limit with lock held
    if ($webform->hasSubmissionLimit() && $webform->isSubmissionLimitExceeded()) {
    $form_state->setErrorByName('', $webform->getSubmissionLimitExceededMessage());
    }
    }
    finally {
    $this->lock->release($lock_id);
    }
    }

  • 🇳🇱Netherlands scuba_fly Netherlands, Vinkeveen

    Adding a patch (WIP) but have to stop for today.

    I'll create a proper MR later and still have to do some testing.

  • 🇳🇱Netherlands scuba_fly Netherlands, Vinkeveen

    I'm still experiencing more submissions then the set limit in a simulation where 25 users submit the webform around the same time.

    At this point I'm thinking a custom handler that would write to the database in the validate might be better.
    So only users that would have a record in the database would be validated.
    The database would look like:
    [webform_id] [submittion_count]

    Then in the validate it would lock the database table, get the webform_id submission count. write the webform_id, and add added submission.
    Then after the user has submit the webform and drupal handled the submission. release the lock.

Production build 0.71.5 2024