Skip to content

Repository files navigation

Airbourne

Airbourne is a microservices-based flight booking platform composed of independently deployable Node.js services. It supports flight search and management, user authentication and authorization, ticket booking, and email reminders/notifications. An API Gateway provides rate limiting and routing to backend services. architecture

Architecture

  • API Gateway (API_gateway)
    • Express reverse proxy with rate limiting via express-rate-limit
    • Proxies /bookingservice to Booking Service (localhost:3002)
    • Auth check via Auth_service GET /api/v1/isAuthenticated before forwarding
    • Port: 3005
  • Auth Service (Auth_service)
    • User signup/signin, JWT auth, role-based checks
    • Sequelize + MySQL; Swagger UI at /api-docs
    • Port: from PORT env (commonly 3001)
  • Flights and Search (FlightsAndSearch)
    • CRUD for City, Airport, Airplane, Flight
    • Input validation middleware for creating flights
    • Sequelize + MySQL
    • Port: from PORT env
  • Reminder Service (reminderService)
    • Consumes AMQP messages for notifications and schedules email jobs
    • Nodemailer for email; Sequelize + MySQL
    • Port: from PORT env
  • Air Ticket Booking Service (AirTicketBookingService)
    • Booking workflows (entrypoint present, source not fully scanned here)
    • Port: from PORT env (commonly 3002)

