UNPKG

uid-pool

Version:

High-performance UUID and unique ID pooling for Node.js. Pre-generate IDs in background worker threads for O(1) synchronous acquisition. Drop-in replacement for uuid.v4() and nanoid() with 10-100x better performance under load.

266 lines (190 loc) β€’ 7.49 kB
# uid-pool πŸŠβ€β™‚οΈ _Because sometimes you need IDs faster than your generator can make them._ ## The Problem Nobody Talks About Picture this: You're building the next big thingβ„’, and suddenly your app needs to generate thousands of unique IDs. Your trusty UUID generator starts sweating bullets, your event loop gets stage fright, and your users are left staring at loading spinners. Not cool. ## Enter uid-pool Think of it as a bouncer with a VIP list. While your ID generator is working hard in the background, uid-pool maintains a pre-generated pool of IDs ready to hand out instantly. No waiting, no blocking, just pure O(1) satisfaction. ```typescript import { IdPool } from "uid-pool"; // Create a pool with your favorite ID generator const pool = await IdPool.create({ generator: () => crypto.randomUUID(), // or nanoid(), uuid.v7(), etc. poolSize: 1000, // Maximum pool capacity minSize: 250, // Refill threshold }); // Get an ID instantly (seriously, it's O(1)) const id = pool.acquire(); // "550e8400-e29b-41d4-a716-446655440000" ``` ## Why Should You Care? ### πŸš€ **Blazing Fast** - **O(1) ID acquisition** - Faster than a caffeinated cheetah - **Non-blocking operations** - Your event loop can finally breathe - **Smart pre-generation** - IDs ready before you need them ### 🧩 **Works With Everything** - **Any ID generator** - UUID, nanoid, or that weird custom ID generator - **Any runtime** - Node.js, Bun, Deno, Edge workers - **Zero dependencies** ### πŸ›‘οΈ **Battle-Tested Design** - **Circular buffer magic** - No array shifting nonsense here - **Worker thread isolation** (Node.js) - True parallelism, not just promises - **Graceful degradation** - Falls back elegantly when things go sideways - **TypeScript native** - Your IDE will thank you ## Installation ```bash npm install uid-pool # or if you're cool bun add uid-pool # or if you're really cool pnpm add uid-pool ``` ## Real-World Examples ### Basic Usage ```typescript import { IdPool } from "uid-pool"; import { nanoid } from "nanoid"; const pool = await IdPool.create({ generator: () => nanoid(), poolSize: 500, }); // Need an ID? Just ask! // The pool is already refilling in the background const id = pool.acquire(); ``` ### Custom ID Generator ```typescript let counter = 0; const pool = await IdPool.create({ generator: () => `user-${Date.now()}-${++counter}`, poolSize: 1000, minSize: 100, }); ``` ### Monitoring Pool Health ```typescript const pool = await IdPool.create({ generator: () => crypto.randomUUID(), poolSize: 1000, minSize: 250, }); pool.on("refill", () => { console.log("Pool is thirsty, refilling..."); }); pool.on("error", (error) => { console.error("Pool party crashed:", error); // Don't worry, the pool keeps working }); // Check pool stats console.log(`Pool size: ${pool.size}`); console.log(`Pool full: ${pool.isFull}`); ``` ### Graceful Cleanup ```typescript // When you're done partying await pool.close(); ``` ## How It Works (The Secret Sauce) 1. **Factory Pattern**: `IdPool.create()` returns a fully initialized pool, pre-filled to your minimum size requirement. No empty pools on day one! 2. **Circular Buffer**: Unlike naive implementations using `Array.shift()` (O(n) complexity), we use a circular buffer for true O(1) operations. Your computer science professor would be proud. 3. **Smart Runtime Detection**: Automatically detects your environment and chooses the optimal strategy: - **Node.js/Bun**: Spawns a worker thread for true parallel ID generation - **Edge/Browser**: Uses chunked generation with `setTimeout` to keep the main thread responsive 4. **Background Refilling**: When the pool drops below `minSize`, it automatically starts refilling without blocking your `acquire()` calls. It's like having a helpful bartender who knows when to restock. ## Configuration Options ```typescript interface IdPoolOptions { // Your ID generator function generator: () => string | Promise<string>; // Maximum number of IDs to keep in the pool poolSize: number; // Start refilling when pool drops below this minSize?: number; // How many IDs to generate per chunk (edge runtime) chunkSize?: number; // Delay between generation chunks in ms (edge runtime) chunkDelay?: number; } ``` ## Platform Support - **Node.js**: v18+ (uses worker threads for maximum performance) - **Bun**: v1.0+ (also uses worker threads, because Bun is cool like that) - **Deno**: Works great with chunked generation - **Edge Workers**: Cloudflare, Vercel Edge, etc. - **Browsers**: Modern browsers with ES2020 support ## Benchmarks On a typical developer machine (you know, the one with 47 Chrome tabs open): ``` ID Acquisition Performance: βœ“ Array.shift() approach: 2,341 ops/sec βœ“ uid-pool O(1) approach: 8,923,654 ops/sec πŸš€ Pool Refill (1000 IDs): βœ“ Blocking generation: 125ms (freezes your app) βœ“ uid-pool background: 0ms (your app keeps running) ``` _Results may vary. Your mileage may depend on how many Slack notifications you're getting._ ## Error Handling The pool is designed to keep swimming even when things go wrong: ```typescript pool.on("error", (error) => { if (error instanceof GeneratorError) { console.log("Generator had a bad day:", error.originalError); } else if (error instanceof WorkerError) { console.log("Worker called in sick:", error); // Don't worry, pool falls back to main thread } }); // The pool keeps working even if the generator fails occasionally const id = pool.acquire(); // Still returns IDs from the pool ``` ## Common Patterns ### High-Traffic API Endpoints ```typescript const requestIdPool = await IdPool.create({ generator: () => nanoid(), poolSize: 10000, // Handle traffic spikes minSize: 5000, // Keep plenty ready }); app.use((req, res, next) => { req.id = requestIdPool.acquire() || nanoid(); // Fallback for safety next(); }); ``` ### Database Record Creation ```typescript const orderIdPool = await IdPool.create({ generator: async () => { // Some expensive custom ID generation const prefix = await getRegionalPrefix(); return `${prefix}-${Date.now()}-${randomBytes(4).toString("hex")}`; }, poolSize: 1000, }); async function createOrder(data) { const id = orderIdPool.acquire(); if (!id) { throw new Error("Order system overwhelmed, try again"); } return db.orders.create({ id, ...data }); } ``` ## Testing Run the test suite (it's comprehensive, we promise): ```bash bun test ``` ## Contributing Found a bug? Have an idea? Pull requests welcome! Just remember: 1. **Performance matters** - If it makes things slower, we need to talk 2. **Keep it simple** - Complexity is the enemy of reliability 3. **Test everything** - Untested code is broken code 4. **Document your why** - Future you will thank present you ## Philosophy This library follows the Unix philosophy: do one thing and do it well. We generate IDs fast. That's it. No blockchain integration, no AI predictions, no metaverse compatibility. Just fast, reliable ID generation. ## License MIT - Because sharing is caring. ## Acknowledgments - The circular buffer implementation was inspired by that computer science textbook you never returned - Worker threads idea stolen from literally every other pooling library (but we did it better) - Special thanks to coffee for making this possible --- _Built with ❀️ and a severe lack of patience for slow ID generation._