Security News
Fluent Assertions Faces Backlash After Abandoning Open Source Licensing
Fluent Assertions is facing backlash after dropping the Apache license for a commercial model, leaving users blindsided and questioning contributor rights.
api-model-limiter
Advanced tools
A flexible and robust rate limiter implementation using Redis for managing API keys and model access with multiple time windows.
Rate limits are tracked across different time windows (minute, hour, day, month). Each window operates independently, meaning a request must satisfy ALL window constraints to be allowed.
Example:
{
minute: 44, // 44 requests per minute
hour: 442, // 442 requests per hour
day: 2000 // 2000 requests per day
}
Limit borrowing allows exceeding shorter time window limits by "borrowing" from longer windows. This is useful for handling burst traffic while maintaining overall usage constraints.
Example Use Case: Consider an API with limits:
Without borrowing:
// If you've used 10 requests in the current minute
result = await limiter.getModel("api 1", false); // Returns null
With borrowing:
// Even if minute limit (10) is reached, but hour limit has space
result = await limiter.getModel("api 1", true); // Returns valid combination
When to Use Borrowing:
The system automatically rotates through available API keys and models when limits are reached. This helps maximize availability and distribute load.
Use Case:
const config = [
{
name: "api 1",
keys: ["key1", "key2"], // Multiple keys
models: [
{
name: "model1", // Multiple models
limits: {...}
},
{
name: "model2",
limits: {...}
}
]
}
];
The rate limiter supports different strategies for selecting both keys and models. These strategies can be configured independently:
Ascending (default)
Random
Round-Robin
Set strategies during initialization:
const limiter = new RateLimiter(config, {
keyStrategy: 'round-robin', // Strategy for key selection
modelStrategy: 'random', // Strategy for model selection
redis: { /* redis options */ },
// ... other options
});
Change strategies at runtime:
// Change key selection strategy
limiter.setKeyStrategy('random');
// Change model selection strategy
limiter.setModelStrategy('round-robin');
Ascending Strategy
// Keys/models used in defined order
const limiter = new RateLimiter(config, {
keyStrategy: 'ascending',
modelStrategy: 'ascending'
});
Best for:
Random Strategy
const limiter = new RateLimiter(config, {
keyStrategy: 'random',
modelStrategy: 'random'
});
Best for:
Round-Robin Strategy
const limiter = new RateLimiter(config, {
keyStrategy: 'round-robin',
modelStrategy: 'round-robin'
});
Best for:
npm install ioredis
const limiter = new RateLimiter(config, {
redis: {
host: 'localhost',
port: 6379,
password: 'optional',
db: 0,
maxRetriesPerRequest: 3,
retryStrategy: (times) => Math.min(times * 50, 2000),
enableOfflineQueue: true,
connectTimeout: 10000
},
enableMetrics: true,
batchSize: 5,
customWindows: {
shift: 28800,
week: 604800
},
keyStrategy: 'ascending',
modelStrategy: 'round-robin'
});
The first parameter (config
) defines your APIs, keys, and models:
const config = [
{
name: "api 1", // Unique API identifier
keys: ["key1", "key2"], // Array of API keys
models: [ // Array of models
{
name: "model1", // Unique model identifier
limits: { // Rate limits per window
minute: 44,
hour: 442,
day: 2000,
month: 200000
}
}
]
}
// ... more APIs
];
Control your Redis connection settings:
{
redis: {
// Connection
host: 'localhost', // Redis host (default: 'localhost')
port: 6379, // Redis port (default: 6379)
password: 'secret', // Redis password (optional)
db: 0, // Redis database number (default: 0)
// Timeouts
connectTimeout: 10000, // Connection timeout in ms (default: 10000)
commandTimeout: 5000, // Command execution timeout (default: 5000)
// Retry Configuration
maxRetriesPerRequest: 3, // Max retries per command (default: 3)
retryStrategy: (times) => { // Custom retry strategy
return Math.min(times * 50, 2000);
},
// Advanced Options
enableOfflineQueue: true, // Queue commands when disconnected (default: true)
keepAlive: 30000, // TCP keep-alive in ms (default: 30000)
enableAutoPipelining: true, // Enable auto pipelining (default: true)
// TLS Options (if needed)
tls: {
// TLS configuration options
ca: fs.readFileSync('path/to/ca.crt'),
cert: fs.readFileSync('path/to/client.crt'),
key: fs.readFileSync('path/to/client.key')
}
}
}
{
enableMetrics: true, // Enable/disable metrics collection (default: true)
metricsPrefix: 'custom', // Custom prefix for metric keys (default: 'metric')
}
{
customWindows: {
// Window name: duration in seconds
halfhour: 1800, // 30 minutes
shift: 28800, // 8 hours
week: 604800, // 1 week
fortnight: 1209600, // 2 weeks
quarter: 7776000 // 3 months
}
}
Get next available key:model combination for a specific API.
// Get next available combination for "api 1"
const result = await limiter.getModel("api 1", false);
if (result) {
console.log('Key:', result.key);
console.log('Model:', result.model);
console.log('Limits:', result.limits);
}
Get multiple combinations for a specific API at once.
// Get 3 combinations for "api 1"
const batch = await limiter.getBatch("api 1", 3);
if (batch) {
batch.forEach(result => {
console.log('Key:', result.key);
console.log('Model:', result.model);
});
}
Freeze a specific key:model combination for an API.
// Freeze for 5 minutes
await limiter.freezeModel("api 1", "key1", "model1", 300);
Update limits for a specific model in an API.
const newLimits = await limiter.updateLimits("api 1", "model1", {
minute: 50,
hour: 500
});
Get usage statistics for a specific key:model combination.
const stats = await limiter.getUsageStats("api 1", "key1", "model1");
console.log('Current usage:', stats.currentUsage);
console.log('Metrics:', stats.metrics);
Get metrics for a specific key:model combination.
const metrics = await limiter.getMetrics("api 1", "key1", "model1");
console.log('Success rate:', metrics.success);
console.log('Limit reached count:', metrics.limitReached);
Change the key selection strategy.
limiter.setKeyStrategy('random'); // 'ascending', 'random', or 'round-robin'
Change the model selection strategy.
limiter.setModelStrategy('round-robin'); // 'ascending', 'random', or 'round-robin'
The rate limiter includes comprehensive error handling:
try {
const result = await limiter.getModel("non-existent-api");
} catch (error) {
console.error('API not found:', error.message);
}
try {
limiter.setKeyStrategy('invalid-strategy');
} catch (error) {
console.error('Invalid strategy:', error.message);
}
Limit Borrowing Strategy
Key-Model Rotation
Metrics Usage
Error Handling
Selection Strategy Best Practices
Strategy Selection Guidelines
MIT
FAQs
A rate limiter to work with multiple api keys and models
The npm package api-model-limiter receives a total of 6 weekly downloads. As such, api-model-limiter popularity was classified as not popular.
We found that api-model-limiter demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Fluent Assertions is facing backlash after dropping the Apache license for a commercial model, leaving users blindsided and questioning contributor rights.
Research
Security News
Socket researchers uncover the risks of a malicious Python package targeting Discord developers.
Security News
The UK is proposing a bold ban on ransomware payments by public entities to disrupt cybercrime, protect critical services, and lead global cybersecurity efforts.