Skip to content

pi-las/challenge-backend

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

1 Commit
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐ŸŽฏ Event Management System

Node.js Fastify License

A high-performance, resilient Event Management System featuring optimized query patterns and circuit breaker implementation for external service reliability.

Quick Start โ€ข API Docs โ€ข Performance โ€ข Resilience


๐Ÿ“‹ Table of Contents


๐Ÿš€ Quick Start

Prerequisites

Node.js npm

Installation

npm install

Running the Application

# Production mode
npm start

# Development mode with auto-reload (Node 18+)
npm run dev

The server will start on http://localhost:3000

Tip

Use npm run dev for development - it includes auto-reload on file changes (requires Node.js 18+)


๐Ÿ—๏ธ Architecture

Tech Stack

  • Framework: Fastify 4.28.0 - High-performance web framework
  • Testing: MSW (Mock Service Worker) 2.7.3 - API mocking for development
  • Runtime: Node.js 18+

Project Structure

challenge-backend/
โ”œโ”€โ”€ services/
โ”‚   โ””โ”€โ”€ index.js              # Main application & API endpoints
โ”œโ”€โ”€ utils/
โ”‚   โ”œโ”€โ”€ circuit-breaker.js    # Circuit breaker implementation
โ”‚   โ””โ”€โ”€ logger.js             # Logging utility
โ”œโ”€โ”€ mock-server/
โ”‚   โ”œโ”€โ”€ index.js              # MSW configuration
โ”‚   โ””โ”€โ”€ mocks/
โ”‚       โ””โ”€โ”€ user.json         # Mock data
โ”œโ”€โ”€ .env.example              # Environment variables template
โ”œโ”€โ”€ .eslintrc.json            # ESLint configuration
โ””โ”€โ”€ package.json

๐Ÿ“ก API Endpoints

Base URL: http://localhost:3000

GET /getUsers

Returns list of all users.

Response Example

Status: 200 OK

[
  {
    "id": "1",
    "name": "User Name",
    "events": ["event-1", "event-2"]
  }
]

GET /getEventsByUserId/:id

Returns all events for a specific user.

Parameters:

Name Type Description
id path User ID

Note

This endpoint is optimized with parallel fetching for maximum performance. See Performance Optimizations.

Response Example

Status: 200 OK

[
  {
    "id": "event-1",
    "name": "Event Name",
    "userId": "1"
  }
]

GET /getEvents

Returns list of all events.

Status: 200 OK


POST /addEvent

Creates a new event.

Important

This endpoint is protected by a circuit breaker to handle external service failures gracefully. See Resilience Patterns.

Request Body:

{
  "name": "Event Name",
  "userId": "3"
}

Responses:

Status Condition
200 OK Event created successfully
503 Service Unavailable Circuit breaker is open (service degraded)

Example Request:

curl -X POST http://localhost:3000/addEvent \
  -H 'Content-Type: application/json' \
  -d '{"name": "Team Meeting", "userId": "3"}'

โšก Performance Optimizations

Problem: N+1 Query Pattern in /getEventsByUserId

Original Implementation: The endpoint was fetching events sequentially in a loop:

for(let i = 0; i < userEvents.length; i++) {
    const event = await fetch('http://event.com/getEventById/' + userEvents[i]);
    const eventData = await event.json();
    eventArray.push(eventData);
}

Impact:

Scenario Response Time Complexity
10 events 5 seconds O(n ร— 500ms)
50 events 25 seconds O(n ร— 500ms)

Warning

This N+1 pattern causes linear performance degradation as event count increases!

Solution: Parallel Fetching with Promise.all()

const eventPromises = userEvents.map(eventId =>
    fetch('http://event.com/getEventById/' + eventId).then(resp => resp.json())
);
const eventArray = await Promise.all(eventPromises);

Results:

Scenario Before After Improvement
10 events 5s ~500ms โšก 90% faster
50 events 25s ~500ms โšก 98% faster

Complexity: O(500ms) - constant time regardless of event count! โœจ

๐Ÿ“ Key Implementation Decisions
  • โœ… Used native Promise.all() instead of external libraries (lodash, p-map) to minimize dependencies
  • โœ… Maintained backward compatibility - no API contract changes
  • โœ… Error handling: Fail-fast approach (if any event fetch fails, entire request fails)

๐Ÿ›ก๏ธ Resilience Patterns

Problem: External Service Failures

The /addEvent endpoint depends on an external API that fails under high load.

Note

