Steps to reproduce, on a single-capacity resource (for example the Refuge example):
- Open the resource calendar, click an available day, then click Book.
- You arrive on the registration webform. Press the browser Back button (the calendar page is cached).
- Click the same day again, then click Book.
Result: the visitor is stuck with "Slot N: 0 of 1 place(s) left, 1 requested." and cannot get back to the registration webform. On a fresh reload the held day is also shown full and cannot be selected, because a held booking consumes capacity and the visitor own hold counts against them.
Cause: the calendar Book always placed a brand new hold in a brand new order and never recorded the order in the session, so a second Book collided with the visitor own still-held place. The availability feed, being globally cached for scale, cannot know which places the visitor already holds.
Fix:
- The calendar Book is now re-entrant: it reuses the session order and holds only the shortfall for each target, so re-submitting a held pick resumes the order instead of colliding with itself. Nothing is released or moved by the calendar; whether a further booking is allowed is left to the resource constraint policies.
- The visitor own held places are published in a small client-read cookie so the calendar shows them as theirs (not full) and lets the visitor resume. The globally cached availability feed and the calendar page are never personalized server-side, so the high-traffic path is unchanged.
Covered by kernel tests: re-submitting a held pick resumes without colliding, a further target adds without releasing, and the cookie projection with its mutation-gated write.
Issue fork yoyaku-3612171
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #3
mably commentedOpened MR !64 against 1.x (mergeable, no conflicts). CI is running. Setting to Needs review.
Comment #6
mably commented