Async Booking Workflow
Queue-based asynchronous flight booking workflow with real-time status updates and automatic ticket issuance.
Overview
Section titled “Overview”The async booking system provides:
- Immediate API response (<1s vs 60-90s synchronous)
- Queue-based processing with automatic retries
- Real-time notifications via FilamentPHP
- Instant ticket order support with 2-minute delay
- Status polling endpoint for frontend integration
Quick Start
Section titled “Quick Start”Dispatch Booking Job
Section titled “Dispatch Booking Job”use App\Jobs\AerticketCreateBookingJob;
AerticketCreateBookingJob::dispatch( fareId: 'fare-123', instantTicketOrder: true, // 2-minute delay for ticket issuance userId: auth()->id())->onQueue('aerticket-bookings');
return response()->json([ 'success' => true, 'message' => 'Booking is being created asynchronously', 'status' => 'processing',]);Poll Booking Status
Section titled “Poll Booking Status”GET /api/bookings/{ref}/retrieve-status
Response:{ "retrieve_status": "completed", "is_ready": true, "pnr_status": "TICKETED"}Architecture
Section titled “Architecture”Job Flow
Section titled “Job Flow”User Request │ ▼AerticketCreateBookingJob (aerticket-bookings queue) │ ├── Success ──► FlightBooking created │ │ │ ▼ │ AerticketRetrieveBookingJob (2-min delay if instant ticket) │ │ │ ▼ │ PNR status updated │ └── Failure ──► Retry (3 attempts) ──► Failed notificationQueue Configuration
Section titled “Queue Configuration”| Queue | Purpose | Priority |
|---|---|---|
aerticket-tickets | Ticket issuance | Highest |
aerticket-bookings | Booking creation | High |
aerticket-fastlane | Fastlane ticketing | High |
default | General tasks | Normal |
Job Configuration
Section titled “Job Configuration”AerticketCreateBookingJob
Section titled “AerticketCreateBookingJob”public int $tries = 3;public int $timeout = 120;public array $backoff = [30, 60, 180]; // 30s, 1m, 3mProperties:
fareId- The fare identifier from search/verifyinstantTicketOrder- Whether to auto-issue ticketsuserId- User who initiated the booking
Behavior:
- Creates booking via AerTicket API
- Stores FlightBooking record
- Dispatches retrieve job (with delay if instant ticket)
- Sends success/failure notification
AerticketRetrieveBookingJob
Section titled “AerticketRetrieveBookingJob”public int $tries = 3;public int $timeout = 60;public array $backoff = [10, 30, 60];Delay Logic:
- Instant ticket order: 2-minute delay before retrieve
- Manual ticketing: Immediate retrieve
Purpose:
- Updates PNR status from AerTicket
- Syncs ticket numbers if issued
- Updates
retrieve_statusfor polling
Status Tracking
Section titled “Status Tracking”Booking Status Values
Section titled “Booking Status Values”| Status | Description |
|---|---|
pending | Booking in progress |
confirmed | PNR created successfully |
ticketed | Tickets issued |
cancelled | Booking cancelled |
failed | Booking failed |
Retrieve Status Values
Section titled “Retrieve Status Values”| Status | Description |
|---|---|
pending | Retrieve not started |
in_progress | Retrieve job running |
completed | Retrieve successful |
failed | Retrieve failed |
Frontend Integration
Section titled “Frontend Integration”JavaScript Polling
Section titled “JavaScript Polling”async function pollBookingStatus(bookingRef) { const maxAttempts = 30; const interval = 5000; // 5 seconds
for (let attempt = 0; attempt < maxAttempts; attempt++) { const response = await fetch(`/api/bookings/${bookingRef}/retrieve-status`); const data = await response.json();
if (data.is_ready) { return data; }
await new Promise(resolve => setTimeout(resolve, interval)); }
throw new Error('Booking status check timed out');}
// Usagetry { const status = await pollBookingStatus('ABC123'); console.log('PNR Status:', status.pnr_status);} catch (error) { console.error('Failed to get booking status');}React Integration
Section titled “React Integration”function useBookingStatus(bookingRef: string) { const [status, setStatus] = useState<BookingStatus | null>(null); const [loading, setLoading] = useState(true);
useEffect(() => { const poll = async () => { try { const response = await fetch(`/api/bookings/${bookingRef}/retrieve-status`); const data = await response.json();
setStatus(data);
if (!data.is_ready) { setTimeout(poll, 5000); } else { setLoading(false); } } catch (error) { setLoading(false); } };
poll(); }, [bookingRef]);
return { status, loading };}Error Handling
Section titled “Error Handling”Job Failures
Section titled “Job Failures”public function failed(\Throwable $exception): void{ Log::error('Booking creation failed', [ 'fare_id' => $this->fareId, 'user_id' => $this->userId, 'error' => $exception->getMessage(), ]);
Notification::make() ->title('Booking Failed') ->body($exception->getMessage()) ->danger() ->sendToDatabase(User::find($this->userId));}Retry Logic
Section titled “Retry Logic”Jobs retry with exponential backoff:
- First retry: 30 seconds
- Second retry: 1 minute
- Third retry: 3 minutes
After all retries exhausted, job moves to failed_jobs table.
Monitoring
Section titled “Monitoring”Queue Status
Section titled “Queue Status”# Check queue status./vendor/bin/sail artisan queue:monitor
# View failed jobs./vendor/bin/sail artisan queue:failed
# Retry failed job./vendor/bin/sail artisan queue:retry {job_id}# Real-time logs./vendor/bin/sail artisan pail --filter="Aerticket"
# View booking-specific logs./vendor/bin/sail artisan pail --filter="AerticketCreateBookingJob"Database Schema
Section titled “Database Schema”flight_bookings Table
Section titled “flight_bookings Table”| Column | Type | Description |
|---|---|---|
booking_reference | VARCHAR | PNR locator |
booking_status | ENUM | confirmed, pending, etc. |
retrieve_status | ENUM | pending, completed, etc. |
pnr_status | VARCHAR | AerTicket PNR status |
ticket_status | ENUM | not_issued, issued, voided |
total_amount | DECIMAL | Total booking amount |
travel_date | DATE | Departure date |
return_date | DATE | Return date (nullable) |
Troubleshooting
Section titled “Troubleshooting”Booking Stuck in Pending
Section titled “Booking Stuck in Pending”- Check queue worker is running:
docker ps | grep queue- Check for failed jobs:
./vendor/bin/sail artisan queue:failed- View job exception:
./vendor/bin/sail artisan tinker>>> DB::table('failed_jobs')->latest()->first()->exception;Retrieve Not Completing
Section titled “Retrieve Not Completing”- Check retrieve job was dispatched:
./vendor/bin/sail artisan pail --filter="AerticketRetrieveBookingJob"- Manually trigger retrieve:
use App\Jobs\AerticketRetrieveBookingJob;
AerticketRetrieveBookingJob::dispatch( bookingReference: 'ABC123', bookingId: 123)->onQueue('aerticket-bookings');Related Documentation
Section titled “Related Documentation”- AerTicket Integration - Complete API reference
- Queue System - Queue infrastructure