Skip to main content

Architecture

This page provides a comprehensive overview of the AsyncEndpoints architecture, including system components, data flow, and scalability considerations.

System Architecture Overview

AsyncEndpoints implements a producer-consumer pattern that separates request handling from processing. The architecture consists of multiple interconnected components that work together to provide asynchronous job processing capabilities.

Core Components

Job Store

The Job Store is the persistence layer that maintains job state and enables distributed processing:

  • Interface: IJobStore defines the storage contract
  • Implementations: In-memory store for development, Redis store for production
  • Responsibilities:
    • Create, read, update, and delete job records
    • Manage job state transitions
    • Handle job queuing and claiming mechanisms
    • Support job recovery operations

Job Manager

The Job Manager coordinates job state management and retry logic:

  • Interface: IJobManager provides job lifecycle management
  • Responsibilities:
    • Create new jobs from HTTP requests
    • Process job success and failure operations
    • Manage retry logic with exponential backoff
    • Handle job state transitions
    • Coordinate job claiming by workers

Background Services

The background services implement the producer-consumer pattern:

  • AsyncEndpointsBackgroundService: Main hosted service managing the job processing workflow
  • Job Producer: Creates jobs from pending HTTP requests
  • Job Consumer: Processes jobs from the queue
  • Job Processor: Executes job handler logic
  • Job Claiming Service: Manages job assignment to workers

HTTP Integration Layer

The HTTP integration layer provides endpoint mapping and request processing:

  • RouteBuilder Extensions: Map asynchronous endpoints using minimal APIs
  • Request Delegate: Processes HTTP requests and submits jobs
  • Context Builder: Preserves HTTP context information through job lifecycle

Component Interaction

The system follows this interaction pattern:

HTTP Request → RouteBuilder → Request Delegate → Job Manager → Job Store

Job Producer ←→ Job Consumer ←→ Job Processor
↓ ↓ ↓
Submit Job Claim Job Execute Handler
  1. HTTP Request Processing: When a client makes a request to an async endpoint, the RouteBuilder extension processes it
  2. Job Creation: The request delegate serializes the request and submits it to the Job Manager
  3. Storage: The Job Manager persists the job to the Job Store
  4. Job Production: The Job Producer discovers pending jobs in the store
  5. Job Consumption: The Job Consumer claims jobs for processing
  6. Job Execution: The Job Processor executes the appropriate handler
  7. Result Storage: Results are stored back in the Job Store

Job Lifecycle Flow

Jobs progress through a defined lifecycle that ensures proper state management:

  1. Queued: Job created and waiting for processing
  2. Scheduled: Job scheduled for delayed execution (with retry delays)
  3. InProgress: Currently being processed by a worker
  4. Completed: Successfully completed with result available
  5. Failed: Failed after all retry attempts exhausted
  6. Canceled: Explicitly canceled before completion

Data Flow Diagram

Client Request → HTTP Context → Job Object → Storage → Processing → Result

HTTP Context:
├── Request Body (serialized to payload)
├── HTTP Headers (preserved for handler access)
├── Route Parameters (preserved for handler access)
└── Query Parameters (preserved for handler access)

Job Object:
├── ID (unique identifier)
├── Name (job handler identifier)
├── Payload (serialized request data)
├── Status (current job state)
├── Retry Information (count, max retries, delay until)
├── Timestamps (created, started, completed, last updated)
├── Result/Error (processing result or error details)
├── Worker ID (current processing worker)
└── HTTP Context (headers, route params, query params)

Scalability Considerations

Concurrency Management

  • Worker Concurrency: Configurable maximum concurrency based on CPU count or custom settings
  • Queue Limits: Configurable maximum queue size to prevent system overload
  • Batch Processing: Configurable batch sizes for efficient processing

Distributed Processing

  • Redis Storage: Enables multiple application instances to share job queues
  • Job Claiming: Atomic job assignment prevents duplicate processing
  • Distributed Recovery: Automatic recovery of stuck jobs across instances

Performance Characteristics

  • Throughput: Determined by worker concurrency, processing time, and I/O characteristics
  • Latency: Job queuing is immediate; processing begins based on queue position
  • Memory Usage: Minimal for the core system; depends on queue sizes and storage implementation

Architecture Patterns

Producer-Consumer Pattern

The system implements a classic producer-consumer pattern where:

  • Producers create jobs from HTTP requests
  • Consumers process jobs from a queue
  • Channels provide efficient communication between components

Circuit Breaker Pattern

  • Queue size limits prevent system overload
  • Immediate rejection when queue is full
  • Client feedback for rejected requests

State Machine Pattern

  • Jobs follow a defined state transition model
  • Validation prevents invalid state transitions
  • Clear lifecycle from creation to completion or failure

Integration Points

With ASP.NET Core

  • Uses minimal APIs for endpoint mapping
  • Integrates with dependency injection
  • Leverages HTTP context for request information
  • Works with existing middleware pipeline

With Storage Systems

  • Abstract storage interface enables multiple backends
  • Consistent API across storage implementations
  • Efficient data structures for job management

This architecture provides a robust foundation for handling long-running operations asynchronously while maintaining system responsiveness and enabling horizontal scaling.