A TypeScript implementation of a scalable waitlist system using Redis, supporting concurrent operations, user management, and position manipulation. Built with atomic operations using Redis Lua scripts for reliability at scale.
- Concurrent user management with email/phone identification
- Linked list-based waitlist system for efficient position management
- Invite code system with configurable position bumping
- Community code system for direct signup access
- Signup cutoff management for controlled user signups
- Atomic operations using Redis Lua scripts
- Email and phone number uniqueness enforcement
- Comprehensive test suite with 45+ test scenarios
- Node.js (v14 or higher)
- Redis server
- Yarn package manager
-
Clone the repository:
git clone https://github.com/stefanionescu/redis-user-waitlist.git cd redis-user-waitlist -
Install dependencies:
yarn install
-
Configure environment:
cp .env.example .env
Edit
.envwith your Redis configuration.
import { WaitlistManager } from './waitlistManager';
const waitlist = new WaitlistManager({
host: process.env.REDIS_HOST || 'localhost',
port: parseInt(process.env.REDIS_PORT || '6379'),
password: process.env.REDIS_PASSWORD || '',
});
// Insert a user
const result = await waitlist.insertUser({
email: 'user@example.com',
phone: '+1234567890', // optional
metadata: { name: 'John Doe' }
});
// Get user position
const position = await waitlist.getPosition(result.id);
// Move user to a different position
await waitlist.moveUser(result.id, 5);insertUser(data: UserData): Add a user with email/phonegetPosition(id: string): Get current position of a usermoveUser(id: string, targetPosition: number): Move user to a specific positionmoveUserByEmail(email: string, targetPosition: number): Move user by emailmoveUserByPhone(phone: string, targetPosition: number): Move user by phoneattachEmail(id: string, email: string): Add/update email for existing userattachPhone(id: string, phone: string): Add/update phone for existing userdeleteUser(id: string): Remove user by IDdeleteUserByEmail(email: string): Remove user by emaildeleteUserByPhone(phone: string): Remove user by phone
createInviteCode(userId: string, minBumpPositions: number): Create invite codeuseInviteCode(code: string, userData: UserData, bumpPositions: number): Use invite codegetInviteCodeCreator(code: string): Get code creatorgetInviteCodeUser(code: string): Get user who used the codegetUserInviteCodeCount(userId: string): Get number of codes created by usergetPositionAfterInviteCodeUse(code: string): Preview position after using codegetInviteCodeBumpPositions(code: string): Get minimum bump positions for codegetUserCreatedInviteCodes(userId: string): Get all codes created by a usergetInviteCodeUsedBy(userId: string): Get invite code info used by a user
createCommunityCode(code: string, maxUses: number): Create a community code with usage limituseCommunityCode(code: string, userData: UserData): Use code to sign up immediatelygetCommunityCodeInfo(code: string): Get code usage informationdeleteCommunityCode(code: string): Delete a community code
setSignupCutoff(cutoff: number): Set position cutoff for signupsisUserSignedUp(id: string): Check if user has signed upcanUserSignUp(id: string): Check if user is eligible to sign upmarkUserAsSignedUp(id: string): Mark user as signed up
getOrderedIds(): Get all user IDs in waitlist ordergetEmailMapping(email: string): Get user ID by emailgetPhoneMapping(phone: string): Get user ID by phonegetLength(): Get total number of users in waitlist
The waitlist uses a Redis list data structure for efficient position management:
- O(1) insertions at head/tail
- O(n) position-based insertions
- Atomic operations for all position changes
- No position rebalancing needed
- Supports unlimited users
All critical operations use Redis Lua scripts to ensure atomicity and consistency:
- User insertion with duplicate checking
- Position updates and movement
- Contact information management
- Invite code creation and usage
- Community code usage tracking
- Deletion across multiple indices
- Signup status management
Uses multiple Redis data structures for efficient operations:
- List: Position management (
waitlist:list) - Hash: User data storage (
waitlist:users) - Hash: Email index (
waitlist:emails) - Hash: Phone index (
waitlist:phones) - Hash: Invite code management (
waitlist:invite_codes,waitlist:used_codes) - Hash: Community code management (
waitlist:codes,waitlist:codes:uses) - Set: Signup tracking (
waitlist:signed_up)
The test suite in waitlistTests.ts includes 45+ comprehensive test scenarios:
- Multiple user insertions
- Duplicate handling
- Position manipulation
- Invite code usage
- Community code usage
- Contact information updates
- Signup management
- Large-scale operations (100,000+ users)
- Batch insertions and moves
- Repeated position changes
- Complex concurrent scenarios
- Signup cutoff changes
- Community code usage limits
- Position boundary conditions
- Deletion during movement
- Invite code limits
- Community code usage tracking
- Contact information uniqueness
- Signup eligibility checks
- Cutoff boundary testing
Run the test suite:
yarn testMIT License - see the LICENSE file for details.