@mytechtoday/augment-extensions 1.2.0 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/AGENTS.md +35 -3
  2. package/README.md +3 -3
  3. package/augment-extensions/domain-rules/software-architecture/README.md +143 -0
  4. package/augment-extensions/domain-rules/software-architecture/examples/banking-layered.md +961 -0
  5. package/augment-extensions/domain-rules/software-architecture/examples/ecommerce-microservices.md +990 -0
  6. package/augment-extensions/domain-rules/software-architecture/examples/iot-eventdriven.md +882 -0
  7. package/augment-extensions/domain-rules/software-architecture/examples/monolith-to-microservices-migration.md +703 -0
  8. package/augment-extensions/domain-rules/software-architecture/examples/serverless-imageprocessing.md +957 -0
  9. package/augment-extensions/domain-rules/software-architecture/examples/trading-eventdriven.md +747 -0
  10. package/augment-extensions/domain-rules/software-architecture/module.json +119 -0
  11. package/augment-extensions/domain-rules/software-architecture/rules/challenges-solutions.md +763 -0
  12. package/augment-extensions/domain-rules/software-architecture/rules/definitions-terminology.md +409 -0
  13. package/augment-extensions/domain-rules/software-architecture/rules/design-principles.md +684 -0
  14. package/augment-extensions/domain-rules/software-architecture/rules/evaluation-testing.md +1381 -0
  15. package/augment-extensions/domain-rules/software-architecture/rules/event-driven-architecture.md +616 -0
  16. package/augment-extensions/domain-rules/software-architecture/rules/fundamentals.md +306 -0
  17. package/augment-extensions/domain-rules/software-architecture/rules/industry-architectures.md +554 -0
  18. package/augment-extensions/domain-rules/software-architecture/rules/layered-architecture.md +776 -0
  19. package/augment-extensions/domain-rules/software-architecture/rules/microservices-architecture.md +503 -0
  20. package/augment-extensions/domain-rules/software-architecture/rules/modeling-documentation.md +1199 -0
  21. package/augment-extensions/domain-rules/software-architecture/rules/monolithic-architecture.md +351 -0
  22. package/augment-extensions/domain-rules/software-architecture/rules/principles.md +556 -0
  23. package/augment-extensions/domain-rules/software-architecture/rules/quality-attributes.md +797 -0
  24. package/augment-extensions/domain-rules/software-architecture/rules/scalability-performance.md +1345 -0
  25. package/augment-extensions/domain-rules/software-architecture/rules/security-architecture.md +1039 -0
  26. package/augment-extensions/domain-rules/software-architecture/rules/serverless-architecture.md +711 -0
  27. package/augment-extensions/domain-rules/software-architecture/rules/skills-development.md +568 -0
  28. package/augment-extensions/domain-rules/software-architecture/rules/tools-methodologies.md +961 -0
  29. package/augment-extensions/workflows/beads/examples/complete-workflow-example.md +8 -8
  30. package/augment-extensions/workflows/beads/rules/best-practices.md +2 -2
  31. package/augment-extensions/workflows/beads/rules/file-format.md +4 -4
  32. package/augment-extensions/workflows/beads/rules/manual-setup.md +4 -4
  33. package/augment-extensions/workflows/beads/rules/workflow.md +3 -3
  34. package/modules.md +40 -3
  35. package/package.json +1 -1
