@engjts/nexus 0.1.7 → 0.1.9
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.
- package/dist/advanced/playground/generatePlaygroundHTML.d.ts.map +1 -1
- package/dist/advanced/playground/generatePlaygroundHTML.js +107 -0
- package/dist/advanced/playground/generatePlaygroundHTML.js.map +1 -1
- package/dist/advanced/playground/playground.d.ts +19 -0
- package/dist/advanced/playground/playground.d.ts.map +1 -1
- package/dist/advanced/playground/playground.js +70 -0
- package/dist/advanced/playground/playground.js.map +1 -1
- package/dist/advanced/playground/types.d.ts +20 -0
- package/dist/advanced/playground/types.d.ts.map +1 -1
- package/dist/core/application.d.ts +14 -0
- package/dist/core/application.d.ts.map +1 -1
- package/dist/core/application.js +173 -71
- package/dist/core/application.js.map +1 -1
- package/dist/core/context-pool.d.ts +2 -13
- package/dist/core/context-pool.d.ts.map +1 -1
- package/dist/core/context-pool.js +7 -45
- package/dist/core/context-pool.js.map +1 -1
- package/dist/core/context.d.ts +108 -5
- package/dist/core/context.d.ts.map +1 -1
- package/dist/core/context.js +449 -53
- package/dist/core/context.js.map +1 -1
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +9 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/middleware.d.ts +6 -0
- package/dist/core/middleware.d.ts.map +1 -1
- package/dist/core/middleware.js +83 -84
- package/dist/core/middleware.js.map +1 -1
- package/dist/core/performance/fast-json.d.ts +149 -0
- package/dist/core/performance/fast-json.d.ts.map +1 -0
- package/dist/core/performance/fast-json.js +473 -0
- package/dist/core/performance/fast-json.js.map +1 -0
- package/dist/core/router/file-router.d.ts +20 -7
- package/dist/core/router/file-router.d.ts.map +1 -1
- package/dist/core/router/file-router.js +41 -13
- package/dist/core/router/file-router.js.map +1 -1
- package/dist/core/router/index.d.ts +6 -0
- package/dist/core/router/index.d.ts.map +1 -1
- package/dist/core/router/index.js +33 -6
- package/dist/core/router/index.js.map +1 -1
- package/dist/core/router/radix-tree.d.ts +4 -1
- package/dist/core/router/radix-tree.d.ts.map +1 -1
- package/dist/core/router/radix-tree.js +7 -3
- package/dist/core/router/radix-tree.js.map +1 -1
- package/dist/core/serializer.d.ts +251 -0
- package/dist/core/serializer.d.ts.map +1 -0
- package/dist/core/serializer.js +290 -0
- package/dist/core/serializer.js.map +1 -0
- package/dist/core/types.d.ts +39 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -2
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
- package/documentation/01-getting-started.md +0 -240
- package/documentation/02-context.md +0 -335
- package/documentation/03-routing.md +0 -397
- package/documentation/04-middleware.md +0 -483
- package/documentation/05-validation.md +0 -514
- package/documentation/06-error-handling.md +0 -465
- package/documentation/07-performance.md +0 -364
- package/documentation/08-adapters.md +0 -470
- package/documentation/09-api-reference.md +0 -548
- package/documentation/10-examples.md +0 -582
- package/documentation/11-deployment.md +0 -477
- package/documentation/12-sentry.md +0 -620
- package/documentation/13-sentry-data-storage.md +0 -996
- package/documentation/14-sentry-data-reference.md +0 -457
- package/documentation/15-sentry-summary.md +0 -409
- package/documentation/16-alerts-system.md +0 -745
- package/documentation/17-alert-adapters.md +0 -696
- package/documentation/18-alerts-implementation-summary.md +0 -385
- package/documentation/19-class-based-routing.md +0 -840
- package/documentation/20-websocket-realtime.md +0 -813
- package/documentation/21-cache-system.md +0 -510
- package/documentation/22-job-queue.md +0 -772
- package/documentation/23-sentry-plugin.md +0 -551
- package/documentation/24-testing-utilities.md +0 -1287
- package/documentation/25-api-versioning.md +0 -533
- package/documentation/26-context-store.md +0 -607
- package/documentation/27-dependency-injection.md +0 -329
- package/documentation/28-lifecycle-hooks.md +0 -521
- package/documentation/29-package-structure.md +0 -196
- package/documentation/30-plugin-system.md +0 -414
- package/documentation/31-jwt-authentication.md +0 -597
- package/documentation/32-cli.md +0 -268
- package/documentation/ALERTS-COMPLETE-SUMMARY.md +0 -429
- package/documentation/ALERTS-INDEX.md +0 -330
- package/documentation/ALERTS-QUICK-REFERENCE.md +0 -286
- package/documentation/README.md +0 -178
- package/documentation/index.html +0 -34
- package/modern_framework_paper.md +0 -1870
- package/public/css/style.css +0 -87
- package/public/index.html +0 -34
- package/public/js/app.js +0 -27
- package/src/advanced/cache/InMemoryCacheStore.ts +0 -68
- package/src/advanced/cache/MultiTierCache.ts +0 -194
- package/src/advanced/cache/RedisCacheStore.ts +0 -341
- package/src/advanced/cache/index.ts +0 -5
- package/src/advanced/cache/types.ts +0 -40
- package/src/advanced/graphql/SimpleDataLoader.ts +0 -42
- package/src/advanced/graphql/index.ts +0 -22
- package/src/advanced/graphql/server.ts +0 -252
- package/src/advanced/graphql/types.ts +0 -42
- package/src/advanced/jobs/InMemoryQueueStore.ts +0 -68
- package/src/advanced/jobs/JobQueue.ts +0 -556
- package/src/advanced/jobs/RedisQueueStore.ts +0 -367
- package/src/advanced/jobs/index.ts +0 -5
- package/src/advanced/jobs/types.ts +0 -70
- package/src/advanced/observability/APMManager.ts +0 -163
- package/src/advanced/observability/AlertManager.ts +0 -109
- package/src/advanced/observability/MetricRegistry.ts +0 -151
- package/src/advanced/observability/ObservabilityCenter.ts +0 -304
- package/src/advanced/observability/StructuredLogger.ts +0 -154
- package/src/advanced/observability/TracingManager.ts +0 -117
- package/src/advanced/observability/adapters.ts +0 -304
- package/src/advanced/observability/createObservabilityMiddleware.ts +0 -63
- package/src/advanced/observability/index.ts +0 -11
- package/src/advanced/observability/types.ts +0 -174
- package/src/advanced/playground/extractPathParams.ts +0 -6
- package/src/advanced/playground/generateFieldExample.ts +0 -31
- package/src/advanced/playground/generatePlaygroundHTML.ts +0 -1849
- package/src/advanced/playground/generateSummary.ts +0 -19
- package/src/advanced/playground/getTagFromPath.ts +0 -9
- package/src/advanced/playground/index.ts +0 -8
- package/src/advanced/playground/playground.ts +0 -170
- package/src/advanced/playground/types.ts +0 -20
- package/src/advanced/playground/zodToExample.ts +0 -16
- package/src/advanced/playground/zodToParams.ts +0 -15
- package/src/advanced/postman/buildAuth.ts +0 -31
- package/src/advanced/postman/buildBody.ts +0 -15
- package/src/advanced/postman/buildQueryParams.ts +0 -27
- package/src/advanced/postman/buildRequestItem.ts +0 -36
- package/src/advanced/postman/buildResponses.ts +0 -11
- package/src/advanced/postman/buildUrl.ts +0 -33
- package/src/advanced/postman/capitalize.ts +0 -4
- package/src/advanced/postman/generateCollection.ts +0 -59
- package/src/advanced/postman/generateEnvironment.ts +0 -34
- package/src/advanced/postman/generateExampleFromZod.ts +0 -21
- package/src/advanced/postman/generateFieldExample.ts +0 -45
- package/src/advanced/postman/generateName.ts +0 -20
- package/src/advanced/postman/generateUUID.ts +0 -11
- package/src/advanced/postman/getTagFromPath.ts +0 -10
- package/src/advanced/postman/index.ts +0 -28
- package/src/advanced/postman/postman.ts +0 -156
- package/src/advanced/postman/slugify.ts +0 -7
- package/src/advanced/postman/types.ts +0 -140
- package/src/advanced/realtime/index.ts +0 -18
- package/src/advanced/realtime/websocket.ts +0 -231
- package/src/advanced/sentry/index.ts +0 -1236
- package/src/advanced/sentry/types.ts +0 -355
- package/src/advanced/static/generateDirectoryListing.ts +0 -47
- package/src/advanced/static/generateETag.ts +0 -7
- package/src/advanced/static/getMimeType.ts +0 -9
- package/src/advanced/static/index.ts +0 -32
- package/src/advanced/static/isSafePath.ts +0 -13
- package/src/advanced/static/publicDir.ts +0 -21
- package/src/advanced/static/serveStatic.ts +0 -225
- package/src/advanced/static/spa.ts +0 -24
- package/src/advanced/static/types.ts +0 -159
- package/src/advanced/swagger/SwaggerGenerator.ts +0 -66
- package/src/advanced/swagger/buildOperation.ts +0 -61
- package/src/advanced/swagger/buildParameters.ts +0 -61
- package/src/advanced/swagger/buildRequestBody.ts +0 -21
- package/src/advanced/swagger/buildResponses.ts +0 -54
- package/src/advanced/swagger/capitalize.ts +0 -5
- package/src/advanced/swagger/convertPath.ts +0 -9
- package/src/advanced/swagger/createSwagger.ts +0 -12
- package/src/advanced/swagger/generateOperationId.ts +0 -21
- package/src/advanced/swagger/generateSpec.ts +0 -105
- package/src/advanced/swagger/generateSummary.ts +0 -24
- package/src/advanced/swagger/generateSwaggerUI.ts +0 -70
- package/src/advanced/swagger/generateThemeCss.ts +0 -53
- package/src/advanced/swagger/index.ts +0 -25
- package/src/advanced/swagger/swagger.ts +0 -237
- package/src/advanced/swagger/types.ts +0 -206
- package/src/advanced/swagger/zodFieldToOpenAPI.ts +0 -94
- package/src/advanced/swagger/zodSchemaToOpenAPI.ts +0 -50
- package/src/advanced/swagger/zodToOpenAPI.ts +0 -22
- package/src/advanced/testing/factory.ts +0 -509
- package/src/advanced/testing/harness.ts +0 -612
- package/src/advanced/testing/index.ts +0 -430
- package/src/advanced/testing/load-test.ts +0 -618
- package/src/advanced/testing/mock-server.ts +0 -498
- package/src/advanced/testing/mock.ts +0 -670
- package/src/cli/bin.ts +0 -9
- package/src/cli/cli.ts +0 -158
- package/src/cli/commands/add.ts +0 -178
- package/src/cli/commands/build.ts +0 -73
- package/src/cli/commands/create.ts +0 -166
- package/src/cli/commands/dev.ts +0 -85
- package/src/cli/commands/generate.ts +0 -99
- package/src/cli/commands/help.ts +0 -95
- package/src/cli/commands/init.ts +0 -91
- package/src/cli/commands/version.ts +0 -38
- package/src/cli/index.ts +0 -6
- package/src/cli/templates/generators.ts +0 -359
- package/src/cli/templates/index.ts +0 -680
- package/src/cli/utils/exec.ts +0 -52
- package/src/cli/utils/file-system.ts +0 -78
- package/src/cli/utils/logger.ts +0 -111
- package/src/core/adapter.ts +0 -88
- package/src/core/application.ts +0 -1335
- package/src/core/context-pool.ts +0 -127
- package/src/core/context.ts +0 -412
- package/src/core/index.ts +0 -80
- package/src/core/middleware.ts +0 -262
- package/src/core/performance/buffer-pool.ts +0 -108
- package/src/core/performance/middleware-optimizer.ts +0 -162
- package/src/core/plugin/PluginManager.ts +0 -435
- package/src/core/plugin/builder.ts +0 -358
- package/src/core/plugin/index.ts +0 -50
- package/src/core/plugin/types.ts +0 -214
- package/src/core/router/file-router.ts +0 -594
- package/src/core/router/index.ts +0 -227
- package/src/core/router/radix-tree.ts +0 -226
- package/src/core/store/index.ts +0 -30
- package/src/core/store/registry.ts +0 -178
- package/src/core/store/request-store.ts +0 -240
- package/src/core/store/types.ts +0 -233
- package/src/core/types.ts +0 -574
- package/src/database/adapter.ts +0 -35
- package/src/database/adapters/index.ts +0 -1
- package/src/database/adapters/mysql.ts +0 -669
- package/src/database/database.ts +0 -70
- package/src/database/dialect.ts +0 -388
- package/src/database/index.ts +0 -12
- package/src/database/migrations.ts +0 -86
- package/src/database/optimizer.ts +0 -125
- package/src/database/query-builder.ts +0 -404
- package/src/database/realtime.ts +0 -53
- package/src/database/schema.ts +0 -71
- package/src/database/transactions.ts +0 -56
- package/src/database/types.ts +0 -87
- package/src/deployment/cluster.ts +0 -471
- package/src/deployment/config.ts +0 -454
- package/src/deployment/docker.ts +0 -599
- package/src/deployment/graceful-shutdown.ts +0 -373
- package/src/deployment/index.ts +0 -56
- package/src/index.ts +0 -264
- package/src/security/adapter.ts +0 -318
- package/src/security/auth/JWTPlugin.ts +0 -234
- package/src/security/auth/JWTProvider.ts +0 -316
- package/src/security/auth/adapter.ts +0 -12
- package/src/security/auth/jwt.ts +0 -234
- package/src/security/auth/middleware.ts +0 -188
- package/src/security/csrf.ts +0 -220
- package/src/security/headers.ts +0 -108
- package/src/security/index.ts +0 -60
- package/src/security/rate-limit/adapter.ts +0 -7
- package/src/security/rate-limit/memory.ts +0 -108
- package/src/security/rate-limit/middleware.ts +0 -181
- package/src/security/sanitization.ts +0 -75
- package/src/security/types.ts +0 -240
- package/src/security/utils.ts +0 -52
- package/tsconfig.json +0 -39
|
@@ -1,510 +0,0 @@
|
|
|
1
|
-
# Cache System - Multi-Tier Caching untuk Nexus Framework
|
|
2
|
-
|
|
3
|
-
## Pendahuluan
|
|
4
|
-
|
|
5
|
-
Nexus Framework menyediakan **Multi-Tier Cache** system yang powerful untuk meningkatkan performa aplikasi. Sistem ini mendukung cache-aside pattern, memoization, tag-based invalidation, dan wildcard pattern matching.
|
|
6
|
-
|
|
7
|
-
## Instalasi & Setup
|
|
8
|
-
|
|
9
|
-
```typescript
|
|
10
|
-
import { MultiTierCache, InMemoryCacheStore } from 'nexus';
|
|
11
|
-
|
|
12
|
-
// Setup cache dengan 1 tier (in-memory)
|
|
13
|
-
const cache = new MultiTierCache([
|
|
14
|
-
{
|
|
15
|
-
store: new InMemoryCacheStore('primary', 10_000), // max 10k entries
|
|
16
|
-
ttl: 60_000 // 1 menit default TTL
|
|
17
|
-
}
|
|
18
|
-
]);
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## API Reference
|
|
22
|
-
|
|
23
|
-
### 1. `cache.get(key)`
|
|
24
|
-
|
|
25
|
-
Ambil value dari cache dengan key tertentu.
|
|
26
|
-
|
|
27
|
-
```typescript
|
|
28
|
-
const value = await cache.get('user:123');
|
|
29
|
-
if (value) {
|
|
30
|
-
console.log('Found in cache:', value);
|
|
31
|
-
} else {
|
|
32
|
-
console.log('Cache miss');
|
|
33
|
-
}
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
**Return**: `Value | undefined`
|
|
37
|
-
|
|
38
|
-
---
|
|
39
|
-
|
|
40
|
-
### 2. `cache.set(key, value, options)`
|
|
41
|
-
|
|
42
|
-
Simpan value ke cache dengan optional TTL dan tags.
|
|
43
|
-
|
|
44
|
-
```typescript
|
|
45
|
-
await cache.set('user:123', userData, {
|
|
46
|
-
ttl: 300_000, // 5 menit
|
|
47
|
-
tags: ['users', 'active-users'],
|
|
48
|
-
meta: { fetchedAt: new Date() }
|
|
49
|
-
});
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
**Options**:
|
|
53
|
-
- `ttl?: number` - Time to live dalam milliseconds
|
|
54
|
-
- `tags?: string[]` - Tag untuk group invalidation
|
|
55
|
-
- `meta?: Record<string, any>` - Metadata tambahan
|
|
56
|
-
|
|
57
|
-
---
|
|
58
|
-
|
|
59
|
-
### 3. `cache.wrap(key, resolver, options)`
|
|
60
|
-
|
|
61
|
-
Cache-aside pattern otomatis. Cek cache, jika miss jalankan resolver lalu simpan hasilnya.
|
|
62
|
-
|
|
63
|
-
```typescript
|
|
64
|
-
const user = await cache.wrap(
|
|
65
|
-
'user:123',
|
|
66
|
-
async () => {
|
|
67
|
-
// Hanya dipanggil jika cache miss
|
|
68
|
-
return await fetchUserFromDatabase(123);
|
|
69
|
-
},
|
|
70
|
-
{ ttl: 300_000, tags: ['users'] }
|
|
71
|
-
);
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
**Keuntungan**:
|
|
75
|
-
- Otomatis handle cache miss
|
|
76
|
-
- Lebih simple dan clean
|
|
77
|
-
- Menghindari race condition
|
|
78
|
-
|
|
79
|
-
---
|
|
80
|
-
|
|
81
|
-
### 4. `cache.memoize(fn, options)`
|
|
82
|
-
|
|
83
|
-
Wrap async function agar hasil cache otomatis.
|
|
84
|
-
|
|
85
|
-
```typescript
|
|
86
|
-
async function fetchOrders(userId: string) {
|
|
87
|
-
return await database.orders.findByUserId(userId);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Memoize dengan custom key resolver
|
|
91
|
-
const getCachedOrders = cache.memoize(fetchOrders, {
|
|
92
|
-
ttl: 300_000,
|
|
93
|
-
tags: ['orders'],
|
|
94
|
-
keyResolver: (userId) => `orders:${userId}`
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
// Panggil seperti biasa, tapi hasil di-cache
|
|
98
|
-
const orders = await getCachedOrders('user:123');
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
---
|
|
102
|
-
|
|
103
|
-
### 5. `cache.delete(key)`
|
|
104
|
-
|
|
105
|
-
Hapus satu cache key.
|
|
106
|
-
|
|
107
|
-
```typescript
|
|
108
|
-
await cache.delete('user:123');
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
---
|
|
112
|
-
|
|
113
|
-
### 6. `cache.deletePattern(pattern)`
|
|
114
|
-
|
|
115
|
-
Hapus cache dengan wildcard pattern.
|
|
116
|
-
|
|
117
|
-
```typescript
|
|
118
|
-
// Hapus semua cache user:123
|
|
119
|
-
await cache.deletePattern('user:123:*');
|
|
120
|
-
|
|
121
|
-
// Hapus semua cache dengan pattern
|
|
122
|
-
await cache.deletePattern('order:*:items');
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
**Pattern Syntax**:
|
|
126
|
-
- `*` = matches any characters (greedy)
|
|
127
|
-
- `?` = matches single character
|
|
128
|
-
|
|
129
|
-
---
|
|
130
|
-
|
|
131
|
-
### 7. `cache.invalidateTags(tags)`
|
|
132
|
-
|
|
133
|
-
Hapus semua cache dengan tag tertentu.
|
|
134
|
-
|
|
135
|
-
```typescript
|
|
136
|
-
// Hapus semua cache dengan tag 'users'
|
|
137
|
-
await cache.invalidateTags(['users']);
|
|
138
|
-
|
|
139
|
-
// Hapus cache dengan multiple tags
|
|
140
|
-
await cache.invalidateTags(['users', 'admin']);
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
**Gunakan untuk**: Invalidasi semua related data dalam satu operation.
|
|
144
|
-
|
|
145
|
-
---
|
|
146
|
-
|
|
147
|
-
### 8. `cache.getStats()`
|
|
148
|
-
|
|
149
|
-
Dapatkan statistik cache.
|
|
150
|
-
|
|
151
|
-
```typescript
|
|
152
|
-
const stats = cache.getStats();
|
|
153
|
-
console.log(stats);
|
|
154
|
-
// Output:
|
|
155
|
-
// {
|
|
156
|
-
// tiers: [{ name: 'primary' }, { name: 'secondary' }],
|
|
157
|
-
// tags: ['users', 'orders', 'products'],
|
|
158
|
-
// defaultTTL: 60000
|
|
159
|
-
// }
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
---
|
|
163
|
-
|
|
164
|
-
## Use Cases & Contoh
|
|
165
|
-
|
|
166
|
-
### Use Case 1: Simple User Data Cache
|
|
167
|
-
|
|
168
|
-
```typescript
|
|
169
|
-
app.get('/api/users/:id', async (ctx: Context) => {
|
|
170
|
-
const userId = ctx.params.id;
|
|
171
|
-
|
|
172
|
-
const user = await cache.wrap(
|
|
173
|
-
`user:${userId}`,
|
|
174
|
-
async () => fetchUserFromDB(userId),
|
|
175
|
-
{ ttl: 300_000, tags: ['users'] }
|
|
176
|
-
);
|
|
177
|
-
|
|
178
|
-
return user;
|
|
179
|
-
});
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
**Flow**:
|
|
183
|
-
1. Request pertama → Cache miss → Fetch dari DB (100ms) → Simpan cache
|
|
184
|
-
2. Request kedua → Cache hit → Response instant (0ms)
|
|
185
|
-
3. Request ketiga → Cache hit → Response instant (0ms)
|
|
186
|
-
|
|
187
|
-
---
|
|
188
|
-
|
|
189
|
-
### Use Case 2: Product Catalog dengan Cache Invalidation
|
|
190
|
-
|
|
191
|
-
```typescript
|
|
192
|
-
// GET product
|
|
193
|
-
app.get('/api/products/:id', async (ctx: Context) => {
|
|
194
|
-
return cache.wrap(
|
|
195
|
-
`product:${ctx.params.id}`,
|
|
196
|
-
() => fetchProduct(ctx.params.id),
|
|
197
|
-
{ ttl: 600_000, tags: ['products'] }
|
|
198
|
-
);
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
// UPDATE product → invalidate cache
|
|
202
|
-
app.put('/api/products/:id', async (ctx: Context) => {
|
|
203
|
-
const productId = ctx.params.id;
|
|
204
|
-
|
|
205
|
-
// Update database
|
|
206
|
-
await updateProductInDB(productId, ctx.body);
|
|
207
|
-
|
|
208
|
-
// Invalidate cache
|
|
209
|
-
await cache.delete(`product:${productId}`);
|
|
210
|
-
|
|
211
|
-
return { message: 'Product updated' };
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
// ADMIN: Clear all product cache
|
|
215
|
-
app.delete('/api/admin/cache/products', async () => {
|
|
216
|
-
await cache.invalidateTags(['products']);
|
|
217
|
-
return { message: 'All product cache cleared' };
|
|
218
|
-
});
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
---
|
|
222
|
-
|
|
223
|
-
### Use Case 3: Complex Query dengan Memoization
|
|
224
|
-
|
|
225
|
-
```typescript
|
|
226
|
-
// Fungsi yang expensive (slow query)
|
|
227
|
-
async function getUserStatistics(userId: string) {
|
|
228
|
-
return {
|
|
229
|
-
totalOrders: await countOrders(userId),
|
|
230
|
-
totalSpent: await sumOrderAmount(userId),
|
|
231
|
-
lastOrder: await getLastOrder(userId),
|
|
232
|
-
favoriteProducts: await getFavoriteProducts(userId)
|
|
233
|
-
};
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// Memoize dengan TTL 1 jam
|
|
237
|
-
const getStatsCached = cache.memoize(getUserStatistics, {
|
|
238
|
-
ttl: 3600_000,
|
|
239
|
-
tags: ['user-stats'],
|
|
240
|
-
keyResolver: (userId) => `stats:${userId}`
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
app.get('/api/users/:id/stats', async (ctx: Context) => {
|
|
244
|
-
// Cache hit: instant
|
|
245
|
-
// Cache miss: sekali hitung, kemudian di-cache
|
|
246
|
-
return getStatsCached(ctx.params.id);
|
|
247
|
-
});
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
---
|
|
251
|
-
|
|
252
|
-
### Use Case 4: Multi-Tier Cache (L1 & L2)
|
|
253
|
-
|
|
254
|
-
```typescript
|
|
255
|
-
const multiTierCache = new MultiTierCache([
|
|
256
|
-
// Tier 1: Ultra fast, limited size (L1)
|
|
257
|
-
{
|
|
258
|
-
store: new InMemoryCacheStore('l1', 1_000),
|
|
259
|
-
ttl: 30_000 // 30 detik
|
|
260
|
-
},
|
|
261
|
-
// Tier 2: Larger, longer TTL (L2)
|
|
262
|
-
{
|
|
263
|
-
store: new InMemoryCacheStore('l2', 50_000),
|
|
264
|
-
ttl: 300_000 // 5 menit
|
|
265
|
-
}
|
|
266
|
-
]);
|
|
267
|
-
|
|
268
|
-
// Cek L1 dulu, kalau miss cek L2
|
|
269
|
-
// Jika di-hit di L2, akan di-promote ke L1 untuk next request
|
|
270
|
-
const data = await multiTierCache.wrap(
|
|
271
|
-
'hot-data',
|
|
272
|
-
() => fetchExpensiveData(),
|
|
273
|
-
{ ttl: 300_000 }
|
|
274
|
-
);
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
**Behavior**:
|
|
278
|
-
- Request 1 → Miss L1 & L2 → Fetch data → Save di L1 & L2
|
|
279
|
-
- Request 2 → Hit L1 → Instant (0ms)
|
|
280
|
-
- Request 3 (setelah L1 expire) → Miss L1 → Hit L2 → Copy ke L1 → Return
|
|
281
|
-
|
|
282
|
-
---
|
|
283
|
-
|
|
284
|
-
### Use Case 5: Search Results Caching dengan Pattern
|
|
285
|
-
|
|
286
|
-
```typescript
|
|
287
|
-
// Cache search results dengan pattern
|
|
288
|
-
app.get('/api/search', async (ctx: Context) => {
|
|
289
|
-
const { q, page = 1 } = ctx.query;
|
|
290
|
-
const cacheKey = `search:${q}:${page}`;
|
|
291
|
-
|
|
292
|
-
return cache.wrap(
|
|
293
|
-
cacheKey,
|
|
294
|
-
() => searchDatabase(q, page),
|
|
295
|
-
{
|
|
296
|
-
ttl: 600_000,
|
|
297
|
-
tags: ['search', `search:${q}`] // tag by query
|
|
298
|
-
}
|
|
299
|
-
);
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
// Clear search results untuk query tertentu
|
|
303
|
-
app.delete('/api/search/:q/cache', async (ctx: Context) => {
|
|
304
|
-
await cache.deletePattern(`search:${ctx.params.q}:*`);
|
|
305
|
-
return { message: `Cleared search cache for "${ctx.params.q}"` };
|
|
306
|
-
});
|
|
307
|
-
```
|
|
308
|
-
|
|
309
|
-
---
|
|
310
|
-
|
|
311
|
-
## Performance Comparison
|
|
312
|
-
|
|
313
|
-
### Tanpa Cache
|
|
314
|
-
```
|
|
315
|
-
GET /api/users/1
|
|
316
|
-
├─ Database query: 100ms
|
|
317
|
-
├─ JSON serialization: 5ms
|
|
318
|
-
└─ Total: ~105ms
|
|
319
|
-
```
|
|
320
|
-
|
|
321
|
-
### Dengan Cache
|
|
322
|
-
```
|
|
323
|
-
GET /api/users/1 (first request)
|
|
324
|
-
├─ Cache miss: 0ms
|
|
325
|
-
├─ Database query: 100ms
|
|
326
|
-
├─ Save to cache: 1ms
|
|
327
|
-
└─ Total: ~101ms
|
|
328
|
-
|
|
329
|
-
GET /api/users/1 (second request)
|
|
330
|
-
├─ Cache hit: <1ms
|
|
331
|
-
└─ Total: <1ms
|
|
332
|
-
|
|
333
|
-
Performance improvement: 100x faster! 🚀
|
|
334
|
-
```
|
|
335
|
-
|
|
336
|
-
---
|
|
337
|
-
|
|
338
|
-
## Best Practices
|
|
339
|
-
|
|
340
|
-
### ✅ Do's
|
|
341
|
-
|
|
342
|
-
1. **Use appropriate TTL**
|
|
343
|
-
```typescript
|
|
344
|
-
// User data yang jarang berubah: TTL panjang
|
|
345
|
-
await cache.set('user:123', user, { ttl: 3600_000 }); // 1 jam
|
|
346
|
-
|
|
347
|
-
// Real-time data: TTL pendek
|
|
348
|
-
await cache.set('stock:ABC', price, { ttl: 5_000 }); // 5 detik
|
|
349
|
-
```
|
|
350
|
-
|
|
351
|
-
2. **Use tags untuk group-related data**
|
|
352
|
-
```typescript
|
|
353
|
-
await cache.set('order:1', order, { tags: ['orders', 'user:123'] });
|
|
354
|
-
await cache.set('order:2', order, { tags: ['orders', 'user:123'] });
|
|
355
|
-
|
|
356
|
-
// Invalidate semua orders user:123
|
|
357
|
-
await cache.invalidateTags(['user:123']);
|
|
358
|
-
```
|
|
359
|
-
|
|
360
|
-
3. **Use wrap() untuk cache-aside pattern**
|
|
361
|
-
```typescript
|
|
362
|
-
const value = await cache.wrap(key, resolver);
|
|
363
|
-
```
|
|
364
|
-
|
|
365
|
-
4. **Use memoize() untuk function results**
|
|
366
|
-
```typescript
|
|
367
|
-
const memoized = cache.memoize(asyncFunction);
|
|
368
|
-
```
|
|
369
|
-
|
|
370
|
-
5. **Invalidate cache after mutations**
|
|
371
|
-
```typescript
|
|
372
|
-
app.put('/users/:id', async (ctx) => {
|
|
373
|
-
await updateUser(ctx.params.id, ctx.body);
|
|
374
|
-
await cache.delete(`user:${ctx.params.id}`);
|
|
375
|
-
return { success: true };
|
|
376
|
-
});
|
|
377
|
-
```
|
|
378
|
-
|
|
379
|
-
### ❌ Don'ts
|
|
380
|
-
|
|
381
|
-
1. **Jangan cache sensitive data tanpa enkripsi**
|
|
382
|
-
```typescript
|
|
383
|
-
// ❌ JANGAN
|
|
384
|
-
await cache.set('password:123', plainPassword);
|
|
385
|
-
|
|
386
|
-
// ✅ LAKUKAN
|
|
387
|
-
await cache.set('password_hash:123', hashedPassword);
|
|
388
|
-
```
|
|
389
|
-
|
|
390
|
-
2. **Jangan cache data yang mutable tanpa copy**
|
|
391
|
-
```typescript
|
|
392
|
-
// ❌ Risiko: object shared reference
|
|
393
|
-
const obj = { count: 0 };
|
|
394
|
-
await cache.set('data', obj);
|
|
395
|
-
obj.count = 1; // modifies cache!
|
|
396
|
-
|
|
397
|
-
// ✅ LAKUKAN: deep copy
|
|
398
|
-
await cache.set('data', JSON.parse(JSON.stringify(obj)));
|
|
399
|
-
```
|
|
400
|
-
|
|
401
|
-
3. **Jangan lupa invalidate setelah update**
|
|
402
|
-
```typescript
|
|
403
|
-
// ❌ JANGAN - user masih melihat old data
|
|
404
|
-
await updateUserInDB(id, data);
|
|
405
|
-
|
|
406
|
-
// ✅ LAKUKAN
|
|
407
|
-
await updateUserInDB(id, data);
|
|
408
|
-
await cache.delete(`user:${id}`);
|
|
409
|
-
```
|
|
410
|
-
|
|
411
|
-
4. **Jangan set TTL terlalu panjang untuk frequently-changing data**
|
|
412
|
-
```typescript
|
|
413
|
-
// ❌ JANGAN - user count bisa stale
|
|
414
|
-
await cache.set('user_count', count, { ttl: 86400_000 }); // 1 hari
|
|
415
|
-
|
|
416
|
-
// ✅ LAKUKAN
|
|
417
|
-
await cache.set('user_count', count, { ttl: 60_000 }); // 1 menit
|
|
418
|
-
```
|
|
419
|
-
|
|
420
|
-
---
|
|
421
|
-
|
|
422
|
-
## Advanced: Redis Store (Coming Soon)
|
|
423
|
-
|
|
424
|
-
Untuk production dengan persistent cache:
|
|
425
|
-
|
|
426
|
-
```typescript
|
|
427
|
-
import { RedisStore } from 'nexus/cache/redis';
|
|
428
|
-
|
|
429
|
-
const cache = new MultiTierCache([
|
|
430
|
-
// L1: Fast in-memory
|
|
431
|
-
{
|
|
432
|
-
store: new InMemoryCacheStore('l1', 1_000),
|
|
433
|
-
ttl: 30_000
|
|
434
|
-
},
|
|
435
|
-
// L2: Redis (persistent)
|
|
436
|
-
{
|
|
437
|
-
store: new RedisStore('redis://localhost:6379'),
|
|
438
|
-
ttl: 3600_000
|
|
439
|
-
}
|
|
440
|
-
]);
|
|
441
|
-
```
|
|
442
|
-
|
|
443
|
-
---
|
|
444
|
-
|
|
445
|
-
## Testing Cache
|
|
446
|
-
|
|
447
|
-
Lihat `demo.ts` untuk contoh lengkap testing cache dengan pembeda performance.
|
|
448
|
-
|
|
449
|
-
```bash
|
|
450
|
-
# Start server
|
|
451
|
-
npx ts-node demo.ts
|
|
452
|
-
|
|
453
|
-
# Test cache hit vs miss
|
|
454
|
-
curl http://localhost:3000/api/users/1 # DATABASE
|
|
455
|
-
curl http://localhost:3000/api/users/1 # CACHE (instant)
|
|
456
|
-
curl http://localhost:3000/api/users/1/no-cache # DATABASE (always)
|
|
457
|
-
|
|
458
|
-
# Invalidate cache
|
|
459
|
-
curl -X DELETE http://localhost:3000/api/users/1/cache
|
|
460
|
-
curl http://localhost:3000/api/users/1 # DATABASE (again)
|
|
461
|
-
|
|
462
|
-
# Stats
|
|
463
|
-
curl http://localhost:3000/api/cache/stats
|
|
464
|
-
```
|
|
465
|
-
|
|
466
|
-
---
|
|
467
|
-
|
|
468
|
-
## Troubleshooting
|
|
469
|
-
|
|
470
|
-
### Cache tidak bekerja?
|
|
471
|
-
|
|
472
|
-
1. **Check TTL expire**
|
|
473
|
-
```typescript
|
|
474
|
-
// Pastikan TTL cukup panjang
|
|
475
|
-
{ ttl: 300_000 } // 5 menit
|
|
476
|
-
```
|
|
477
|
-
|
|
478
|
-
2. **Check cache key consistency**
|
|
479
|
-
```typescript
|
|
480
|
-
// ❌ JANGAN - key berbeda tiap kali
|
|
481
|
-
cache.wrap(`user:${Math.random()}`, resolver);
|
|
482
|
-
|
|
483
|
-
// ✅ LAKUKAN - key konsisten
|
|
484
|
-
cache.wrap(`user:${userId}`, resolver);
|
|
485
|
-
```
|
|
486
|
-
|
|
487
|
-
3. **Check tags untuk invalidation**
|
|
488
|
-
```typescript
|
|
489
|
-
// Setup dengan tag
|
|
490
|
-
await cache.set(key, value, { tags: ['users'] });
|
|
491
|
-
|
|
492
|
-
// Invalidate dengan tag yang sama
|
|
493
|
-
await cache.invalidateTags(['users']);
|
|
494
|
-
```
|
|
495
|
-
|
|
496
|
-
---
|
|
497
|
-
|
|
498
|
-
## Summary
|
|
499
|
-
|
|
500
|
-
| Fitur | Use Case |
|
|
501
|
-
|-------|----------|
|
|
502
|
-
| `get()` / `set()` | Manual cache management |
|
|
503
|
-
| `wrap()` | Cache-aside pattern otomatis |
|
|
504
|
-
| `memoize()` | Function result caching |
|
|
505
|
-
| `delete()` | Invalidate single key |
|
|
506
|
-
| `deletePattern()` | Invalidate by pattern |
|
|
507
|
-
| `invalidateTags()` | Invalidate group of related data |
|
|
508
|
-
| Multi-tier | L1 (fast) + L2 (large/persistent) |
|
|
509
|
-
|
|
510
|
-
Gunakan cache dengan bijak untuk meningkatkan performa aplikasi hingga 100x! 🚀
|