| name | maintainx-rate-limits |
| description | Implement MaintainX API rate limiting, pagination, and backoff patterns.
Use when handling rate limit errors, implementing retry logic,
or optimizing API request throughput for MaintainX.
Trigger with phrases like "maintainx rate limit", "maintainx throttling",
"maintainx 429", "maintainx retry", "maintainx backoff", "maintainx pagination".
|
| allowed-tools | Read, Write, Edit |
| version | 1.0.0 |
| license | MIT |
| author | Jeremy Longshore <jeremy@intentsolutions.io> |
MaintainX Rate Limits
Overview
Handle MaintainX API rate limits gracefully with exponential backoff, pagination, and request queuing.
Prerequisites
- MaintainX SDK installed
- Understanding of async/await patterns
- Familiarity with cursor-based pagination
MaintainX API Limits
| Aspect | Limit | Notes |
|---|
| Requests per minute | Varies by plan | Check your subscription |
| Page size | 100 max | Default varies by endpoint |
| Concurrent requests | Recommended: 5 | Avoid parallel bursts |
Instructions
Step 1: Exponential Backoff with Jitter
interface RetryConfig {
maxRetries: number;
baseDelayMs: number;
maxDelayMs: number;
jitterMs: number;
}
const defaultConfig: RetryConfig = {
maxRetries: 5,
baseDelayMs: 1000,
maxDelayMs: 60000,
jitterMs: 500,
};
async function withExponentialBackoff<T>(
operation: () => Promise<T>,
config: Partial<RetryConfig> = {}
): Promise<T> {
const { maxRetries, baseDelayMs, maxDelayMs, jitterMs } = {
...defaultConfig,
...config,
};
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await operation();
} catch (error: any) {
if (attempt === maxRetries) throw error;
const status = error.response?.status;
if (status !== && (status < || status >= )) {
error;
}
retryAfter = error.?.?.[];
: ;
(retryAfter) {
delay = (retryAfter) * ;
} {
exponentialDelay = baseDelayMs * .(, attempt);
jitter = .() * jitterMs;
delay = .(exponentialDelay + jitter, maxDelayMs);
}
.(
+
);
( (r, delay));
}
}
();
}
() {
(
client.({ : }),
{ : }
);
}
Step 2: Request Queue for Concurrency Control
import PQueue from 'p-queue';
class RateLimitedClient {
private queue: PQueue;
private client: MaintainXClient;
constructor(client: MaintainXClient, options?: { concurrency?: number; interval?: number }) {
this.client = client;
this.queue = new PQueue({
concurrency: options?.concurrency || 5,
interval: options?.interval || 1000,
intervalCap: 10,
});
}
async getWorkOrders(params?: any) {
return this.queue.add(() =>
withExponentialBackoff(() => this.client.getWorkOrders(params))
);
}
() {
..(
( ..(params))
);
}
() {
..(
( ..(data))
);
}
() {
{
: ..,
: ..,
};
}
() {
..();
}
}
rateLimitedClient = (client, {
: ,
: ,
});
.([
rateLimitedClient.(),
rateLimitedClient.(),
rateLimitedClient.({ : }),
]);
Step 3: Cursor-Based Pagination
interface PaginationOptions {
limit?: number;
maxPages?: number;
delayBetweenPages?: number;
}
async function* paginate<T>(
fetchPage: (cursor?: string) => Promise<{ items: T[]; nextCursor: string | null }>,
options: PaginationOptions = {}
): AsyncGenerator<T[], void, unknown> {
const { limit = 100, maxPages = Infinity, delayBetweenPages = 100 } = options;
let cursor: string | undefined;
let pageCount = 0;
do {
const response = await fetchPage(cursor);
yield response.items;
cursor = response.nextCursor || undefined;
pageCount++;
if (cursor && delayBetweenPages > 0) {
await new ( (r, delayBetweenPages));
}
} (cursor && pageCount < maxPages);
}
* (
: ,
: = {},
: = {}
): <[], , > {
* (
(cursor) => {
response = (
client.({ ...params, cursor, : options. || })
);
{
: response.,
: response.,
};
},
options
);
}
(): <[]> {
: [] = [];
( batch (client, params, options)) {
allWorkOrders.(...batch);
.();
}
allWorkOrders;
}
() {
workOrders = (
client,
{ : },
{
: ,
: ,
: ,
}
);
.();
workOrders;
}
Step 4: Rate Limit Monitor
class RateLimitMonitor {
private requestCount = 0;
private windowStart = Date.now();
private readonly windowMs = 60000;
private readonly maxRequests = 60;
recordRequest() {
const now = Date.now();
if (now - this.windowStart > this.windowMs) {
this.requestCount = 0;
this.windowStart = now;
}
this.requestCount++;
}
shouldThrottle(): boolean {
return this.requestCount >= this.maxRequests * 0.8;
}
getWaitTime(): number {
if (!this.shouldThrottle()) return 0;
windowEnd = . + .;
.(, windowEnd - .());
}
() {
{
: .,
: .(, . - (.() - .)),
: .(),
};
}
}
{
: ;
: ;
() {
. = ();
. = ();
}
throttledRequest<T>(: <T>): <T> {
(..()) {
waitTime = ..();
.();
( (r, waitTime));
}
..();
();
}
() {
.( ..(params));
}
}
Step 5: Batch Operations with Rate Limiting
interface BatchConfig {
batchSize: number;
delayBetweenBatches: number;
maxConcurrent: number;
}
async function processBatch<T, R>(
items: T[],
processor: (item: T) => Promise<R>,
config: Partial<BatchConfig> = {}
): Promise<R[]> {
const { batchSize = 10, delayBetweenBatches = 500, maxConcurrent = 5 } = config;
const results: R[] = [];
for (let i = 0; i < items.length; i += batchSize) {
const batch = items.slice(i, i + batchSize);
console.log(`Processing batch ${Math.floor(i / batchSize) + 1}/${Math.ceil(items.length / batchSize)}...`);
const queue = new PQueue({ concurrency: maxConcurrent });
const batchPromises = batch.map( =>
queue.( ( (item)))
);
batchResults = .(batchPromises);
results.(...batchResults);
(i + batchSize < items.) {
( (r, delayBetweenBatches));
}
}
results;
}
(): <[]> {
(
workOrdersData,
client.(data),
{
: ,
: ,
: ,
}
);
}
Output
- Resilient API calls with automatic retry
- Proper pagination handling
- Request queuing and throttling
- Rate limit monitoring
Error Handling
| Scenario | Strategy |
|---|
| 429 Rate Limited | Exponential backoff with jitter |
| Retry-After header | Honor the specified wait time |
| Burst requests | Use request queue |
| Large data sets | Use pagination with delays |
Best Practices
- Start conservative: Begin with lower limits and increase gradually
- Use pagination: Never try to fetch all data in one request
- Add delays: Include delays between batch operations
- Monitor usage: Track request counts and adjust
- Handle errors gracefully: Always implement retry logic
Resources
Next Steps
For security configuration, see maintainx-security-basics.