@@ -0,0 +1,1345 @@
1
+ # Scalability and Performance
2
+
3
+ ## Overview
4
+
5
+ This document covers scalability and performance principles, patterns, and techniques for building systems that can handle growth and deliver fast response times.
6
+
7
+ ---
8
+
9
+ ## Knowledge
10
+
11
+ ### Scalability Fundamentals
12
+
13
+ #### Horizontal Scaling (Scale Out)
14
+
15
+ **Definition**
16
+ - Add more servers/instances to handle increased load
17
+ - Distribute load across multiple machines
18
+ - Preferred for cloud-native applications
19
+ - Enables elastic scaling
20
+
21
+ **Characteristics**
22
+ - Linear cost scaling (add servers as needed)
23
+ - Improved fault tolerance (redundancy)
24
+ - Requires stateless services
25
+ - Load balancing required
26
+
27
+ **Benefits**
28
+ - No theoretical limit to scaling
29
+ - Better fault tolerance
30
+ - Cost-effective (commodity hardware)
31
+ - Supports auto-scaling
32
+
33
+ **Challenges**
34
+ - Distributed system complexity
35
+ - Data consistency issues
36
+ - Network latency
37
+ - Load balancing overhead
38
+
39
+ #### Vertical Scaling (Scale Up)
40
+
41
+ **Definition**
42
+ - Add more resources (CPU, RAM, disk) to existing servers
43
+ - Increase capacity of individual machines
44
+ - Simpler than horizontal scaling
45
+ - Has physical limits
46
+
47
+ **Characteristics**
48
+ - Easier to implement (no code changes)
49
+ - Maintains data locality
50
+ - Limited by hardware constraints
51
+ - Single point of failure
52
+
53
+ **Benefits**
54
+ - Simpler architecture
55
+ - No distributed system complexity
56
+ - Better for stateful applications
57
+ - Lower network overhead
58
+
59
+ **Challenges**
60
+ - Physical limits (max CPU, RAM)
61
+ - Expensive (high-end hardware)
62
+ - Downtime during upgrades
63
+ - Single point of failure
64
+
65
+ ### Performance Fundamentals
66
+
67
+ #### Latency
68
+
69
+ **Definition**
70
+ - Time delay between request and response
71
+ - Measured in milliseconds (ms)
72
+ - Critical for user experience
73
+ - Affected by network, processing, I/O
74
+
75
+ **Latency Numbers Every Programmer Should Know**
76
+ ```
77
+ L1 cache reference: 0.5 ns
78
+ Branch mispredict: 5 ns
79
+ L2 cache reference: 7 ns
80
+ Mutex lock/unlock: 25 ns
81
+ Main memory reference: 100 ns
82
+ Compress 1KB with Snappy: 3,000 ns
83
+ Send 1KB over 1 Gbps: 10,000 ns
84
+ Read 4KB from SSD: 150,000 ns (0.15 ms)
85
+ Read 1MB sequentially: 1,000,000 ns (1 ms)
86
+ Disk seek: 10,000,000 ns (10 ms)
87
+ Read 1MB from network: 10,000,000 ns (10 ms)
88
+ Round trip in datacenter: 500,000 ns (0.5 ms)
89
+ ```
90
+
91
+ **Reducing Latency**
92
+ - Caching (reduce database queries)
93
+ - CDN (reduce network distance)
94
+ - Database indexing (faster queries)
95
+ - Asynchronous processing (non-blocking)
96
+ - Connection pooling (reuse connections)
97
+
98
+ #### Throughput
99
+
100
+ **Definition**
101
+ - Number of operations per unit time
102
+ - Measured in requests/second, transactions/second
103
+ - Indicates system capacity
104
+ - Can be increased by parallelism
105
+
106
+ **Improving Throughput**
107
+ - Horizontal scaling (more servers)
108
+ - Parallel processing (multi-threading)
109
+ - Batch processing (group operations)
110
+ - Asynchronous processing (queues)
111
+ - Resource optimization (efficient algorithms)
112
+
113
+ ### Caching Strategies
114
+
115
+ #### Cache-Aside (Lazy Loading)
116
+
117
+ **Definition**
118
+ - Application checks cache first
119
+ - On miss, load from database and populate cache
120
+ - Application manages cache
121
+ - Most common pattern
122
+
123
+ **Flow**
124
+ 1. Check cache for data
125
+ 2. If found (cache hit), return data
126
+ 3. If not found (cache miss), load from database
127
+ 4. Store in cache for future requests
128
+ 5. Return data
129
+
130
+ **Benefits**
131
+ - Only cache what's needed
132
+ - Cache failures don't break application
133
+ - Simple to implement
134
+
135
+ **Challenges**
136
+ - Cache miss penalty (extra latency)
137
+ - Stale data possible
138
+ - Cache warming needed
139
+
140
+ #### Read-Through Cache
141
+
142
+ **Definition**
143
+ - Cache sits between application and database
144
+ - Cache handles loading from database
145
+ - Transparent to application
146
+ - Cache manages itself
147
+
148
+ **Benefits**
149
+ - Simpler application code
150
+ - Consistent caching logic
151
+ - Automatic cache population
152
+
153
+ **Challenges**
154
+ - Requires cache infrastructure
155
+ - Cache miss penalty
156
+ - Less control over caching
157
+
158
+ #### Write-Through Cache
159
+
160
+ **Definition**
161
+ - Writes go through cache to database
162
+ - Cache and database updated synchronously
163
+ - Ensures cache consistency
164
+ - Higher write latency
165
+
166
+ **Benefits**
167
+ - Cache always consistent
168
+ - No stale data
169
+ - Simple consistency model
170
+
171
+ **Challenges**
172
+ - Higher write latency
173
+ - Unnecessary caching of rarely-read data
174
+ - Write amplification
175
+
176
+ #### Write-Behind Cache (Write-Back)
177
+
178
+ **Definition**
179
+ - Writes go to cache first
180
+ - Database updated asynchronously
181
+ - Lower write latency
182
+ - Risk of data loss
183
+
184
+ **Benefits**
185
+ - Fast writes
186
+ - Batch database updates
187
+ - Reduced database load
188
+
189
+ **Challenges**
190
+ - Data loss risk (cache failure)
191
+ - Complex consistency
192
+ - Eventual consistency
193
+
194
+ ### Load Balancing
195
+
196
+ **Definition**
197
+ - Distribute traffic across multiple servers
198
+ - Improve availability and scalability
199
+ - Prevent server overload
200
+ - Enable horizontal scaling
201
+
202
+ **Load Balancing Algorithms**
203
+
204
+ **Round Robin**
205
+ - Distribute requests sequentially
206
+ - Simple and fair
207
+ - Doesn't consider server load
208
+
209
+ **Least Connections**
210
+ - Send to server with fewest active connections
211
+ - Better for long-lived connections
212
+ - Requires connection tracking
213
+
214
+ **Least Response Time**
215
+ - Send to server with fastest response
216
+ - Adapts to server performance
217
+ - Requires health monitoring
218
+
219
+ **IP Hash**
220
+ - Hash client IP to determine server
221
+ - Session affinity (sticky sessions)
222
+ - Uneven distribution possible
223
+
224
+ **Weighted Round Robin**
225
+ - Assign weights to servers
226
+ - More requests to powerful servers
227
+ - Handles heterogeneous servers
228
+
229
+ **Load Balancing Layers**
230
+
231
+ **Layer 4 (Transport Layer)**
232
+ - Based on IP and port
233
+ - Fast (no application inspection)
234
+ - Limited routing logic
235
+
236
+ **Layer 7 (Application Layer)**
237
+ - Based on HTTP headers, URL, cookies
238
+ - Flexible routing (path-based, host-based)
239
+ - Slower (application inspection)
240
+
241
+ ### Database Scaling
242
+
243
+ #### Database Replication
244
+
245
+ **Master-Slave Replication**
246
+ - One master (writes), multiple slaves (reads)
247
+ - Scales read operations
248
+ - Eventual consistency
249
+ - Failover to slave on master failure
250
+
251
+ **Master-Master Replication**
252
+ - Multiple masters (writes and reads)
253
+ - Higher write availability
254
+ - Conflict resolution needed
255
+ - More complex
256
+
257
+ **Benefits**
258
+ - Improved read performance
259
+ - High availability
260
+ - Geographic distribution
261
+ - Backup and disaster recovery
262
+
263
+ **Challenges**
264
+ - Replication lag (eventual consistency)
265
+ - Conflict resolution (multi-master)
266
+ - Increased complexity
267
+ - Storage duplication
268
+
269
+ #### Database Sharding
270
+
271
+ **Definition**
272
+ - Partition data across multiple databases
273
+ - Each shard holds subset of data
274
+ - Horizontal partitioning
275
+ - Scales both reads and writes
276
+
277
+ **Sharding Strategies**
278
+
279
+ **Range-Based Sharding**
280
+ - Partition by value range (e.g., A-M, N-Z)
281
+ - Simple to implement
282
+ - Risk of uneven distribution (hotspots)
283
+
284
+ **Hash-Based Sharding**
285
+ - Hash key to determine shard
286
+ - Even distribution
287
+ - Difficult to add/remove shards
288
+
289
+ **Geographic Sharding**
290
+ - Partition by location
291
+ - Reduced latency (data locality)
292
+ - Regulatory compliance (data residency)
293
+
294
+ **Benefits**
295
+ - Scales reads and writes
296
+ - Improved performance (smaller datasets)
297
+ - Fault isolation (shard failure)
298
+
299
+ **Challenges**
300
+ - Complex queries (cross-shard joins)
301
+ - Rebalancing (adding/removing shards)
302
+ - Distributed transactions
303
+ - Application complexity
304
+
305
+ #### Database Indexing
306
+
307
+ **Definition**
308
+ - Data structure to speed up queries
309
+ - Trade-off: faster reads, slower writes
310
+ - Essential for query performance
311
+ - Requires careful design
312
+
313
+ **Index Types**
314
+
315
+ **B-Tree Index**
316
+ - Balanced tree structure
317
+ - Good for range queries
318
+ - Default in most databases
319
+ - Supports equality and range
320
+
321
+ **Hash Index**
322
+ - Hash table structure
323
+ - Fast equality lookups
324
+ - No range queries
325
+ - Memory-intensive
326
+
327
+ **Full-Text Index**
328
+ - Optimized for text search
329
+ - Supports natural language queries
330
+ - Larger storage overhead
331
+
332
+ **Composite Index**
333
+ - Index on multiple columns
334
+ - Order matters (leftmost prefix)
335
+ - Reduces index count
336
+
337
+ **Best Practices**
338
+ - Index foreign keys
339
+ - Index columns in WHERE, JOIN, ORDER BY
340
+ - Avoid over-indexing (write penalty)
341
+ - Monitor index usage
342
+ - Regular index maintenance
343
+
344
+ ### Asynchronous Processing
345
+
346
+ **Definition**
347
+ - Decouple request from processing
348
+ - Non-blocking operations
349
+ - Improves responsiveness
350
+ - Enables background processing
351
+
352
+ **Message Queues**
353
+ - Producer sends messages to queue
354
+ - Consumer processes messages asynchronously
355
+ - Decouples components
356
+ - Enables retry and error handling
357
+
358
+ **Benefits**
359
+ - Improved responsiveness (fast response)
360
+ - Better resource utilization
361
+ - Fault tolerance (retry failed jobs)
362
+ - Load leveling (smooth traffic spikes)
363
+
364
+ **Use Cases**
365
+ - Email sending
366
+ - Image processing
367
+ - Report generation
368
+ - Data synchronization
369
+ - Batch operations
370
+
371
+ **Popular Message Queues**
372
+ - RabbitMQ
373
+ - Apache Kafka
374
+ - Amazon SQS
375
+ - Redis (pub/sub)
376
+ - Google Cloud Pub/Sub
377
+
378
+ ### Content Delivery Network (CDN)
379
+
380
+ **Definition**
381
+ - Distributed network of servers
382
+ - Cache static content close to users
383
+ - Reduces latency and bandwidth
384
+ - Improves availability
385
+
386
+ **How CDN Works**
387
+ 1. User requests content
388
+ 2. CDN edge server checks cache
389
+ 3. If cached (hit), return content
390
+ 4. If not cached (miss), fetch from origin
391
+ 5. Cache content at edge
392
+ 6. Return content to user
393
+
394
+ **Benefits**
395
+ - Reduced latency (geographic proximity)
396
+ - Reduced bandwidth costs
397
+ - Improved availability (distributed)
398
+ - DDoS protection (distributed traffic)
399
+
400
+ **What to Cache**
401
+ - Static assets (images, CSS, JavaScript)
402
+ - Videos and media files
403
+ - API responses (with appropriate TTL)
404
+ - HTML pages (with cache invalidation)
405
+
406
+ **CDN Providers**
407
+ - Cloudflare
408
+ - Amazon CloudFront
409
+ - Akamai
410
+ - Fastly
411
+ - Google Cloud CDN
412
+
413
+ ---
414
+
415
+ ## Skills
416
+
417
+ ### Implementing Caching
418
+
419
+ **In-Memory Cache with Redis**
420
+ ```typescript
421
+ import Redis from 'ioredis';
422
+
423
+ class CacheService {
424
+ private redis: Redis;
425
+
426
+ constructor() {
427
+ this.redis = new Redis({
428
+ host: process.env.REDIS_HOST,
429
+ port: parseInt(process.env.REDIS_PORT || '6379'),
430
+ password: process.env.REDIS_PASSWORD,
431
+ retryStrategy: (times) => {
432
+ const delay = Math.min(times * 50, 2000);
433
+ return delay;
434
+ }
435
+ });
436
+ }
437
+
438
+ async get<T>(key: string): Promise<T | null> {
439
+ const value = await this.redis.get(key);
440
+ return value ? JSON.parse(value) : null;
441
+ }
442
+
443
+ async set<T>(key: string, value: T, ttlSeconds?: number): Promise<void> {
444
+ const serialized = JSON.stringify(value);
445
+
446
+ if (ttlSeconds) {
447
+ await this.redis.setex(key, ttlSeconds, serialized);
448
+ } else {
449
+ await this.redis.set(key, serialized);
450
+ }
451
+ }
452
+
453
+ async delete(key: string): Promise<void> {
454
+ await this.redis.del(key);
455
+ }
456
+
457
+ async invalidatePattern(pattern: string): Promise<void> {
458
+ const keys = await this.redis.keys(pattern);
459
+ if (keys.length > 0) {
460
+ await this.redis.del(...keys);
461
+ }
462
+ }
463
+ }
464
+
465
+ // Usage with cache-aside pattern
466
+ class ProductService {
467
+ constructor(
468
+ private productRepository: ProductRepository,
469
+ private cache: CacheService
470
+ ) {}
471
+
472
+ async getProduct(id: string): Promise<Product> {
473
+ const cacheKey = `product:${id}`;
474
+
475
+ // Try cache first
476
+ const cached = await this.cache.get<Product>(cacheKey);
477
+ if (cached) {
478
+ return cached;
479
+ }
480
+
481
+ // Cache miss - load from database
482
+ const product = await this.productRepository.findById(id);
483
+
484
+ if (product) {
485
+ // Cache for 1 hour
486
+ await this.cache.set(cacheKey, product, 3600);
487
+ }
488
+
489
+ return product;
490
+ }
491
+
492
+ async updateProduct(id: string, data: Partial<Product>): Promise<Product> {
493
+ const product = await this.productRepository.update(id, data);
494
+
495
+ // Invalidate cache
496
+ await this.cache.delete(`product:${id}`);
497
+
498
+ // Invalidate related caches
499
+ await this.cache.invalidatePattern(`products:category:${product.categoryId}:*`);
500
+
501
+ return product;
502
+ }
503
+ }
504
+ ```
505
+
506
+ ### Implementing Load Balancing
507
+
508
+ **Application-Level Load Balancing**
509
+ ```typescript
510
+ interface Server {
511
+ url: string;
512
+ weight: number;
513
+ activeConnections: number;
514
+ healthy: boolean;
515
+ }
516
+
517
+ class LoadBalancer {
518
+ private servers: Server[];
519
+ private currentIndex = 0;
520
+
521
+ constructor(servers: Array<{ url: string; weight?: number }>) {
522
+ this.servers = servers.map(s => ({
523
+ url: s.url,
524
+ weight: s.weight || 1,
525
+ activeConnections: 0,
526
+ healthy: true
527
+ }));
528
+
529
+ // Start health checks
530
+ this.startHealthChecks();
531
+ }
532
+
533
+ // Round-robin algorithm
534
+ getNextServerRoundRobin(): Server | null {
535
+ const healthyServers = this.servers.filter(s => s.healthy);
536
+
537
+ if (healthyServers.length === 0) {
538
+ return null;
539
+ }
540
+
541
+ const server = healthyServers[this.currentIndex % healthyServers.length];
542
+ this.currentIndex++;
543
+
544
+ return server;
545
+ }
546
+
547
+ // Least connections algorithm
548
+ getNextServerLeastConnections(): Server | null {
549
+ const healthyServers = this.servers.filter(s => s.healthy);
550
+
551
+ if (healthyServers.length === 0) {
552
+ return null;
553
+ }
554
+
555
+ return healthyServers.reduce((min, server) =>
556
+ server.activeConnections < min.activeConnections ? server : min
557
+ );
558
+ }
559
+
560
+ // Weighted round-robin algorithm
561
+ getNextServerWeighted(): Server | null {
562
+ const healthyServers = this.servers.filter(s => s.healthy);
563
+
564
+ if (healthyServers.length === 0) {
565
+ return null;
566
+ }
567
+
568
+ // Create weighted list
569
+ const weighted: Server[] = [];
570
+ for (const server of healthyServers) {
571
+ for (let i = 0; i < server.weight; i++) {
572
+ weighted.push(server);
573
+ }
574
+ }
575
+
576
+ const server = weighted[this.currentIndex % weighted.length];
577
+ this.currentIndex++;
578
+
579
+ return server;
580
+ }
581
+
582
+ async executeRequest<T>(
583
+ request: (url: string) => Promise<T>,
584
+ algorithm: 'round-robin' | 'least-connections' | 'weighted' = 'round-robin'
585
+ ): Promise<T> {
586
+ let server: Server | null;
587
+
588
+ switch (algorithm) {
589
+ case 'least-connections':
590
+ server = this.getNextServerLeastConnections();
591
+ break;
592
+ case 'weighted':
593
+ server = this.getNextServerWeighted();
594
+ break;
595
+ default:
596
+ server = this.getNextServerRoundRobin();
597
+ }
598
+
599
+ if (!server) {
600
+ throw new Error('No healthy servers available');
601
+ }
602
+
603
+ server.activeConnections++;
604
+
605
+ try {
606
+ const result = await request(server.url);
607
+ return result;
608
+ } finally {
609
+ server.activeConnections--;
610
+ }
611
+ }
612
+
613
+ private startHealthChecks(): void {
614
+ setInterval(async () => {
615
+ for (const server of this.servers) {
616
+ try {
617
+ const response = await fetch(`${server.url}/health`, {
618
+ method: 'GET',
619
+ timeout: 5000
620
+ });
621
+
622
+ server.healthy = response.ok;
623
+ } catch (error) {
624
+ server.healthy = false;
625
+ }
626
+ }
627
+ }, 10000); // Check every 10 seconds
628
+ }
629
+ }
630
+
631
+ // Usage
632
+ const loadBalancer = new LoadBalancer([
633
+ { url: 'http://server1.example.com', weight: 2 },
634
+ { url: 'http://server2.example.com', weight: 1 },
635
+ { url: 'http://server3.example.com', weight: 1 }
636
+ ]);
637
+
638
+ const result = await loadBalancer.executeRequest(
639
+ async (url) => {
640
+ const response = await fetch(`${url}/api/data`);
641
+ return response.json();
642
+ },
643
+ 'weighted'
644
+ );
645
+ ```
646
+
647
+ ### Implementing Database Connection Pooling
648
+
649
+ **Connection Pool**
650
+ ```typescript
651
+ import { Pool, PoolClient } from 'pg';
652
+
653
+ class DatabasePool {
654
+ private pool: Pool;
655
+
656
+ constructor() {
657
+ this.pool = new Pool({
658
+ host: process.env.DB_HOST,
659
+ port: parseInt(process.env.DB_PORT || '5432'),
660
+ database: process.env.DB_NAME,
661
+ user: process.env.DB_USER,
662
+ password: process.env.DB_PASSWORD,
663
+
664
+ // Pool configuration
665
+ min: 2, // Minimum connections
666
+ max: 10, // Maximum connections
667
+ idleTimeoutMillis: 30000, // Close idle connections after 30s
668
+ connectionTimeoutMillis: 2000, // Wait 2s for connection
669
+
670
+ // Connection validation
671
+ allowExitOnIdle: true
672
+ });
673
+
674
+ // Monitor pool events
675
+ this.pool.on('connect', () => {
676
+ console.log('New client connected to pool');
677
+ });
678
+
679
+ this.pool.on('error', (err) => {
680
+ console.error('Unexpected pool error', err);
681
+ });
682
+ }
683
+
684
+ async query<T>(sql: string, params?: any[]): Promise<T[]> {
685
+ const client = await this.pool.connect();
686
+
687
+ try {
688
+ const result = await client.query(sql, params);
689
+ return result.rows;
690
+ } finally {
691
+ client.release(); // Return connection to pool
692
+ }
693
+ }
694
+
695
+ async transaction<T>(
696
+ callback: (client: PoolClient) => Promise<T>
697
+ ): Promise<T> {
698
+ const client = await this.pool.connect();
699
+
700
+ try {
701
+ await client.query('BEGIN');
702
+ const result = await callback(client);
703
+ await client.query('COMMIT');
704
+ return result;
705
+ } catch (error) {
706
+ await client.query('ROLLBACK');
707
+ throw error;
708
+ } finally {
709
+ client.release();
710
+ }
711
+ }
712
+
713
+ async close(): Promise<void> {
714
+ await this.pool.end();
715
+ }
716
+ }
717
+
718
+ // Usage
719
+ const db = new DatabasePool();
720
+
721
+ // Simple query
722
+ const users = await db.query<User>(
723
+ 'SELECT * FROM users WHERE active = $1',
724
+ [true]
725
+ );
726
+
727
+ // Transaction
728
+ await db.transaction(async (client) => {
729
+ await client.query(
730
+ 'INSERT INTO orders (user_id, total) VALUES ($1, $2)',
731
+ [userId, total]
732
+ );
733
+
734
+ await client.query(
735
+ 'UPDATE inventory SET quantity = quantity - $1 WHERE product_id = $2',
736
+ [quantity, productId]
737
+ );
738
+ });
739
+ ```
740
+
741
+ ### Implementing Asynchronous Processing
742
+
743
+ **Message Queue with Bull (Redis-based)**
744
+ ```typescript
745
+ import Queue from 'bull';
746
+
747
+ // Define job data types
748
+ interface EmailJob {
749
+ to: string;
750
+ subject: string;
751
+ body: string;
752
+ }
753
+
754
+ interface ImageProcessingJob {
755
+ imageUrl: string;
756
+ operations: Array<'resize' | 'compress' | 'watermark'>;
757
+ }
758
+
759
+ class QueueService {
760
+ private emailQueue: Queue.Queue<EmailJob>;
761
+ private imageQueue: Queue.Queue<ImageProcessingJob>;
762
+
763
+ constructor() {
764
+ const redisConfig = {
765
+ host: process.env.REDIS_HOST,
766
+ port: parseInt(process.env.REDIS_PORT || '6379'),
767
+ password: process.env.REDIS_PASSWORD
768
+ };
769
+
770
+ // Create queues
771
+ this.emailQueue = new Queue<EmailJob>('email', {
772
+ redis: redisConfig,
773
+ defaultJobOptions: {
774
+ attempts: 3,
775
+ backoff: {
776
+ type: 'exponential',
777
+ delay: 2000
778
+ },
779
+ removeOnComplete: true,
780
+ removeOnFail: false
781
+ }
782
+ });
783
+
784
+ this.imageQueue = new Queue<ImageProcessingJob>('image-processing', {
785
+ redis: redisConfig,
786
+ defaultJobOptions: {
787
+ attempts: 2,
788
+ timeout: 60000 // 1 minute timeout
789
+ }
790
+ });
791
+
792
+ // Set up processors
793
+ this.setupProcessors();
794
+ }
795
+
796
+ private setupProcessors(): void {
797
+ // Email processor
798
+ this.emailQueue.process(5, async (job) => {
799
+ console.log(`Processing email job ${job.id}`);
800
+
801
+ const { to, subject, body } = job.data;
802
+
803
+ // Simulate email sending
804
+ await this.sendEmail(to, subject, body);
805
+
806
+ // Update progress
807
+ await job.progress(100);
808
+
809
+ return { sent: true, timestamp: new Date() };
810
+ });
811
+
812
+ // Image processing processor
813
+ this.imageQueue.process(3, async (job) => {
814
+ console.log(`Processing image job ${job.id}`);
815
+
816
+ const { imageUrl, operations } = job.data;
817
+
818
+ let processedUrl = imageUrl;
819
+
820
+ for (let i = 0; i < operations.length; i++) {
821
+ const operation = operations[i];
822
+ processedUrl = await this.processImage(processedUrl, operation);
823
+
824
+ // Update progress
825
+ await job.progress(((i + 1) / operations.length) * 100);
826
+ }
827
+
828
+ return { processedUrl };
829
+ });
830
+
831
+ // Error handling
832
+ this.emailQueue.on('failed', (job, err) => {
833
+ console.error(`Email job ${job.id} failed:`, err);
834
+ });
835
+
836
+ this.imageQueue.on('failed', (job, err) => {
837
+ console.error(`Image job ${job.id} failed:`, err);
838
+ });
839
+ }
840
+
841
+ async addEmailJob(data: EmailJob, priority?: number): Promise<string> {
842
+ const job = await this.emailQueue.add(data, {
843
+ priority: priority || 0
844
+ });
845
+
846
+ return job.id.toString();
847
+ }
848
+
849
+ async addImageProcessingJob(
850
+ data: ImageProcessingJob,
851
+ delay?: number
852
+ ): Promise<string> {
853
+ const job = await this.imageQueue.add(data, {
854
+ delay: delay || 0
855
+ });
856
+
857
+ return job.id.toString();
858
+ }
859
+
860
+ async getJobStatus(
861
+ queueName: 'email' | 'image-processing',
862
+ jobId: string
863
+ ): Promise<any> {
864
+ const queue = queueName === 'email' ? this.emailQueue : this.imageQueue;
865
+ const job = await queue.getJob(jobId);
866
+
867
+ if (!job) {
868
+ return null;
869
+ }
870
+
871
+ return {
872
+ id: job.id,
873
+ state: await job.getState(),
874
+ progress: job.progress(),
875
+ data: job.data,
876
+ result: job.returnvalue,
877
+ failedReason: job.failedReason
878
+ };
879
+ }
880
+
881
+ private async sendEmail(to: string, subject: string, body: string): Promise<void> {
882
+ // Implement actual email sending
883
+ await new Promise(resolve => setTimeout(resolve, 1000));
884
+ }
885
+
886
+ private async processImage(url: string, operation: string): Promise<string> {
887
+ // Implement actual image processing
888
+ await new Promise(resolve => setTimeout(resolve, 2000));
889
+ return `${url}-${operation}`;
890
+ }
891
+ }
892
+
893
+ // Usage
894
+ const queueService = new QueueService();
895
+
896
+ // Add email job
897
+ const emailJobId = await queueService.addEmailJob({
898
+ to: 'user@example.com',
899
+ subject: 'Welcome',
900
+ body: 'Welcome to our service!'
901
+ }, 1); // High priority
902
+
903
+ // Add image processing job with delay
904
+ const imageJobId = await queueService.addImageProcessingJob({
905
+ imageUrl: 'https://example.com/image.jpg',
906
+ operations: ['resize', 'compress', 'watermark']
907
+ }, 5000); // Process after 5 seconds
908
+
909
+ // Check job status
910
+ const status = await queueService.getJobStatus('email', emailJobId);
911
+ console.log('Job status:', status);
912
+ ```
913
+
914
+ ---
915
+
916
+ ## Examples
917
+
918
+ ### Database Query Optimization
919
+
920
+ **N+1 Query Problem**
921
+ ```typescript
922
+ // Bad: N+1 queries
923
+ async function getOrdersWithCustomers(): Promise<OrderWithCustomer[]> {
924
+ const orders = await db.query<Order>('SELECT * FROM orders');
925
+
926
+ const ordersWithCustomers = [];
927
+ for (const order of orders) {
928
+ // N additional queries!
929
+ const customer = await db.query<Customer>(
930
+ 'SELECT * FROM customers WHERE id = $1',
931
+ [order.customerId]
932
+ );
933
+
934
+ ordersWithCustomers.push({
935
+ ...order,
936
+ customer: customer[0]
937
+ });
938
+ }
939
+
940
+ return ordersWithCustomers;
941
+ }
942
+
943
+ // Good: Single query with JOIN
944
+ async function getOrdersWithCustomers(): Promise<OrderWithCustomer[]> {
945
+ const rows = await db.query(`
946
+ SELECT
947
+ o.id as order_id,
948
+ o.total,
949
+ o.created_at,
950
+ c.id as customer_id,
951
+ c.name as customer_name,
952
+ c.email as customer_email
953
+ FROM orders o
954
+ JOIN customers c ON o.customer_id = c.id
955
+ `);
956
+
957
+ return rows.map(row => ({
958
+ id: row.order_id,
959
+ total: row.total,
960
+ createdAt: row.created_at,
961
+ customer: {
962
+ id: row.customer_id,
963
+ name: row.customer_name,
964
+ email: row.customer_email
965
+ }
966
+ }));
967
+ }
968
+
969
+ // Better: Use DataLoader for batching
970
+ import DataLoader from 'dataloader';
971
+
972
+ const customerLoader = new DataLoader(async (customerIds: string[]) => {
973
+ const customers = await db.query<Customer>(
974
+ 'SELECT * FROM customers WHERE id = ANY($1)',
975
+ [customerIds]
976
+ );
977
+
978
+ // Return in same order as requested
979
+ const customerMap = new Map(customers.map(c => [c.id, c]));
980
+ return customerIds.map(id => customerMap.get(id) || null);
981
+ });
982
+
983
+ async function getOrdersWithCustomers(): Promise<OrderWithCustomer[]> {
984
+ const orders = await db.query<Order>('SELECT * FROM orders');
985
+
986
+ // Batch load all customers in single query
987
+ const ordersWithCustomers = await Promise.all(
988
+ orders.map(async (order) => ({
989
+ ...order,
990
+ customer: await customerLoader.load(order.customerId)
991
+ }))
992
+ );
993
+
994
+ return ordersWithCustomers;
995
+ }
996
+ ```
997
+
998
+ **Database Indexing**
999
+ ```sql
1000
+ -- Bad: No index on frequently queried column
1001
+ SELECT * FROM orders WHERE customer_id = '123';
1002
+ -- Full table scan!
1003
+
1004
+ -- Good: Add index
1005
+ CREATE INDEX idx_orders_customer_id ON orders(customer_id);
1006
+
1007
+ -- Composite index for multiple columns
1008
+ CREATE INDEX idx_orders_customer_status ON orders(customer_id, status);
1009
+
1010
+ -- Partial index for specific conditions
1011
+ CREATE INDEX idx_orders_pending ON orders(created_at)
1012
+ WHERE status = 'pending';
1013
+
1014
+ -- Covering index (includes all needed columns)
1015
+ CREATE INDEX idx_orders_covering ON orders(customer_id, status, total, created_at);
1016
+ ```
1017
+
1018
+ ### Caching Strategies
1019
+
1020
+ **Multi-Level Caching**
1021
+ ```typescript
1022
+ class MultiLevelCache {
1023
+ constructor(
1024
+ private l1Cache: Map<string, any>, // In-memory (fast, small)
1025
+ private l2Cache: CacheService // Redis (slower, larger)
1026
+ ) {}
1027
+
1028
+ async get<T>(key: string): Promise<T | null> {
1029
+ // Try L1 cache (in-memory)
1030
+ if (this.l1Cache.has(key)) {
1031
+ return this.l1Cache.get(key);
1032
+ }
1033
+
1034
+ // Try L2 cache (Redis)
1035
+ const value = await this.l2Cache.get<T>(key);
1036
+
1037
+ if (value) {
1038
+ // Populate L1 cache
1039
+ this.l1Cache.set(key, value);
1040
+ }
1041
+
1042
+ return value;
1043
+ }
1044
+
1045
+ async set<T>(key: string, value: T, ttl?: number): Promise<void> {
1046
+ // Set in both caches
1047
+ this.l1Cache.set(key, value);
1048
+ await this.l2Cache.set(key, value, ttl);
1049
+ }
1050
+
1051
+ async delete(key: string): Promise<void> {
1052
+ this.l1Cache.delete(key);
1053
+ await this.l2Cache.delete(key);
1054
+ }
1055
+ }
1056
+ ```
1057
+
1058
+ **Cache Stampede Prevention**
1059
+ ```typescript
1060
+ class CacheWithStampedePrevention {
1061
+ private locks = new Map<string, Promise<any>>();
1062
+
1063
+ constructor(private cache: CacheService) {}
1064
+
1065
+ async get<T>(
1066
+ key: string,
1067
+ loader: () => Promise<T>,
1068
+ ttl: number = 3600
1069
+ ): Promise<T> {
1070
+ // Try cache first
1071
+ const cached = await this.cache.get<T>(key);
1072
+ if (cached) {
1073
+ return cached;
1074
+ }
1075
+
1076
+ // Check if another request is already loading this key
1077
+ if (this.locks.has(key)) {
1078
+ return this.locks.get(key);
1079
+ }
1080
+
1081
+ // Create lock (promise) for this key
1082
+ const loadPromise = (async () => {
1083
+ try {
1084
+ const value = await loader();
1085
+ await this.cache.set(key, value, ttl);
1086
+ return value;
1087
+ } finally {
1088
+ this.locks.delete(key);
1089
+ }
1090
+ })();
1091
+
1092
+ this.locks.set(key, loadPromise);
1093
+
1094
+ return loadPromise;
1095
+ }
1096
+ }
1097
+
1098
+ // Usage
1099
+ const cache = new CacheWithStampedePrevention(cacheService);
1100
+
1101
+ // Multiple concurrent requests for same key will only trigger one database query
1102
+ const [result1, result2, result3] = await Promise.all([
1103
+ cache.get('user:123', () => db.getUserById('123')),
1104
+ cache.get('user:123', () => db.getUserById('123')),
1105
+ cache.get('user:123', () => db.getUserById('123'))
1106
+ ]);
1107
+ // Only one database query executed!
1108
+ ```
1109
+
1110
+ ### Performance Monitoring
1111
+
1112
+ **Response Time Tracking**
1113
+ ```typescript
1114
+ class PerformanceMonitor {
1115
+ private metrics = new Map<string, number[]>();
1116
+
1117
+ async measure<T>(
1118
+ operation: string,
1119
+ fn: () => Promise<T>
1120
+ ): Promise<T> {
1121
+ const start = Date.now();
1122
+
1123
+ try {
1124
+ const result = await fn();
1125
+ const duration = Date.now() - start;
1126
+
1127
+ this.recordMetric(operation, duration);
1128
+
1129
+ return result;
1130
+ } catch (error) {
1131
+ const duration = Date.now() - start;
1132
+ this.recordMetric(`${operation}:error`, duration);
1133
+ throw error;
1134
+ }
1135
+ }
1136
+
1137
+ private recordMetric(operation: string, duration: number): void {
1138
+ if (!this.metrics.has(operation)) {
1139
+ this.metrics.set(operation, []);
1140
+ }
1141
+
1142
+ this.metrics.get(operation)!.push(duration);
1143
+
1144
+ // Keep only last 1000 measurements
1145
+ const measurements = this.metrics.get(operation)!;
1146
+ if (measurements.length > 1000) {
1147
+ measurements.shift();
1148
+ }
1149
+ }
1150
+
1151
+ getStats(operation: string): PerformanceStats | null {
1152
+ const measurements = this.metrics.get(operation);
1153
+
1154
+ if (!measurements || measurements.length === 0) {
1155
+ return null;
1156
+ }
1157
+
1158
+ const sorted = [...measurements].sort((a, b) => a - b);
1159
+
1160
+ return {
1161
+ count: measurements.length,
1162
+ min: sorted[0],
1163
+ max: sorted[sorted.length - 1],
1164
+ avg: measurements.reduce((a, b) => a + b, 0) / measurements.length,
1165
+ p50: sorted[Math.floor(sorted.length * 0.5)],
1166
+ p95: sorted[Math.floor(sorted.length * 0.95)],
1167
+ p99: sorted[Math.floor(sorted.length * 0.99)]
1168
+ };
1169
+ }
1170
+
1171
+ getAllStats(): Map<string, PerformanceStats> {
1172
+ const stats = new Map<string, PerformanceStats>();
1173
+
1174
+ for (const operation of this.metrics.keys()) {
1175
+ const operationStats = this.getStats(operation);
1176
+ if (operationStats) {
1177
+ stats.set(operation, operationStats);
1178
+ }
1179
+ }
1180
+
1181
+ return stats;
1182
+ }
1183
+ }
1184
+
1185
+ interface PerformanceStats {
1186
+ count: number;
1187
+ min: number;
1188
+ max: number;
1189
+ avg: number;
1190
+ p50: number;
1191
+ p95: number;
1192
+ p99: number;
1193
+ }
1194
+
1195
+ // Usage
1196
+ const monitor = new PerformanceMonitor();
1197
+
1198
+ const user = await monitor.measure('db:getUser', async () => {
1199
+ return userRepository.findById(userId);
1200
+ });
1201
+
1202
+ // Get statistics
1203
+ const stats = monitor.getStats('db:getUser');
1204
+ console.log('Database query performance:', stats);
1205
+ // { count: 1000, min: 5, max: 250, avg: 25, p50: 20, p95: 50, p99: 100 }
1206
+ ```
1207
+
1208
+ ---
1209
+
1210
+ ## Understanding
1211
+
1212
+ ### Scalability Patterns
1213
+
1214
+ **CQRS (Command Query Responsibility Segregation)**
1215
+ - Separate read and write models
1216
+ - Optimize each independently
1217
+ - Scale reads and writes separately
1218
+ - Eventual consistency between models
1219
+
1220
+ **Event Sourcing**
1221
+ - Store events instead of current state
1222
+ - Rebuild state from events
1223
+ - Complete audit trail
1224
+ - Enables time travel and replay
1225
+
1226
+ **Saga Pattern**
1227
+ - Manage distributed transactions
1228
+ - Compensating transactions for rollback
1229
+ - Eventual consistency
1230
+ - Complex but scalable
1231
+
1232
+ ### Performance Testing
1233
+
1234
+ **Load Testing**
1235
+ - Test system under expected load
1236
+ - Identify performance bottlenecks
1237
+ - Validate scalability
1238
+ - Tools: Apache JMeter, k6, Gatling
1239
+
1240
+ **Stress Testing**
1241
+ - Test system beyond normal capacity
1242
+ - Find breaking point
1243
+ - Identify failure modes
1244
+ - Plan for peak loads
1245
+
1246
+ **Spike Testing**
1247
+ - Sudden increase in load
1248
+ - Test auto-scaling
1249
+ - Identify resource limits
1250
+ - Plan for traffic spikes
1251
+
1252
+ **Endurance Testing**
1253
+ - Sustained load over time
1254
+ - Identify memory leaks
1255
+ - Test resource cleanup
1256
+ - Validate long-term stability
1257
+
1258
+ ### Best Practices
1259
+
1260
+ 1. **Measure Before Optimizing**
1261
+ - Profile to find bottlenecks
1262
+ - Don't guess, measure
1263
+ - Focus on biggest impact
1264
+ - Avoid premature optimization
1265
+
1266
+ 2. **Cache Strategically**
1267
+ - Cache expensive operations
1268
+ - Set appropriate TTLs
1269
+ - Implement cache invalidation
1270
+ - Monitor cache hit rates
1271
+
1272
+ 3. **Design for Horizontal Scaling**
1273
+ - Stateless services
1274
+ - Externalize session state
1275
+ - Use load balancers
1276
+ - Enable auto-scaling
1277
+
1278
+ 4. **Optimize Database Access**
1279
+ - Use indexes wisely
1280
+ - Avoid N+1 queries
1281
+ - Use connection pooling
1282
+ - Consider read replicas
1283
+
1284
+ 5. **Implement Asynchronous Processing**
1285
+ - Decouple long-running tasks
1286
+ - Use message queues
1287
+ - Implement retry logic
1288
+ - Monitor queue depth
1289
+
1290
+ 6. **Monitor and Alert**
1291
+ - Track key metrics (latency, throughput, errors)
1292
+ - Set up alerts for anomalies
1293
+ - Use distributed tracing
1294
+ - Implement health checks
1295
+
1296
+ ### Common Pitfalls
1297
+
1298
+ 1. **Premature Optimization**
1299
+ - Optimizing before measuring
1300
+ - Adding complexity without benefit
1301
+ - Focus on correctness first
1302
+
1303
+ 2. **Over-Caching**
1304
+ - Caching everything
1305
+ - Stale data issues
1306
+ - Memory pressure
1307
+ - Cache invalidation complexity
1308
+
1309
+ 3. **Ignoring Database Performance**
1310
+ - Missing indexes
1311
+ - N+1 queries
1312
+ - Large result sets
1313
+ - Inefficient queries
1314
+
1315
+ 4. **Synchronous Processing**
1316
+ - Blocking on long operations
1317
+ - Poor user experience
1318
+ - Resource waste
1319
+ - Limited scalability
1320
+
1321
+ 5. **Single Point of Failure**
1322
+ - No redundancy
1323
+ - No failover
1324
+ - Downtime risk
1325
+ - Scalability limit
1326
+
1327
+ 6. **Insufficient Monitoring**
1328
+ - No visibility into performance
1329
+ - Can't identify bottlenecks
1330
+ - Reactive instead of proactive
1331
+ - Difficult troubleshooting
1332
+
1333
+ ---
1334
+
1335
+ ## References
1336
+
1337
+ - **Designing Data-Intensive Applications**: Martin Kleppmann
1338
+ - **High Performance Browser Networking**: Ilya Grigorik
1339
+ - **Site Reliability Engineering**: Google
1340
+ - **The Art of Scalability**: Martin L. Abbott, Michael T. Fisher
1341
+ - **Database Internals**: Alex Petrov
1342
+ - **Redis in Action**: Josiah L. Carlson
1343
+ - **CAP Theorem**: Eric Brewer
1344
+ - **Latency Numbers**: Jeff Dean (Google)
1345
+