A demonstration application showcasing a reactive buffering pattern for handling high-frequency events in Angular applications using RxJS.
This project demonstrates a powerful pattern for efficiently handling high-frequency events in Angular applications. The buffer service aggregates events over time and processes them in batches, which is ideal for:
- Analytics tracking with reduced network overhead
- User interaction events (clicks, form changes, etc.)
- Telemetry data collection
- Any scenario where you want to batch events for performance
- Time-based buffering: Automatically sends events after a configurable period of inactivity
- Count-based buffering: Sends events when a specific number has accumulated
- Manual flush control: Force the buffer to process pending events immediately
- Real-time visualizations: See the buffer filling and timer countdown
- Configurable settings: Adjust buffer size and time parameters
- Comprehensive metrics: Track events processed, batch sizes, and processing status
The heart of this project is the EventsService
which leverages RxJS operators to efficiently manage event buffering:
bufferWhen
: Dynamically determines when to buffer eventsrace
: Allows multiple conditions to trigger a buffer flushtap
andswitchMap
: Process events in a reactive pipeline- Angular Signals: Provide reactive state management throughout the application
- Node.js (v18 or higher)
- npm (v8 or higher)
-
Clone the repository:
git clone https://github.com/natig4/angular-buffer-service.git cd angular-buffer-service
-
Install dependencies:
npm install
-
Start the development server:
ng serve
-
Open your browser and navigate to
http://localhost:4200
The demo allows you to generate three types of events (Primary, Secondary, and Tertiary) by clicking buttons. These events are sent to the EventsService
, which buffers them based on:
- Time threshold: Events are automatically sent after a configurable period (default: 5 seconds) of inactivity
- Count threshold: Events are sent when a certain number accumulate (default: 100 events)
- Manual flush: You can force the buffer to send events immediately with the "Flush Buffer Now" button
The UI visualizes:
- Current buffer fill level
- Time remaining until automatic send
- Event log showing individual events and batches
- Service metrics (events processed, batches sent, etc.)
The EventsService
is designed to be reusable in your own Angular applications. Here's how to implement it:
Add the events.service.ts
file to your project's services folder.
import { Component, inject } from "@angular/core";
import { EventsService } from "./services/events.service";
@Component({
selector: "app-root",
template: "...",
})
export class AppComponent {
private eventsService = inject(EventsService);
constructor() {
// Configure the buffer service
this.eventsService.configure({
delay: 3000, // 3 seconds inactivity before sending
batchSize: 50, // Send after 50 events
});
}
trackUserEvent(action: string) {
// Send event to buffer
this.eventsService.send({
name: action,
data: Date.now(),
});
}
forceSync() {
// Manually flush the buffer
this.eventsService.flushBuffer();
}
}
ngOnInit() {
this.eventsService.bufferedEvents$.subscribe(events => {
// Process the batch of events
this.analyticsService.sendBatch(events);
});
}
The buffer service uses a combination of RxJS operators to create an efficient event processing pipeline:
this.eventsSubject
.pipe(
// Store events in our currentBuffer variable
tap((event) => {
this.currentBuffer.push(event);
this.lastEventTimestamp = Date.now();
this.bufferSizeSubject.next(this.currentBuffer.length);
}),
// Buffer events based on either time delay, count threshold, or explicit flush
bufferWhen(() =>
race([
// Condition 1: Time-based buffer - triggers after DELAY ms of inactivity
this.eventsSubject.pipe(delay(this.DELAY)),
// Condition 2: Count-based buffer - triggers after collecting EVENTS_COUNT_BEFORE_SEND events
this.eventsSubject.pipe(bufferCount(this.EVENTS_COUNT_BEFORE_SEND)),
// Condition 3: Manual flush trigger
this.flushSubject.asObservable(),
])
),
// Process batched events
switchMap((events) => {
// In a real application, you would send these events to your backend
// ...
})
)
.subscribe({
// Handle success/error cases
});
The service accepts the following configuration options:
eventsService.configure({
delay: 5000, // Time in ms to wait before sending a batch (default: 5000)
batchSize: 100, // Number of events to collect before sending (default: 100)
});
The demo uses a simple event structure, but you can customize this to fit your specific needs:
// Example structure used in the demo
interface IEventDto {
name: string; // Event name/type
data: number; // Event data
}
// You can replace this with your own structure
interface YourCustomEventType {
eventType: string;
timestamp: Date;
userId: string;
properties: Record<string, any>;
// Any other fields you need
}
The buffer service can work with any event structure - simply modify the generic type or interface to match your requirements.
The application is built with a modern Angular architecture:
- Standalone Components: Each UI element is an independent, reusable component
- Signal-based State Management: Reactive state using Angular's signals API
- Service-Component Communication: Clean separation of concerns between services and components
- Computed Values: Derived state calculated from base signals
Using the buffer pattern can significantly reduce:
- Network requests: By grouping multiple events into a single request
- Server load: By reducing the number of connections and requests
- Client resource usage: By minimizing DOM updates and processing overhead
- Perceived latency: By handling events in the background without blocking the UI
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- The Angular team for creating an amazing framework
- The RxJS team for powerful reactive extensions