Ticket Booking: seat hold, payment ও expiry
Ticket Booking System
এই পাঠের সূচিপত্র
এই পাঠে যা শিখবেন
- Seat hold, expiry ও confirmed booking আলাদা করা
- Payment race এবং one-seat invariant রক্ষা
- Hot event admission ও fairness design
সমস্যা দিয়ে শুরু
Concert-এর এক আসন একসঙ্গে দুই customer কিনতে চান। একজন payment করছেন, আরেকজন seat map-এ available দেখছেন। Requirements: event/seat browsing, short hold, payment, confirm/cancel ও ticket verification। Resale এবং dynamic pricing প্রথম scope-এর বাইরে। Seat map সামান্য stale হতে পারে, কিন্তু একটি seat-এর দুটি active ownership চলবে না। Waiting room capacity রক্ষা করে; reservation invariant তার আলাদা কাজ।
সহজ করে বুঝি
Hold একটি time-bounded claim, confirmed ticket নয়। Seat authoritative state transaction বা atomic conditional update-এ বদলায়। Hold-এর owner token, expiry এবং version রাখলে old client বা late worker ভুল release করতে পারে না। Payment call lock ধরে দীর্ঘ সময় করা ঠিক নয়। Late success hold expire হওয়ার পরে এলে controlled policy—reacquire বা refund—দরকার; silently double-book নয়।
পরিচিত একটি উপমা
দোকানে শেষ বই অল্প সময়ের জন্য counter-এ আলাদা রাখা hold। Customer টাকা না দিলে বই ফেরত যায়। কিন্তু customer টাকা দিয়ে ফেরার মুহূর্তে অন্য clerk বই বিক্রি করে দিলে dispute হয়; expiry ও payment coordination দরকার।
নকশাটি দেখুন
Diagram লোড হচ্ছে…
Diagram-এর text flow দেখুন
flowchart TD U[Buyer] --> W[Waiting room and quota] W --> H[Atomic seat hold] H --> D[(Seat and reservation state)] H --> P[Payment attempt] P --> V[Verified result] V --> C[Conditional confirmation] E[Expiry worker] --> D C --> T[Unique ticket]
Admission সীমিত buyer checkout-এ ঢোকায়। Atomic hold database seat state পরিবর্তন করে। Payment result verified হলে current hold ownership ও state দেখে confirm করে। Expiry worker একই predicate মেনে release করে। Ticket unique booking reference বহন করে, scan endpoint repeated use কী করবে নির্ধারণ করুন। Hold validity browser clock নয়, server-authoritative time দিয়ে হিসাব হবে।
PHP ও Laravel-এ প্রয়োগ
Assumption: ২০ হাজার seat, launch-এ ১ লাখ visitor; সবাইকে transaction-এ ঢোকালে contention হবে। GET /events/{id}/seats, POST /holds, POST /holds/{id}/confirm; seats event_id+seat_no unique, reservations token unique,status,expires_at। নিচের fragment row lock-এ available seat ধরে; reservation record একই transaction-এ যোগ করার কথা ধরে নিন। Positive payment result এই snippet-এর বাইরে।
use App\Models\Seat;
use Illuminate\Support\Facades\DB;
DB::transaction(function () use ($seatId, $holdToken) {
$seat = Seat::query()->lockForUpdate()->findOrFail($seatId);
abort_unless($seat->status === 'available', 409);
$seat->update([
'status' => 'held',
'hold_token' => $holdToken,
'held_until' => now()->addMinutes(5),
]);
});সুবিধা, সীমাবদ্ধতা ও trade-off
Long hold buyer convenience বাড়ায়, scarce inventory আটকে রাখে। Short hold conversion কমাতে পারে। Waiting room overload কমায়, কিন্তু fairness, bot resistance ও queue token replay সামলাতে হয়। Strong per-seat transaction correctness দেয়; multi-seat contiguous booking larger lock set এবং deadlock risk আনে। Consistent lock ordering সাহায্য করে।
সাধারণ ভুল
- Cache seat map-কে booking authority বানানো।
- Hold expiry worker token/version না দেখে release করা।
- Payment success-এর পরে expired hold নিঃশর্ত confirm করা।
আরও একটু গভীরে
Payment provider unknown outcome হলে hold policy explicit রাখুন। Hold extension bounded এবং owner-only হওয়া উচিত। Database unique active booking constraint schema অনুযায়ী enforce করুন; historical cancelled booking-এর কারণে overly broad unique index legitimate resale আটকাতে পারে। Event-specific partitioning hot event-এর isolated capacity দিতে পারে। Ticket QR sensitive bearer artifact; scan authorization এবং replay handling দরকার।
মনে রাখুন
Ticket correctness-এর কেন্দ্র exclusive seat state; hold expiry, payment confirmation ও late worker একই authoritative rules মানবে।
নিজে চেষ্টা করুন
Expiry এবং payment callback একই সময়ে চলার concurrency test design করুন। Old expiry job নতুন hold release করতে পারে কি না যাচাই করুন। Bot traffic-এর জন্য waiting room ও per-user limit আলাদা পরিকল্পনা দিন।
নিজের বোঝা যাচাই করুন
1. Seat map available মানেই seat পাব?
না। Read view stale হতে পারে। Final hold authoritative transaction-এ সিদ্ধান্ত নেয়।
2. Hold কি ticket?
না। এটি temporary claim; payment ও confirmation transition-এর পরে ticket তৈরি হয়।
3. Expiry token কেন?
নতুন hold তৈরি হলে পুরোনো expiry job যেন সেটি release না করে। Ownership/version predicate দরকার।
4. Payment late হলে?
Product policy অনুযায়ী safe reacquire বা refund/reconciliation। Double booking করে সমস্যা লুকানো যাবে না।
5. Waiting room invariant রক্ষা করে?
Capacity ও fairness সাহায্য করে; এক seat এক ownership-এর database rule আলাদা দরকার।
আরও পড়ুন
এই পাঠের কুইজ
এই পাঠ থেকে ২টি প্রশ্ন। উত্তর দিয়ে ব্যাখ্যা দেখুন; অধ্যায়ের কুইজ আলাদাভাবে দিতে হবে।
এই পাঠের ২টি প্রশ্নের উত্তর দিন। পাস করতে দুটিই সঠিক হতে হবে।
জমা দেওয়ার পর সঠিক উত্তর ও ব্যাখ্যা দেখবেন। ফলাফল এই ব্রাউজারে সংরক্ষিত থাকবে। অনুশীলনের ফল অধ্যায় সম্পন্নের হিসাবে যোগ হয় না।
অগ্রগতি এই ব্রাউজারে সংরক্ষিত থাকে। শুধু পাঠ খুললে সম্পন্ন হয় না।