chore(): Caching improvements (#13660)
* chore(): Caching improvements * Create proud-windows-sleep.md * naming * fix tests * address feedback
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/caching": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
chore(): Caching improvements
|
||||||
@@ -48,6 +48,11 @@ jest.spyOn(MedusaModule, "getAllJoinerConfigs").mockReturnValue([
|
|||||||
|
|
||||||
moduleIntegrationTestRunner<ICachingModuleService>({
|
moduleIntegrationTestRunner<ICachingModuleService>({
|
||||||
moduleName: Modules.CACHING,
|
moduleName: Modules.CACHING,
|
||||||
|
moduleOptions: {
|
||||||
|
in_memory: {
|
||||||
|
enable: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
testSuite: ({ service }) => {
|
testSuite: ({ service }) => {
|
||||||
describe("Caching Module Service", () => {
|
describe("Caching Module Service", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
|||||||
@@ -61,6 +61,11 @@ moduleIntegrationTestRunner<ICachingModuleService>({
|
|||||||
injectedDependencies: {
|
injectedDependencies: {
|
||||||
[Modules.EVENT_BUS]: mockEventBus,
|
[Modules.EVENT_BUS]: mockEventBus,
|
||||||
},
|
},
|
||||||
|
moduleOptions: {
|
||||||
|
in_memory: {
|
||||||
|
enable: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
testSuite: ({ service }) => {
|
testSuite: ({ service }) => {
|
||||||
describe("Cache Invalidation with Entity Relationships", () => {
|
describe("Cache Invalidation with Entity Relationships", () => {
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
|
|||||||
@@ -0,0 +1,159 @@
|
|||||||
|
import { Modules } from "@medusajs/framework/utils"
|
||||||
|
import { moduleIntegrationTestRunner } from "@medusajs/test-utils"
|
||||||
|
import { ICachingModuleService } from "@medusajs/framework/types"
|
||||||
|
import { MedusaModule } from "@medusajs/framework/modules-sdk"
|
||||||
|
|
||||||
|
jest.setTimeout(10000)
|
||||||
|
|
||||||
|
jest.spyOn(MedusaModule, "getAllJoinerConfigs").mockReturnValue([
|
||||||
|
{
|
||||||
|
schema: `
|
||||||
|
type Product {
|
||||||
|
id: ID
|
||||||
|
title: String
|
||||||
|
handle: String
|
||||||
|
status: String
|
||||||
|
type_id: String
|
||||||
|
collection_id: String
|
||||||
|
is_giftcard: Boolean
|
||||||
|
external_id: String
|
||||||
|
created_at: DateTime
|
||||||
|
updated_at: DateTime
|
||||||
|
|
||||||
|
variants: [ProductVariant]
|
||||||
|
sales_channels: [SalesChannel]
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProductVariant {
|
||||||
|
id: ID
|
||||||
|
product_id: String
|
||||||
|
sku: String
|
||||||
|
|
||||||
|
prices: [Price]
|
||||||
|
}
|
||||||
|
|
||||||
|
type Price {
|
||||||
|
id: ID
|
||||||
|
amount: Float
|
||||||
|
currency_code: String
|
||||||
|
}
|
||||||
|
|
||||||
|
type SalesChannel {
|
||||||
|
id: ID
|
||||||
|
is_disabled: Boolean
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
moduleIntegrationTestRunner<ICachingModuleService>({
|
||||||
|
moduleName: Modules.CACHING,
|
||||||
|
moduleOptions: {
|
||||||
|
in_memory: {
|
||||||
|
enable: true,
|
||||||
|
maxSize: 1000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
testSuite: ({ service }) => {
|
||||||
|
describe("Memory Cache maxSize Integration", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await service.clear({ tags: ["*"] }).catch(() => {})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should respect maxSize limit and stop caching when exceeded", async () => {
|
||||||
|
// Create test data that will use most of the 1000 byte limit
|
||||||
|
const largeData = {
|
||||||
|
id: "large-test",
|
||||||
|
name: "Large Test Item",
|
||||||
|
description: "A".repeat(400), // 400 characters
|
||||||
|
metadata: { info: "B".repeat(300) }, // Another 300 characters
|
||||||
|
}
|
||||||
|
|
||||||
|
await service.set({
|
||||||
|
key: "first-key",
|
||||||
|
data: largeData,
|
||||||
|
tags: ["large-data"],
|
||||||
|
})
|
||||||
|
|
||||||
|
let result = await service.get({ key: "first-key" })
|
||||||
|
expect(result).toEqual(largeData)
|
||||||
|
|
||||||
|
const anotherLargeData = {
|
||||||
|
id: "another-large",
|
||||||
|
content: "C".repeat(500), // This should push us over the 1000 byte limit but accepted because we are still bellow
|
||||||
|
}
|
||||||
|
|
||||||
|
await service.set({
|
||||||
|
key: "second-key",
|
||||||
|
data: anotherLargeData,
|
||||||
|
tags: ["overflow-data"],
|
||||||
|
})
|
||||||
|
|
||||||
|
result = await service.get({ key: "second-key" })
|
||||||
|
expect(result).toEqual(anotherLargeData)
|
||||||
|
|
||||||
|
const anotherLargeData2 = {
|
||||||
|
id: "another-large-2",
|
||||||
|
content: "D".repeat(500), // This should push us over the 1000 byte limit but rejected because we are over the limit
|
||||||
|
}
|
||||||
|
|
||||||
|
await service.set({
|
||||||
|
key: "third-key",
|
||||||
|
data: anotherLargeData2,
|
||||||
|
tags: ["overflow-data-2"],
|
||||||
|
})
|
||||||
|
|
||||||
|
result = await service.get({ key: "third-key" })
|
||||||
|
expect(result).toBeNull()
|
||||||
|
|
||||||
|
const firstResult = await service.get({ key: "first-key" })
|
||||||
|
expect(firstResult).toEqual(largeData)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should allow small entries after reaching the limit", async () => {
|
||||||
|
const largeData = {
|
||||||
|
id: "large-test",
|
||||||
|
description: "A".repeat(800), // Use most of the 1000 byte limit
|
||||||
|
}
|
||||||
|
|
||||||
|
await service.set({
|
||||||
|
key: "large-key",
|
||||||
|
data: largeData,
|
||||||
|
tags: ["large"],
|
||||||
|
})
|
||||||
|
|
||||||
|
let result = await service.get({ key: "large-key" })
|
||||||
|
expect(result).toEqual(largeData)
|
||||||
|
|
||||||
|
await service.set({
|
||||||
|
key: "overflow-key",
|
||||||
|
data: { content: "B".repeat(500) },
|
||||||
|
})
|
||||||
|
|
||||||
|
result = await service.get({ key: "overflow-key" })
|
||||||
|
expect(result).toEqual({ content: "B".repeat(500) })
|
||||||
|
|
||||||
|
await service.set({
|
||||||
|
key: "overflow-key-2",
|
||||||
|
data: { content: "C".repeat(500) },
|
||||||
|
})
|
||||||
|
|
||||||
|
result = await service.get({ key: "overflow-key-2" })
|
||||||
|
expect(result).toBeNull()
|
||||||
|
|
||||||
|
// Remove the large entry to free up space
|
||||||
|
await service.clear({ key: "large-key" })
|
||||||
|
|
||||||
|
// Now small entries should work again
|
||||||
|
const smallData = { id: "small", name: "Small Item" }
|
||||||
|
await service.set({
|
||||||
|
key: "small-key",
|
||||||
|
data: smallData,
|
||||||
|
})
|
||||||
|
|
||||||
|
result = await service.get({ key: "small-key" })
|
||||||
|
expect(result).toEqual(smallData)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -49,21 +49,29 @@ export default async ({
|
|||||||
const strategy = DefaultCacheStrategy // Re enable custom strategy another time
|
const strategy = DefaultCacheStrategy // Re enable custom strategy another time
|
||||||
container.register("strategy", asValue(strategy))
|
container.register("strategy", asValue(strategy))
|
||||||
|
|
||||||
// MemoryCachingProvider - default provider
|
const inMemoryOptions = options?.in_memory ?? {}
|
||||||
container.register({
|
const { enable: isInMemoryEnabled, ...restInmemoryOptions } = inMemoryOptions
|
||||||
[CachingProviderRegistrationPrefix + MemoryCachingProvider.identifier]:
|
|
||||||
asFunction(() => new MemoryCachingProvider(), {
|
if (isInMemoryEnabled) {
|
||||||
lifetime: Lifetime.SINGLETON,
|
// MemoryCachingProvider - default provider
|
||||||
}),
|
container.register({
|
||||||
})
|
[CachingProviderRegistrationPrefix + MemoryCachingProvider.identifier]:
|
||||||
container.registerAdd(
|
asFunction(
|
||||||
CachingIdentifiersRegistrationName,
|
(cradle) => new MemoryCachingProvider(cradle, restInmemoryOptions),
|
||||||
asValue(MemoryCachingProvider.identifier)
|
{
|
||||||
)
|
lifetime: Lifetime.SINGLETON,
|
||||||
container.register(
|
}
|
||||||
CachingDefaultProvider,
|
),
|
||||||
asValue(MemoryCachingProvider.identifier)
|
})
|
||||||
)
|
container.registerAdd(
|
||||||
|
CachingIdentifiersRegistrationName,
|
||||||
|
asValue(MemoryCachingProvider.identifier)
|
||||||
|
)
|
||||||
|
container.register(
|
||||||
|
CachingDefaultProvider,
|
||||||
|
asValue(MemoryCachingProvider.identifier)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Load other providers
|
// Load other providers
|
||||||
await moduleProviderLoader({
|
await moduleProviderLoader({
|
||||||
@@ -85,10 +93,16 @@ export default async ({
|
|||||||
|
|
||||||
const logger = container.resolve(ContainerRegistrationKeys.LOGGER)
|
const logger = container.resolve(ContainerRegistrationKeys.LOGGER)
|
||||||
if (!hasDefaultProvider) {
|
if (!hasDefaultProvider) {
|
||||||
logger.warn(
|
if (isInMemoryEnabled) {
|
||||||
`[caching-module]: No default caching provider defined. Using "${container.resolve(
|
logger.warn(
|
||||||
CachingDefaultProvider
|
`[caching-module]: No default caching provider defined. Using "${container.resolve(
|
||||||
)}" as default.`
|
CachingDefaultProvider
|
||||||
)
|
)}" as default.`
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
throw new Error(
|
||||||
|
"[caching-module]: No providers have been configured and the built in memory cache has not been enabled."
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,40 +1,45 @@
|
|||||||
import NodeCache from "node-cache"
|
import NodeCache from "node-cache"
|
||||||
import type { ICachingProviderService } from "@medusajs/framework/types"
|
import type { ICachingProviderService, Logger } from "@medusajs/framework/types"
|
||||||
|
import { MemoryCacheModuleOptions } from "@types"
|
||||||
|
|
||||||
export interface MemoryCacheModuleOptions {
|
const THREE_HUNDRED_MB = 300 * 1024 * 1024
|
||||||
/**
|
|
||||||
* TTL in seconds
|
const formatBytes = (bytes: number): string => {
|
||||||
*/
|
if (bytes < 1024) return `${bytes} B`
|
||||||
ttl?: number
|
if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`
|
||||||
/**
|
return `${Math.round(bytes / 1024 / 1024)} MB`
|
||||||
* Maximum number of keys to store (see node-cache documentation)
|
|
||||||
*/
|
|
||||||
maxKeys?: number
|
|
||||||
/**
|
|
||||||
* Check period for expired keys in seconds (see node-cache documentation)
|
|
||||||
*/
|
|
||||||
checkPeriod?: number
|
|
||||||
/**
|
|
||||||
* Use clones for cached data (see node-cache documentation)
|
|
||||||
*/
|
|
||||||
useClones?: boolean
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MemoryCachingProvider implements ICachingProviderService {
|
export class MemoryCachingProvider implements ICachingProviderService {
|
||||||
static identifier = "cache-memory"
|
static identifier = "cache-memory"
|
||||||
|
|
||||||
|
protected logger: Logger
|
||||||
protected cacheClient: NodeCache
|
protected cacheClient: NodeCache
|
||||||
protected tagIndex: Map<string, Set<string>> = new Map() // tag -> keys
|
protected tagIndex: Map<string, Set<string>> = new Map() // tag -> keys
|
||||||
protected keyTags: Map<string, Set<string>> = new Map() // key -> tags
|
protected keyTags: Map<string, Set<string>> = new Map() // key -> tags
|
||||||
protected entryOptions: Map<string, { autoInvalidate?: boolean }> = new Map() // key -> options
|
protected entryOptions: Map<string, { autoInvalidate?: boolean }> = new Map() // key -> options
|
||||||
|
protected keySizes: Map<string, number> = new Map() // key -> approximate size in bytes
|
||||||
|
protected approximateMemoryUsage: number = 0
|
||||||
protected options: MemoryCacheModuleOptions
|
protected options: MemoryCacheModuleOptions
|
||||||
|
protected maxSize: number
|
||||||
|
protected hasher: (key: string) => string
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
{ logger, hasher }: { logger?: Logger; hasher: (key: string) => string },
|
||||||
|
options: MemoryCacheModuleOptions = {}
|
||||||
|
) {
|
||||||
|
this.logger = logger ?? (console as unknown as Logger)
|
||||||
|
const { maxSize, ...rest } = options
|
||||||
|
this.maxSize = maxSize ?? THREE_HUNDRED_MB
|
||||||
|
|
||||||
|
this.hasher = hasher
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.options = {
|
this.options = {
|
||||||
ttl: 3600,
|
ttl: 3600,
|
||||||
maxKeys: 25000,
|
maxKeys: 25000,
|
||||||
checkPeriod: 60, // 10 minutes
|
checkPeriod: 60, // 10 minutes
|
||||||
useClones: false, // Default to false for speed, true would be slower but safer. we can discuss
|
useClones: false, // Default to false for speed, true would be slower but safer. we can ...discuss
|
||||||
|
...rest,
|
||||||
}
|
}
|
||||||
|
|
||||||
const cacheClient = new NodeCache({
|
const cacheClient = new NodeCache({
|
||||||
@@ -47,15 +52,31 @@ export class MemoryCachingProvider implements ICachingProviderService {
|
|||||||
this.cacheClient = cacheClient
|
this.cacheClient = cacheClient
|
||||||
|
|
||||||
// Clean up tag indices when keys expire
|
// Clean up tag indices when keys expire
|
||||||
this.cacheClient.on("expired", (key: string, value: any) => {
|
this.cacheClient.on("expired", (key: string) => {
|
||||||
this.cleanupTagReferences(key)
|
this.cleanupTagReferences(key)
|
||||||
})
|
})
|
||||||
|
|
||||||
this.cacheClient.on("del", (key: string, value: any) => {
|
this.cacheClient.on("del", (key: string) => {
|
||||||
this.cleanupTagReferences(key)
|
this.cleanupTagReferences(key)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private calculateEntrySize(
|
||||||
|
key: string,
|
||||||
|
data: object,
|
||||||
|
tags?: string[]
|
||||||
|
): number {
|
||||||
|
const dataSize = Buffer.byteLength(JSON.stringify(data), "utf8")
|
||||||
|
const keySize = Buffer.byteLength(key, "utf8")
|
||||||
|
|
||||||
|
let tagsSize = 0
|
||||||
|
if (tags?.length) {
|
||||||
|
tagsSize = Buffer.byteLength(JSON.stringify(tags), "utf8")
|
||||||
|
}
|
||||||
|
|
||||||
|
return dataSize + keySize + tagsSize
|
||||||
|
}
|
||||||
|
|
||||||
private cleanupTagReferences(key: string): void {
|
private cleanupTagReferences(key: string): void {
|
||||||
const tags = this.keyTags.get(key)
|
const tags = this.keyTags.get(key)
|
||||||
if (tags) {
|
if (tags) {
|
||||||
@@ -70,20 +91,30 @@ export class MemoryCachingProvider implements ICachingProviderService {
|
|||||||
})
|
})
|
||||||
this.keyTags.delete(key)
|
this.keyTags.delete(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clean up memory tracking
|
||||||
|
const keySize = this.keySizes.get(key)
|
||||||
|
if (keySize) {
|
||||||
|
this.approximateMemoryUsage -= keySize
|
||||||
|
this.keySizes.delete(key)
|
||||||
|
}
|
||||||
|
|
||||||
// Also clean up entry options
|
// Also clean up entry options
|
||||||
this.entryOptions.delete(key)
|
this.entryOptions.delete(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
async get({ key, tags }: { key?: string; tags?: string[] }): Promise<any> {
|
async get({ key, tags }: { key?: string; tags?: string[] }): Promise<any> {
|
||||||
if (key) {
|
if (key) {
|
||||||
return this.cacheClient.get(key) ?? null
|
const hashedKey = this.hasher(key)
|
||||||
|
return this.cacheClient.get(hashedKey) ?? null
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tags && tags.length) {
|
if (tags?.length) {
|
||||||
const allKeys = new Set<string>()
|
const allKeys = new Set<string>()
|
||||||
|
|
||||||
tags.forEach((tag) => {
|
tags.forEach((tag) => {
|
||||||
const keysForTag = this.tagIndex.get(tag)
|
const hashedTag = this.hasher(tag)
|
||||||
|
const keysForTag = this.tagIndex.get(hashedTag)
|
||||||
if (keysForTag) {
|
if (keysForTag) {
|
||||||
keysForTag.forEach((key) => allKeys.add(key))
|
keysForTag.forEach((key) => allKeys.add(key))
|
||||||
}
|
}
|
||||||
@@ -122,24 +153,39 @@ export class MemoryCachingProvider implements ICachingProviderService {
|
|||||||
autoInvalidate?: boolean
|
autoInvalidate?: boolean
|
||||||
}
|
}
|
||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
|
// Only reject if we're already over the limit
|
||||||
|
if (this.approximateMemoryUsage > this.maxSize) {
|
||||||
|
this.logger.warn(
|
||||||
|
`Cache is full. Current usage: ${formatBytes(
|
||||||
|
this.approximateMemoryUsage
|
||||||
|
)}, Max: ${formatBytes(this.maxSize)}. Skipping cache entry.`
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const hashedKey = this.hasher(key)
|
||||||
|
const hashedTags = tags?.map((tag) => this.hasher(tag))
|
||||||
|
|
||||||
|
const totalSize = this.calculateEntrySize(hashedKey, data, hashedTags)
|
||||||
|
|
||||||
// Set the cache entry
|
// Set the cache entry
|
||||||
const effectiveTTL = ttl ?? this.options.ttl ?? 3600
|
const effectiveTTL = ttl ?? this.options.ttl ?? 3600
|
||||||
this.cacheClient.set(key, data, effectiveTTL)
|
this.cacheClient.set(hashedKey, data, effectiveTTL)
|
||||||
|
|
||||||
// Handle tags if provided
|
// Handle tags if provided
|
||||||
if (tags && tags.length) {
|
if (hashedTags?.length) {
|
||||||
// Clean up any existing tag references for this key
|
// Clean up any existing tag references for this key
|
||||||
this.cleanupTagReferences(key)
|
this.cleanupTagReferences(hashedKey)
|
||||||
|
|
||||||
const tagSet = new Set(tags)
|
const tagSet = new Set(hashedTags)
|
||||||
this.keyTags.set(key, tagSet)
|
this.keyTags.set(hashedKey, tagSet)
|
||||||
|
|
||||||
// Add this key to each tag's index
|
// Add this key to each tag's index
|
||||||
tags.forEach((tag) => {
|
hashedTags.forEach((tag) => {
|
||||||
if (!this.tagIndex.has(tag)) {
|
if (!this.tagIndex.has(tag)) {
|
||||||
this.tagIndex.set(tag, new Set())
|
this.tagIndex.set(tag, new Set())
|
||||||
}
|
}
|
||||||
this.tagIndex.get(tag)!.add(key)
|
this.tagIndex.get(tag)!.add(hashedKey)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,8 +194,14 @@ export class MemoryCachingProvider implements ICachingProviderService {
|
|||||||
Object.keys(options ?? {}).length &&
|
Object.keys(options ?? {}).length &&
|
||||||
!Object.values(options ?? {}).every((value) => value === undefined)
|
!Object.values(options ?? {}).every((value) => value === undefined)
|
||||||
) {
|
) {
|
||||||
this.entryOptions.set(key, options!)
|
this.entryOptions.set(hashedKey, options!)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Track memory usage
|
||||||
|
const existingSize = this.keySizes.get(hashedKey) || 0
|
||||||
|
this.approximateMemoryUsage =
|
||||||
|
this.approximateMemoryUsage - existingSize + totalSize
|
||||||
|
this.keySizes.set(hashedKey, totalSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
async clear({
|
async clear({
|
||||||
@@ -164,13 +216,14 @@ export class MemoryCachingProvider implements ICachingProviderService {
|
|||||||
}
|
}
|
||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
if (key) {
|
if (key) {
|
||||||
this.cacheClient.del(key)
|
const hashedKey = this.hasher(key)
|
||||||
|
this.cacheClient.del(hashedKey)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tags && tags.length) {
|
if (tags?.length) {
|
||||||
// Handle wildcard tag to clear all cache data
|
// Handle wildcard tag to clear all cache data
|
||||||
if (tags.includes("*")) {
|
if (tags?.includes("*")) {
|
||||||
this.cacheClient.flushAll()
|
this.cacheClient.flushAll()
|
||||||
this.tagIndex.clear()
|
this.tagIndex.clear()
|
||||||
this.keyTags.clear()
|
this.keyTags.clear()
|
||||||
@@ -178,9 +231,10 @@ export class MemoryCachingProvider implements ICachingProviderService {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hashedTags = tags.map((tag) => this.hasher(tag))
|
||||||
const allKeys = new Set<string>()
|
const allKeys = new Set<string>()
|
||||||
|
|
||||||
tags.forEach((tag) => {
|
hashedTags.forEach((tag) => {
|
||||||
const keysForTag = this.tagIndex.get(tag)
|
const keysForTag = this.tagIndex.get(tag)
|
||||||
if (keysForTag) {
|
if (keysForTag) {
|
||||||
keysForTag.forEach((key) => allKeys.add(key))
|
keysForTag.forEach((key) => allKeys.add(key))
|
||||||
|
|||||||
@@ -23,6 +23,31 @@ export type InjectedDependencies = {
|
|||||||
[Modules.EVENT_BUS]: IEventBusModuleService
|
[Modules.EVENT_BUS]: IEventBusModuleService
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface MemoryCacheModuleOptions {
|
||||||
|
/**
|
||||||
|
* TTL in seconds
|
||||||
|
*/
|
||||||
|
ttl?: number
|
||||||
|
/**
|
||||||
|
* Maximum number of keys to store (see node-cache documentation)
|
||||||
|
*/
|
||||||
|
maxKeys?: number
|
||||||
|
/**
|
||||||
|
* Check period for expired keys in seconds (see node-cache documentation)
|
||||||
|
*/
|
||||||
|
checkPeriod?: number
|
||||||
|
/**
|
||||||
|
* Use clones for cached data (see node-cache documentation)
|
||||||
|
*/
|
||||||
|
useClones?: boolean
|
||||||
|
/**
|
||||||
|
* Maximum size of the cache in bytes (default 300MB).
|
||||||
|
* It is an approximation, if a new entry will make the limit exceeded, the entry will be cached
|
||||||
|
* but not the following ones
|
||||||
|
*/
|
||||||
|
maxSize?: number
|
||||||
|
}
|
||||||
|
|
||||||
export type CachingModuleOptions = Partial<ModuleServiceInitializeOptions> & {
|
export type CachingModuleOptions = Partial<ModuleServiceInitializeOptions> & {
|
||||||
/**
|
/**
|
||||||
* The strategy to be used. Default to the inbuilt default strategy.
|
* The strategy to be used. Default to the inbuilt default strategy.
|
||||||
@@ -32,6 +57,15 @@ export type CachingModuleOptions = Partial<ModuleServiceInitializeOptions> & {
|
|||||||
* Time to keep data in cache (in seconds)
|
* Time to keep data in cache (in seconds)
|
||||||
*/
|
*/
|
||||||
ttl?: number
|
ttl?: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable and configure the built in memory cache
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
in_memory?: MemoryCacheModuleOptions & {
|
||||||
|
enable?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Providers to be registered
|
* Providers to be registered
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user