Data Flow

  1. Client authenticates against Auth_service and receives a JWT.
  2. Requests to /bookingservice/** go through API_gateway where the JWT is verified by Auth_service.
  3. Gateway proxies authorized requests to Booking Service.
  4. Booking/flight changes may emit AMQP events; reminderService consumes and sends emails.

RabbitMQ (AMQP) Usage

Why RabbitMQ

  • Decouples services so producers (e.g., Booking) and consumers (Reminder) can scale independently.
  • Improves reliability and user experience by handling asynchronous work (emails, notifications) off the critical request path.
  • Adds resilience via queueing and retries; transient failures in consumers do not impact producers immediately.
  • Enables fan-out and selective routing using exchanges and binding keys.

Where It’s Used

  • Reminder Service subscribes to messages to create and send notifications.
    • Queue: notification_queue
    • Binding key (from env): EXCHANGE_BINDING_KEY (exposed as REMINDER_BINDING_KEY in code)
    • Exchange: EXCHANGE_NAME
    • Consumer setup: subscribeMessage(channel, 'notification_queue', EmailService.subscribeEvents, REMINDER_BINDING_KEY)
  • Producers (e.g., Booking Service and/or Flights Service) publish events such as ticket creation, payment success, or flight updates. These events are routed to the notification_queue for downstream processing by the Reminder Service.

Message Handling

  • The Reminder Service’s EmailService.subscribeEvents(payload) switches on payload.service to trigger actions:
    • CREATE_TICKET: persists a notification ticket for later sending
    • SEND_BASIC_MAIL: sends a basic email via Nodemailer
  • A scheduled job scans for PENDING tickets and dispatches emails, updating ticket status afterward.

RabbitMQ Environment

Add to .env in reminderService (and to producers where applicable):

  • MESSAGE_BROKER_URL (e.g., amqp://localhost)
  • EXCHANGE_NAME
  • EXCHANGE_BINDING_KEY (used as REMINDER_BINDING_KEY in code)

Technologies

  • Node.js, Express, Sequelize (MySQL)
  • JWT for auth (jsonwebtoken), password hashing (bcrypt)
  • Reverse proxy (http-proxy-middleware), logging (morgan)
  • Rate limiting (express-rate-limit)
  • Messaging via AMQP (amqplib)
  • Email via nodemailer
  • Dev tooling: nodemon, Swagger (swagger-jsdoc, swagger-ui-express)

Environment Variables

Create a .env file in each service with the following (adjust as needed):

  • Auth Service (Auth_service)

    • PORT (e.g., 3001)
    • JWT_key (secret for signing tokens)
    • DB_SYNC (optional; truthy to run sequelize.sync({ alter: true }))
    • Standard Sequelize environment via src/config/config.json
  • Flights and Search (FlightsAndSearch)

    • PORT
    • SYNC (truthy to run sequelize.sync({ force: true }))
    • Standard Sequelize environment via src/config/config.json
  • Reminder Service (reminderService)

    • PORT
    • EMAIL_ID, EMAIL_PASS
    • MESSAGE_BROKER_URL (e.g., amqp://localhost)
    • EXCHANGE_NAME
    • EXCHANGE_BINDING_KEY (used as REMINDER_BINDING_KEY in code)
    • Standard Sequelize environment via src/config/config.json
  • API Gateway (API_gateway)

    • Typically no .env needed; update target URLs in index.js if changed
  • Air Ticket Booking Service (AirTicketBookingService)

    • PORT
    • Database and any AMQP config (follow the pattern from other services)

Database Configuration

For services using Sequelize, create src/config/config.json:

{
  "development": {
    "username": "root",
    "password": "<password>",
    "database": "<db_name>",
    "host": "127.0.0.1",
    "dialect": "mysql"
  }
}

Initialize databases per service:

npx sequelize db:create
# Optional during development
DB_SYNC=true node src/index.js

Services: Endpoints and Ports

API Gateway (3005)

  • GET /home → health check
  • Proxies /bookingservice/** to http://localhost:3002/** after calling Auth_service GET http://localhost:3001/api/v1/isAuthenticated with header x-access-token
  • Rate limit: 5 requests per 2 minutes per IP

Auth Service (PORT, default 3001)

  • Base path: /api/v1
  • POST /signup → body: { email, password }
  • POST /signin → body: { email, password } → returns token
  • GET /isAuthenticated → header: x-access-token
  • GET /dummy → quick OK
  • GET /isAdmin → body: { id }
  • GET /health → service health
  • GET /api-docs → Swagger UI

Flights and Search (PORT)

  • Base path: /api/v1
  • Cities
    • POST /city
    • GET /city/:id
    • GET /city
    • PATCH /city/:id
    • DELETE /city/:id
  • Airplanes
    • POST /airplane
    • GET /airplane/:id
    • GET /airplane
    • PATCH /airplane/:id
    • DELETE /airplane/:id
  • Airports
    • POST /airports
    • GET /airports/:id
    • GET /airports
    • PATCH /airports/:id
    • DELETE /airports/:id
  • Flights
    • POST /flights (requires body: flightNumber, airplaneId, departureAirportID, arrivalAirportId, arrivalTime, departureTime, price)
    • GET /flights
    • GET /flights/:id
    • PATCH /flights/:id
    • DELETE /flights/:id

Reminder Service (PORT)

  • Subscribes to AMQP queue notification_queue with binding key EXCHANGE_BINDING_KEY
  • POST /api/v1/tickets → create notification ticket
  • Scheduled job runner triggers email sends for PENDING tickets

Air Ticket Booking Service (PORT, default 3002)

  • Exposed via API Gateway at /bookingservice/**
  • Health: GET /health
  • Additional routes depend on implementation (follow existing service patterns)

Running Locally

Open four terminals and start each service after installing dependencies.

Install dependencies:

# In each service directory
npm install

Start services:

# API Gateway
node index.js

# Auth Service
npm start  # runs nodemon src/index.js

# Flights and Search
node src/index.js

# Reminder Service
node src/index.js

# Air Ticket Booking Service
npm start  # if nodemon config present; otherwise node src/index.js

Set headers when calling protected routes via Gateway:

# Example: calling booking service via gateway after signin
curl -H "x-access-token: <JWT_TOKEN>" http://localhost:3005/bookingservice/health

Development Notes & Expertise Highlights

  • Security: JWT-based auth; input validation for critical endpoints; role-check endpoint (/isAdmin).
  • Reliability: Rate limiting in gateway; structured error codes; health endpoints.
  • Scalability: Microservices with independent ports; AMQP-based decoupling for async tasks.
  • Observability: Request logging via morgan in gateway; Swagger documentation in Auth Service.
  • Database: Sequelize models and migrations for core domain entities; optional DB_SYNC/SYNC modes for iterative dev.
  • Messaging: Centralized message queue consumption in Reminder Service with pluggable handlers (subscribeEvents).

Performance Testing & Load Analysis

The Airbourne platform has undergone comprehensive performance testing using k6 load testing framework with InfluxDB for metrics storage and Grafana for visualization. The testing suite includes four distinct test types to evaluate different aspects of system performance under various load conditions.

Testing Overview

Test Type Purpose Max Load Duration Key Focus
Load Test Baseline performance 100 VUs ~5 min Normal operation metrics
Soak Test Long-term stability 50 VUs 30 min Memory leaks, resource exhaustion
Stress Test Breaking point analysis 500 VUs ~6 min Maximum capacity limits
Spike Test Burst traffic handling 200 VUs ~50 sec Sudden load changes

Test Configuration

All tests follow a realistic user journey: Authentication → Flight Booking via API Gateway

// Example k6 configuration
export let options = {
  stages: [
    { duration: "30s", target: 20 },
    { duration: "1m", target: 20 },
    { duration: "30s", target: 50 },
    { duration: "1m", target: 50 },
    { duration: "30s", target: 100 },
    { duration: "1m", target: 100 },
    { duration: "30s", target: 0 },
  ],
  thresholds: {
    "http_req_duration{operation:booking}": ["p(95)<2000", "p(99)<5000"],
    "http_req_duration{operation:login}": ["p(95)<300"],
    "http_req_failed{operation:booking}": ["rate<0.05"],
    "checks{check:booking_success}": ["rate>0.95"],
  },
};

Performance Results Summary

Load Test Results (100 VUs, 5 minutes)

  • Total Requests: 13,133
  • Peak Throughput: ~42 requests/second
  • Booking p95 Latency: 39.09ms (Target: <2000ms)
  • Booking p99 Latency: 86.92ms (Target: <5000ms)
  • Failure Rate: 0.00% (Target: <5%)
  • Success Rate: 100.00%

🏃 Soak Test Results (50 VUs, 30 minutes)

  • Total Requests: 93,841
  • Sustained Throughput: ~38 requests/second
  • Booking p95 Latency: 66.69ms (Target: <2000ms)
  • Failure Rate: 0.00% over 30 minutes
  • Stability: No performance degradation detected

Stress Test Results (500 VUs, 6 minutes)

  • Total Requests: 45,465
  • Peak Throughput: ~124 requests/second
  • Booking p95 Latency: 1.25s (Target: <2000ms)
  • Failure Rate: 0.00% even at 5x normal load
  • Capacity: System stable up to 500 concurrent users

Spike Test Results (0→200 VUs, 50 seconds)

  • Total Requests: 2,975
  • Peak Throughput: ~52 requests/second
  • Booking p95 Latency: 58.02ms (Target: <2000ms)
  • Failure Rate: 0.00% during rapid load changes
  • Elasticity: Perfect handling of sudden traffic bursts

Key Performance Insights

  1. Exceptional Baseline Performance: The system consistently delivers sub-100ms p95 latency for booking operations, far exceeding the 2000ms threshold.

  2. Perfect Reliability: Across all test scenarios, the system maintained 0.00% failure rates, demonstrating robust error handling and fault tolerance.

  3. High Scalability: Successfully handled 500 concurrent users (5x normal load) while maintaining acceptable performance levels.

  4. Excellent Elasticity: Rapid load changes (0→200 VUs in 10 seconds) caused no performance degradation or failures.

  5. Long-term Stability: 30-minute soak test showed no memory leaks or resource exhaustion issues.

Running Tests Locally

# Install dependencies
npm --prefix tests install

# Run specific test
k6 run tests/booking_load_test.js

# Run with custom output
k6 run --out json=results.json tests/booking_load_test.js

Test Scripts & Documentation

  • Load Test Script: tests/booking_load_test.js
  • Detailed Reports: Available in docs/Load Test/, docs/Soak Test/, docs/Stress Test/, docs/Spike Test/
  • Visual Dashboards: Grafana screenshots included in each test directory
  • JSON Reports: Machine-readable results for further analysis

For comprehensive test setup, methodology, and detailed analysis, see the complete documentation in the docs/ directory.

Contributing

  • Use feature branches and conventional commits.
  • Add/adjust Swagger docs when changing Auth_service routes.
  • Ensure migrations are created for DB schema changes.

License

ISC

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages