in-memory-tracker v2.0.0
In-Memory Tracker
In-Memory Tracker is a lightweight, standalone JavaScript module designed for the deduplication, deferral, and change detection of events using an in-memory store. It is ideal for scenarios such as alert systems or logging tools—where you need fine‑grained control over duplicate events and adjustments when event details change.
Features
In-Memory Storage:
Manage event states entirely in memory, eliminating the need for external databases.Three-Level Identification:
Events are now tracked by a combination of:- Category: A high-level grouping (e.g.
authentication
). - ID: A specific identifier within that category (e.g. a user’s ID).
- Details: Detailed information about the event (e.g. IP address, failure reason).
A composite key (computed as an MD5 hash from category and ID) is used to uniquely track each record.
- Category: A high-level grouping (e.g.
Event Deduplication and Change Detection:
A details hash (computed from the sorted event details JSON) lets the tracker:- Detect changes in event details and reset the counter accordingly.
- Increase the counter for multiple events with identical details.
Deferral Mechanism:
Configurable limits and deferral intervals let you defer events that exceed a specified threshold. Deferred events are later eligible for re‑processing.Deferred Events Lookup:
Easily retrieve a list of deferred events, optionally filtered by category and/or id.Flexible Integration:
Clear result types (immediate
,deferred
, orignored
) let your application decide what to do next.
Installation
Install the module via npm:
npm install in-memory-tracker
Usage
Below is a real‑world example that simulates failed login attempts within an authentication system. In this scenario:
- Category: Represents the system (e.g.
authentication
). - ID: Represents the specific user (e.g.
user:john_doe
). - Details: Include attributes such as the IP address and a failure reason.
const InMemoryTracker = require('in-memory-tracker');
// Create a tracker instance with custom options.
const tracker = new InMemoryTracker({
limit: 3, // Allow up to 3 immediate events before deferring.
deferInterval: 10 * 1000, // 10 seconds until a deferred event can be re‑processed.
expireTime: 60 * 60 * 1000 // Reset the event count after 1 hour.
});
// Real-world scenario: Failed login attempts.
// Category represents the system ("authentication") and id represents a specific user.
function simulateFailedLogin(user, ip) {
// Details include the IP address and the failure reason.
const details = {
ipAddress: ip,
failureReason: 'Invalid password'
};
// Track a failed login attempt.
const result = tracker.trackEvent('authentication', user, details);
if (result.type === 'immediate') {
console.log(`[Immediate] Login attempt for ${user} from ${ip} recorded. Count: ${result.data.count}`);
} else if (result.type === 'deferred') {
console.log(`[Deferred] Too many login attempts for ${user} from ${ip}. Notification scheduled at ${new Date(result.data.scheduledSendAt).toLocaleTimeString()}`);
} else { // 'ignored'
console.log(`[Ignored] Login attempt for ${user} from ${ip} ignored (already deferred).`);
}
}
// Simulate several failed login attempts for the user 'user:john_doe'.
const user = 'user:john_doe';
const ip = '192.168.1.101';
// The first three events are processed immediately.
simulateFailedLogin(user, ip);
simulateFailedLogin(user, ip);
simulateFailedLogin(user, ip);
// The fourth event exceeds the limit and triggers deferral.
simulateFailedLogin(user, ip);
// After the defer interval has passed, process the deferred events.
setTimeout(() => {
const deferredEvents = tracker.processDeferredEvents();
if (deferredEvents.length > 0) {
console.log('Processing deferred events:');
deferredEvents.forEach(ev => {
console.log(`Deferred event for ${ev.category} "${ev.id}" with details:`, ev.details);
});
} else {
console.log('No deferred events ready for processing.');
}
// Optionally, retrieve deferred events for monitoring.
const allDeferred = tracker.getDeferredEvents({ category: 'authentication', id: user });
if (allDeferred.length > 0) {
console.log('Currently deferred events:', allDeferred);
}
}, 11 * 1000); // Wait slightly longer than the deferInterval to allow processing.
API
Constructor
new InMemoryTracker(options);
Options
limit
(number, default: 5):
Maximum number of immediate events allowed before deferral.deferInterval
(number, default: 60 60 1000):
Time (in milliseconds) to wait before a deferred event becomes eligible for re‑processing.expireTime
(number, default: 24 60 60 * 1000):
Time (in milliseconds) after which the event count is reset.autoPurge
(boolean, default: true):
When enabled, expired records are automatically purged each time an event is tracked.
Methods
trackEvent(category, id, details)
Records an incoming event.
Parameters:
category
(string): The high-level category (e.g. "authentication").id
(string): The specific identifier within the category (e.g. user id).details
(object): Additional event details (e.g.{ ipAddress, failureReason }
).
Behavior:
- If no record exists, a new record is created with count set to 1.
- If a record exists and the event details have changed, the record is reset.
- If the record exists with unchanged details and is within the expire window, the counter increments.
- Returns
immediate
if the count is within the limit. - Returns
deferred
and schedules re‑processing if the count exceeds the limit. - Returns
ignored
if an event is already deferred.
- Returns
Returns:
An object with:type
:"immediate"
,"deferred"
, or"ignored"
.data
: Includes category, id, details, count, and (if applicable)scheduledSendAt
.
processDeferredEvents()
Processes deferred events that are eligible for re‑processing (based on the defer interval).
- Returns:
An array of events ready for processing, each containing:- The composite key.
- The category and id.
- The event details.
getDeferredEvents(filter)
Retrieves deferred events, optionally filtered by category and/or id.
Parameters:
filter
(object, optional):category
(string): Filter events by category.id
(string): Filter events by id.
Returns:
An array of deferred event objects, each including:- The composite key.
- The category and id.
- The event details.
- The scheduled send time (
scheduledSendAt
) for processing.
Contributing
Contributions, improvements, and bug fixes are welcome! Feel free to fork the repository and open pull requests.
License
This project is licensed under the MIT License. See the LICENSE file for details.