@cqrs-ddd/pipeline-cache
Αποθηκεύει συντεθειμένα αποτελέσματα queries σε backends cache-manager και Keyv: μνήμη (in-memory), Redis, Memcache, SQLite, PostgreSQL, ή πολυεπίπεδους (multi-tier) συνδυασμούς.
Ένα cache hit επιστρέφει το αποθηκευμένο αποτέλεσμα άμεσα χωρίς να εκτελέσει τον handler ή τους εσωτερικούς ελέγχους οντοτήτων. Προς αποφυγή διαρροής δεδομένων μεταξύ χρηστών ή επιπέδων δικαιωμάτων, τα cache keys πρέπει να διαχωρίζονται ανά tenant, principal και permission scope.
Εγκατάσταση
Ενότητα με τίτλο «Εγκατάσταση»pnpm add @cqrs-ddd/pipeline-cache @cqrs-ddd/pipeline cache-manager keyvΠροαιρετικοί adapters του Keyv για εξωτερική αποθήκευση:
- Redis:
@keyv/redis - PostgreSQL:
@keyv/postgres - SQLite:
@keyv/sqlite - Memcache:
@keyv/memcache
Δύο επίπεδα Cache στο @cqrs-ddd
Ενότητα με τίτλο «Δύο επίπεδα Cache στο @cqrs-ddd»Το @cqrs-ddd διαχωρίζει το caching σε δύο διακριτά, συμπληρωματικά επίπεδα:
- Pipeline Result Caching (
@cqrs-ddd/pipeline-cache): Στο επίπεδο use case / query handler. Αποθηκεύει συντεθειμένα DTOs και view models. Ελέγχει τα όρια ασφαλείας (tenant, principal, permission scope) και τις πολιτικές ανανέωσης (freshness policies). - Repository Snapshot Caching (
@FromCache,@Cacheστο@cqrs-ddd/core): Στο επίπεδο persistence. Αποθηκεύει σειριοποιημένα entity snapshots με συγκρίσεις εκδόσεων CAS (isCacheNewer) και mutation barriers.
Η ακύρωση (invalidation) μιας οντότητας στο persistence δεν ακυρώνει αυτόματα τα συντεθειμένα query responses. Κάθε επίπεδο διαχειρίζεται τον δικό του κύκλο ζωής.
1. Plain Node.js / Μηχανή Pipeline
Ενότητα με τίτλο «1. Plain Node.js / Μηχανή Pipeline»import { createPipeline } from '@cqrs-ddd/pipeline';import { buildCache, CacheBehavior, cache, createPartitionedCacheKeyFactory,} from '@cqrs-ddd/pipeline-cache';
const cacheStore = buildCache({ store: { type: 'redis', url: process.env.REDIS_URL, namespace: 'query_cache' }, ttl: 60_000,});
const pipeline = createPipeline({ behaviors: [new CacheBehavior(cacheStore)],});
const orderListKey = createPartitionedCacheKeyFactory({ principal: (ctx) => ctx.items.get('userId') as string, scope: (ctx) => ctx.items.get('userRolesHash') as string, includeTenant: true,});
export const getOrders = pipeline.wrap( { name: 'getOrders', kind: 'query' }, cache({ key: orderListKey, ttl: 30_000 }),)(async (filter: OrderFilterDto) => ordersService.listOrders(filter));2. Ενσωμάτωση στο NestJS (@cqrs-ddd/nestjs)
Ενότητα με τίτλο «2. Ενσωμάτωση στο NestJS (@cqrs-ddd/nestjs)»Καταχωρίστε το CacheBehavior ως provider στο infrastructure module σας:
import { Module } from '@nestjs/common';import { buildCache, CacheBehavior } from '@cqrs-ddd/pipeline-cache';
@Module({ providers: [ { provide: CacheBehavior, useFactory: () => { return new CacheBehavior( buildCache({ store: { type: 'redis', url: process.env.REDIS_URL }, ttl: 60_000, }), ); }, }, ], exports: [CacheBehavior],})export class CacheModule {}Διακοσμήστε τον @QueryHandler με το cache():
import { QueryHandler, IQueryHandler } from '@nestjs/cqrs';import { UsePipeline } from '@cqrs-ddd/pipeline';import { cache } from '@cqrs-ddd/pipeline-cache';
@QueryHandler(GetCatalogQuery)@UsePipeline(cache({ key: catalogKeyFactory, ttl: 120_000 }))export class GetCatalogHandler implements IQueryHandler<GetCatalogQuery> { async execute(query: GetCatalogQuery) { return this.catalog.load(query); }}Αποθηκευτικά Backends & Πολυεπίπεδο Caching (Multi-Tier)
Ενότητα με τίτλο «Αποθηκευτικά Backends & Πολυεπίπεδο Caching (Multi-Tier)»Το buildCache(options) διαμορφώνει αποθήκευση μονού ή πολλαπλών επιπέδων:
const multiTierCache = buildCache({ store: [ { type: 'memory', ttl: 10_000 }, { type: 'redis', url: process.env.REDIS_URL, ttl: 300_000 }, ], nonBlocking: true,});| Τύπος Store | Απαιτούμενο πακέτο | Βέλτιστη χρήση |
|---|---|---|
'memory' |
Ενσωματωμένο | L1 in-process caching, testing, dev περιβάλλοντα |
'redis' |
@keyv/redis |
Κατανεμημένο L2 caching, microservices υψηλής απόδοσης |
'postgres' |
@keyv/postgres |
Σχεσιακές βάσεις χωρίς αποκλειστική υποδομή Redis |
'sqlite' |
@keyv/sqlite |
Ενσωματωμένες εφαρμογές CLI/desktop ή edge |
'memcache' |
@keyv/memcache |
Key-value stores υψηλού όγκου |
Διαχωρισμός κλειδιών & Όρια ασφαλείας
Ενότητα με τίτλο «Διαχωρισμός κλειδιών & Όρια ασφαλείας»Τα κλειδιά short-circuit αποτελούν κρίσιμο όριο ασφαλείας. Η επιστροφή αποθηκευμένου αποτελέσματος παρακάμπτει όλους τους εσωτερικούς ελέγχους δικαιωμάτων πεδίων και οντοτήτων.
Διαχωρίζετε πάντοτε τα κλειδιά ανά tenant, principal και scope δικαιωμάτων:
import { createPartitionedCacheKeyFactory } from '@cqrs-ddd/pipeline-cache';import { abilityDigest, getCaslPrincipal } from '@cqrs-ddd/pipeline-casl';
export const userProfileKey = createPartitionedCacheKeyFactory({ principal: (ctx) => getCaslPrincipal(ctx)?.id, scope: abilityDigest, includeTenant: true, requireTenant: true, requirePrincipal: true, requireScope: true,});| Επιλογή Factory | Τύπος | Προεπιλογή | Περιγραφή |
|---|---|---|---|
principal |
(ctx) => string | undefined |
υποχρεωτικό | Ταυτοποιεί τον καλούντα. Ρίχνει MissingCachePartitionError αν απουσιάζει. |
scope |
(ctx) => string | undefined |
undefined |
Αποτύπωμα δικαιωμάτων (ρόλοι ή abilityDigest). |
requirePrincipal |
boolean |
true |
Αν είναι true, ελλείπον principal ρίχνει σφάλμα fail-closed. |
requireScope |
boolean |
true |
Αν είναι true, ελλείπον scope δικαιωμάτων ρίχνει σφάλμα. |
includeTenant |
boolean |
true |
Προσαρτά το ενεργό tenant ID στο κλειδί. |
requireTenant |
boolean |
τιμή του includeTenant |
Επιβάλλει την παρουσία tenant στο context εκτέλεσης. |
Επιλογές παραμετροποίησης
Ενότητα με τίτλο «Επιλογές παραμετροποίησης»| Επιλογή | Τύπος | Προεπιλογή | Περιγραφή |
|---|---|---|---|
key |
CacheKeyFactory |
υποχρεωτικό | Υπολογίζει το cache key από το context του pipeline. |
ttl |
number |
Προεπιλογή cache | Χρόνος ζωής της εγγραφής σε milliseconds. |
kinds |
DeclaredKind[] |
['query'] |
Είδη αιτημάτων στα οποία εφαρμόζεται (συνήθως μόνο queries). |
condition |
(ctx) => boolean | Promise<boolean> |
undefined |
Συνθήκη που καθορίζει αν το συγκεκριμένο αίτημα θα ελέγξει/αποθηκεύσει στην cache. |
failOpen |
boolean |
true |
Όταν είναι true, σφάλματα του υποκείμενου store καταγράφουν προειδοποίηση και η εκτέλεση συνεχίζει χωρίς cache. Όταν είναι false, ρίχνεται σφάλμα. |
Παρατηρησιμότητα (Observability)
Ενότητα με τίτλο «Παρατηρησιμότητα (Observability)»Το CacheBehavior καταγράφει στοιχεία runtime στο context.items:
CACHE_HIT_ITEM_TOKEN: Boolean που δηλώνει αν το αποτέλεσμα προήλθε από την cache.CACHE_KEY_ITEM_TOKEN: String του κλειδιού στο οποίο αναζητήθηκε ή γράφτηκε η εγγραφή.
Μετατρέψτε τα σε tracing attributes με το buildCacheAttributes(context).
Σειρά των behaviors
Ενότητα με τίτλο «Σειρά των behaviors»Τοποθετήστε το CacheBehavior μετά από validation και authorization:
ZodValidationBehavior: Επικυρώνει και κανονικοποιεί τις παραμέτρους.CaslBehavior: Ελέγχει την εξουσιοδότηση τύπου.CacheBehavior: Ελέγχει το cache key με το αυθεντικοποιημένο principal και scope δικαιωμάτων.