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
- Quick Start
- Architecture
- API Endpoints
- Performance Optimizations
- Resilience Patterns
- Configuration
- Development
- Production Considerations
npm install# Production mode
npm start
# Development mode with auto-reload (Node 18+)
npm run devThe 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+)
- 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+
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
Base URL: http://localhost:3000
Returns list of all users.
Response Example
Status: 200 OK
[
{
"id": "1",
"name": "User Name",
"events": ["event-1", "event-2"]
}
]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"
}
]Returns list of all events.
Status: 200 OK
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"}'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)
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 โ
Implementation: utils/circuit-breaker.js
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++)
| 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. |
{
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
}| 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
Tip
Copy .env.example to .env and customize for your environment:
cp .env.example .envAvailable 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:
- Install dotenv:
npm install dotenv - Add to
services/index.js:require('dotenv').config() - Replace hardcoded values with
process.env.VARIABLE_NAME
Linting (ESLint):
# Check for issues
npm run lint
# Auto-fix issues
npm run lint:fixESLint Configuration:
- Extends:
eslint:recommended - Style: 2-space indentation, single quotes, semicolons required
- Environment: Node.js, ES2021
Warning
Current Status: Test framework not yet implemented (time constraints)
Recommended Setup:
npm install --save-dev jest supertestProposed Test Structure
tests/
โโโ unit/
โ โโโ circuit-breaker.test.js
โ โโโ logger.test.js
โโโ integration/
โ โโโ endpoints.test.js
โโโ setup.js
Priority Tests:
- โ Circuit breaker state transitions
- โ Parallel event fetching
- โ Error handling
- โ API contract validation
- Install dependencies:
npm install - Run in dev mode:
npm run dev(auto-reloads on file changes) - Lint before commit:
npm run lint:fix - Test manually: Use provided curl commands or Postman
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
๐ด High Priority
- Install dotenv package
- Load environment variables in application
- Validate required variables on startup
fastify.setErrorHandler((error, request, reply) => {
fastify.log.error(error);
reply.status(error.statusCode || 500).send({
error: error.message,
statusCode: error.statusCode || 500
});
});-
Request Validation
const addEventSchema = { body: { type: 'object', required: ['name', 'userId'], properties: { name: { type: 'string', minLength: 1 }, userId: { type: 'string', minLength: 1 } } } };
-
Structured Logging
- Replace console.log with structured JSON logging (pino is built into Fastify)
- Add request/response logging middleware
- Include correlation IDs for tracing
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
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)
| 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 ๐ |
| 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 |
๐ด 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
ISC
- ๐ด Fork the repository
- ๐ฟ Create a feature branch
- โ๏ธ Make your changes
- โ
Run
npm run lint:fix - ๐ฌ Submit a pull request