Procházet zdrojové kódy

docs(core): Document the SelfRefreshingCache (#3666)

Drayke před 6 měsíci
rodič
revize
03eb7fb2c9

+ 67 - 0
docs/docs/guides/developer-guide/cache/index.mdx

@@ -258,3 +258,70 @@ which internally just uses whatever the current `CacheStrategy` is to store the
 This means that in most cases you don't need to worry about the session cache, but if you have specific
 requirements, you can create a custom session cache strategy and set it via the `authOptions.sessionCacheStrategy`
 config property.
+
+## SelfRefreshingCache
+The [SelfRefreshingCache](/reference/typescript-api/cache/self-refreshing-cache) is a specialized in-memory cache which automatically
+refreshes itself if the value is found to be stale. This is useful to cache a single frequently-accessed value, that don't change often.
+
+It is created using the [createSelfRefreshingCache](/reference/typescript-api/cache/self-refreshing-cache#createselfrefreshingcache) function, which takes a configuration object that specifies the
+name of the cache, the time-to-live (TTL) for the cache entries, and a refresh function that will be called to update the value when it is stale.
+
+```ts title="SelfRefreshingCache Example"
+import {
+  Channel,
+  createSelfRefreshingCache,
+  EventBus,
+  InitializerEvent,
+  InternalServerError,
+  Logger,
+  RequestContext
+  SelfRefreshingCache,
+  TransactionalConnection,
+} from '@vendure/core';
+
+@Injectable()
+export class PublicChannelService {
+// highlight-start
+  private publicChannel: SelfRefreshingCache<Channel, [RequestContext]>;
+// highlight-end
+  private readonly logCtx = 'PublicChannelService';
+
+  constructor(
+    private connection: TransactionalConnection,
+    private eventBus: EventBus,
+  ) {
+    this.eventBus.ofType(InitializerEvent).subscribe(async () => {
+      // highlight-start
+      this.publicChannel = await createSelfRefreshingCache({
+        name: 'PublicChannelService.publicChannel',
+        ttl: 1000 * 60 * 5, // 5min
+        refresh: { fn: ctx => this.findPublicChannel(ctx), defaultArgs: [RequestContext.empty()] },
+      });
+      // highlight-end
+    });
+  }
+
+  async getPublicChannel(): Promise<Channel> {
+    // highlight-start
+    const publicChannel = await this.publicChannel.value();
+    // highlight-end
+    if (!publicChannel) {
+      throw new InternalServerError(`error.public-channel-not-found`);
+    }
+    return publicChannel;
+  }
+
+  private async findPublicChannel(ctx: RequestContext): Promise<Channel> {
+    const publicChannel = await this.connection.getRepository(ctx, Channel).findOne({
+      where: { code: DEFAULT_PUBLIC_CHANNEL_CODE },
+      relations: ['defaultShippingZone', 'defaultTaxZone'],
+    });
+
+    if (!publicChannel) {
+      Logger.error('Could not find public channel!', this.logCtx);
+      throw new InternalServerError(`error.public-channel-not-found`);
+    }
+    return publicChannel;
+  }
+}
+```

+ 51 - 2
packages/core/src/common/self-refreshing-cache.ts

@@ -1,10 +1,11 @@
-import { Json } from '@vendure/common/lib/shared-types';
-
 import { Logger } from '../config/logger/vendure-logger';
 
 /**
  * @description
  * A cache which automatically refreshes itself if the value is found to be stale.
+ *
+ * @docsCategory cache
+ * @docsPage SelfRefreshingCache
  */
 export interface SelfRefreshingCache<V, RefreshArgs extends any[] = []> {
     /**
@@ -35,9 +36,31 @@ export interface SelfRefreshingCache<V, RefreshArgs extends any[] = []> {
     refresh(...args: RefreshArgs): Promise<V>;
 }
 
+/**
+ * @description
+ * Configuration options for creating a {@link SelfRefreshingCache}.
+ *
+ * @docsCategory cache
+ * @docsPage SelfRefreshingCache
+ */
 export interface SelfRefreshingCacheConfig<V, RefreshArgs extends any[]> {
+    /**
+     * @description
+     * The name of the cache, used for logging purposes.
+     * e.g. `'MyService.cachedValue'`.
+     */
     name: string;
+    /**
+     * @description
+     * The time-to-live (ttl) in milliseconds for the cache. After this time, the value will be considered stale
+     * and will be refreshed the next time it is accessed.
+     */
     ttl: number;
+    /**
+     * @description
+     * The function which is used to refresh the value of the cache.
+     * This function should return a Promise which resolves to the new value.
+     */
     refresh: {
         fn: (...args: RefreshArgs) => Promise<V>;
         /**
@@ -46,6 +69,7 @@ export interface SelfRefreshingCacheConfig<V, RefreshArgs extends any[]> {
         defaultArgs: RefreshArgs;
     };
     /**
+     * @description
      * Intended for unit testing the SelfRefreshingCache only.
      * By default uses `() => new Date().getTime()`
      */
@@ -61,6 +85,31 @@ export interface SelfRefreshingCacheConfig<V, RefreshArgs extends any[]> {
  * From there, when the `.value` property is accessed, it will return a value from the cache, and if the
  * value has expired, it will automatically run the `refreshFn` to update the value and then return the
  * fresh value.
+ *
+ * @example
+ * ```ts title="Example of creating a SelfRefreshingCache"
+ * import { createSelfRefreshingCache } from '@vendure/core';
+ *
+ * \@Injectable()
+ * export class PublicChannelService {
+ *   private publicChannel: SelfRefreshingCache<Channel, [RequestContext]>;
+ *
+ *   async init() {
+ *     this.publicChannel = await createSelfRefreshingCache<Channel, [RequestContext]>({
+ *      name: 'PublicChannelService.publicChannel',
+ *      ttl: 1000 * 60 * 60, // 1 hour
+ *      refresh: {
+ *        fn: async (ctx: RequestContext) => {
+ *         return this.channelService.getPublicChannel(ctx);
+ *       },
+ *      defaultArgs: [RequestContext.empty()],
+ *     },
+ *   });
+ * }
+ * ```
+ *
+ * @docsCategory cache
+ * @docsPage SelfRefreshingCache
  */
 export async function createSelfRefreshingCache<V, RefreshArgs extends any[]>(
     config: SelfRefreshingCacheConfig<V, RefreshArgs>,