Mock Service Behavior:

  • โœ… Succeeds for the first 5 requests
  • โŒ Fails with 503 for the next 10 requests
  • ๐Ÿ”„ Resets after 15 total requests

Without protection: Cascading failures and poor user experience โŒ

Solution: Custom Circuit Breaker Implementation

Implementation: utils/circuit-breaker.js

Circuit States

stateDiagram-v2
    [*] --> CLOSED
    CLOSED --> OPEN: 3+ failures in 30s
    OPEN --> HALF_OPEN: Wait timeout expires
    HALF_OPEN --> CLOSED: Request succeeds โœ“
    HALF_OPEN --> OPEN: Request fails (backoff++)
Loading
State Description Behavior
๐ŸŸข CLOSED Normal Operation All requests pass through to external service. Tracks failures within time window.
๐Ÿ”ด OPEN Service Degraded Rejects requests immediately without calling external service. Returns 503 with retry information.
๐ŸŸก HALF_OPEN Testing Recovery Allows limited test requests through. Success โ†’ CLOSED. Failure โ†’ OPEN with exponential backoff.

Configuration

{
  failureThreshold: 3,        // Open circuit after 3 failures
  failureWindowMs: 30000,     // Within 30-second window
  resetTimeoutMs: 10000,      // Initial retry after 10s
  maxResetTimeoutMs: 60000    // Max backoff of 60s
}

Exponential Backoff Strategy

Attempt Wait Time
1st โฑ๏ธ 10s
2nd โฑ๏ธ 20s
3rd โฑ๏ธ 40s
4th+ โฑ๏ธ 60s (capped)

Error Responses:

When circuit is OPEN:

{
  "success": false,
  "error": "Service temporarily unavailable",
  "message": "Event service is currently experiencing issues. Please try again later.",
  "retryAfter": 10,
  "circuitBreakerState": "OPEN"
}

Why Custom Implementation?

Per requirements, no third-party circuit breaker libraries (like opossum, cockatiel) were used. Benefits:

  • Full control over behavior
  • No additional dependencies
  • Educational value
  • Customizable for specific requirements

Key Features:

  • Detects 3+ failures within 30-second window
  • Exponential backoff with jitter protection
  • Gradual recovery testing (HALF_OPEN state)
  • Appropriate client error messages
  • Logging for observability

โš™๏ธ Configuration

Environment Variables

Tip

Copy .env.example to .env and customize for your environment:

cp .env.example .env

Available Variables:

Variable Default Description
PORT 3000 Server port
NODE_ENV development Environment (development/production)
EVENT_API_BASE_URL http://event.com External API base URL
CIRCUIT_BREAKER_FAILURE_THRESHOLD 3 Failures before opening circuit
CIRCUIT_BREAKER_FAILURE_WINDOW_MS 30000 Time window for counting failures (ms)
CIRCUIT_BREAKER_RESET_TIMEOUT_MS 10000 Initial retry timeout (ms)
CIRCUIT_BREAKER_MAX_RESET_TIMEOUT_MS 60000 Maximum backoff timeout (ms)

Note

Currently, environment variable support is configured but not yet implemented in code.

To fully enable:

  1. Install dotenv: npm install dotenv
  2. Add to services/index.js: require('dotenv').config()
  3. Replace hardcoded values with process.env.VARIABLE_NAME

๐Ÿ”ง Development

Code Quality

Linting (ESLint):

# Check for issues
npm run lint

# Auto-fix issues
npm run lint:fix

ESLint Configuration:

  • Extends: eslint:recommended
  • Style: 2-space indentation, single quotes, semicolons required
  • Environment: Node.js, ES2021

Testing

Warning

Current Status: Test framework not yet implemented (time constraints)

Recommended Setup:

npm install --save-dev jest supertest
Proposed Test Structure
tests/
โ”œโ”€โ”€ unit/
โ”‚   โ”œโ”€โ”€ circuit-breaker.test.js
โ”‚   โ””โ”€โ”€ logger.test.js
โ”œโ”€โ”€ integration/
โ”‚   โ””โ”€โ”€ endpoints.test.js
โ””โ”€โ”€ setup.js

Priority Tests:

  1. โœ… Circuit breaker state transitions
  2. โœ… Parallel event fetching
  3. โœ… Error handling
  4. โœ… API contract validation

Development Workflow

  1. Install dependencies: npm install
  2. Run in dev mode: npm run dev (auto-reloads on file changes)
  3. Lint before commit: npm run lint:fix
  4. Test manually: Use provided curl commands or Postman

๐Ÿšข Production Considerations

โœ… What's Been Implemented

Performance Optimization: Parallel query execution Resilience Pattern: Circuit breaker with exponential backoff Code Quality: ESLint configuration Documentation: Comprehensive README Environment Config: Template for environment variables Version Control: .gitignore configured

๐Ÿ”ฎ What Should Be Added (Time Permitting)

๐Ÿ”ด High Priority

1. Environment Variable Integration

  • Install dotenv package
  • Load environment variables in application
  • Validate required variables on startup

2. Error Handling Middleware

fastify.setErrorHandler((error, request, reply) => {
  fastify.log.error(error);
  reply.status(error.statusCode || 500).send({
    error: error.message,
    statusCode: error.statusCode || 500
  });
});
  1. Request Validation

    const addEventSchema = {
      body: {
        type: 'object',
        required: ['name', 'userId'],
        properties: {
          name: { type: 'string', minLength: 1 },
          userId: { type: 'string', minLength: 1 }
        }
      }
    };
  2. Structured Logging

    • Replace console.log with structured JSON logging (pino is built into Fastify)
    • Add request/response logging middleware
    • Include correlation IDs for tracing

5. Health Check Endpoints

fastify.get('/health', async () => ({ status: 'ok' }));
fastify.get('/ready', async () => {
  // Check external service connectivity
  // Check circuit breaker state
  return { ready: true };
});
๐ŸŸก Medium Priority
  • Rate Limiting - Prevent abuse
  • CORS Configuration - If serving browser clients
  • Metrics/Monitoring - Prometheus, Datadog
  • Containerization - Dockerfile, docker-compose.yml
  • CI/CD Pipeline - GitHub Actions, GitLab CI
๐ŸŸข Future Enhancements
  • Caching Layer - Redis for event data
  • Database Integration - PostgreSQL, MongoDB
  • Authentication/Authorization - JWT, OAuth
  • API Versioning - /v1/, /v2/
  • OpenAPI/Swagger Documentation

Deployment

Recommended Platforms:

  • Docker: Containerize with Alpine Node image
  • Cloud: AWS ECS, Google Cloud Run, Azure Container Apps
  • Platform: Heroku, Railway, Render

Production Checklist:

  • Enable HTTPS/TLS
  • Set NODE_ENV=production
  • Configure log aggregation
  • Set up monitoring/alerting
  • Configure auto-scaling
  • Enable health checks
  • Set up backup/disaster recovery
  • Security audit (npm audit, Snyk)

๐Ÿ“Š Performance Metrics

/getEventsByUserId Improvements

Events Before โฑ๏ธ After โšก Improvement ๐Ÿ“ˆ
5 2.5s ~500ms 80% faster ๐Ÿš€
10 5.0s ~500ms 90% faster ๐Ÿš€
20 10.0s ~500ms 95% faster ๐Ÿš€
50 25.0s ~500ms 98% faster ๐Ÿš€

/addEvent Resilience Comparison

Aspect โŒ Without Circuit Breaker โœ… With Circuit Breaker
Failures Cascading failures during outages Immediate feedback (503 with retry info)
Load No backoff โ†’ amplifies external service load Reduced load on failing service (fail-fast)
Recovery Manual intervention required Automatic recovery testing
UX Poor (timeouts, errors) Graceful degradation

๐Ÿ” Troubleshooting

Common Issues

๐Ÿ”ด Circuit breaker frequently opening

Cause: External service genuinely experiencing issues

Solution: Check external service status, adjust thresholds if needed

๐ŸŒ Slow /getEventsByUserId despite optimization

Cause: External API still has 500ms delay (intentional in mock)

Solution: This is expected behavior; optimization reduces the multiplier effect

โŒ ESLint errors on first run

Cause: ESLint not installed

Solution: Run npm install to install dev dependencies


๐Ÿ“„ License

ISC

๐Ÿค Contributing

  1. ๐Ÿด Fork the repository
  2. ๐ŸŒฟ Create a feature branch
  3. โœ๏ธ Make your changes
  4. โœ… Run npm run lint:fix
  5. ๐Ÿ“ฌ Submit a pull request

๐ŸŽ“ Acknowledgments

Built as part of a technical challenge to demonstrate:

Performance Optimization โ€ข Resilience Patterns โ€ข Production-Ready Configuration โ€ข Technical Documentation


โญ Found this helpful? Give it a star! โญ

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published