Уведомление о переводе ИИ

Эта документация была автоматически переведена ИИ.

Кэш

Модуль кэширования NocoBase основан на библиотеке node-cache-manager и предоставляет функциональность кэширования для разработки плагинов. Система имеет два встроенных типа кэша:

  • memory - Кэш в оперативной памяти на основе lru-cache, предоставляемый node-cache-manager по умолчанию.
  • redis - Кэш Redis на основе node-cache-manager-redis-yet.

Дополнительные типы кэша можно расширять и регистрировать через API.

Базовое использование

app.cache

app.cache — это экземпляр кэша по умолчанию на уровне приложения, который можно использовать напрямую.

// Установить кэш
await app.cache.set('key', 'value', { ttl: 3600 }); // Единица измерения TTL: секунды

// Получить кэш
const value = await app.cache.get('key');

// Удалить кэш
await this.app.cache.del('key');

ctx.cache

В промежуточном ПО или операциях с ресурсами вы можете получить доступ к кэшу через ctx.cache.

async (ctx, next) => {
  let data = await ctx.cache.get('custom:data');
  if (!data) {
    // Промах кэша, получить из базы данных
    data = await this.getDataFromDatabase();
    // Сохранить в кэше, срок действия 1 час
    await ctx.cache.set('custom:data', data, { ttl: 3600 });
  }
  await next();
}

Создание пользовательского кэша

Если вам нужно создать независимый экземпляр кэша (например, с разными пространствами имен или конфигурациями), вы можете использовать метод app.cacheManager.createCache().

import { Plugin } from '@nocobase/server';

export default class PluginCacheDemo extends Plugin {
  async load() {
    // Создать экземпляр кэша с префиксом
    const myCache = await this.app.cacheManager.createCache({
      name: 'myPlugin',
      prefix: 'plugin:cache:', // Все ключи будут автоматически иметь этот префикс
      store: 'memory', // Использовать кэш в памяти, необязательно, по умолчанию используется defaultStore
      max: 1000, // Максимальное количество элементов кэша
    });

    await myCache.set('user:1', { name: 'John' });
    const user = await myCache.get('user:1');
  }
}

Описание параметров createCache

ПараметрТипОписание
namestringУникальный идентификатор кэша, обязателен
prefixstringНеобязательно, префикс для ключей кэша, используется для предотвращения конфликтов ключей
storestringНеобязательно, идентификатор типа хранилища (например, 'memory', 'redis'), по умолчанию используется defaultStore
[key: string]anyДругие пользовательские параметры конфигурации, связанные с хранилищем

Получение созданного кэша

const myCache = this.app.cacheManager.getCache('myPlugin');

Основные методы кэша

Экземпляры кэша предоставляют обширные методы для работы с кэшем, большинство из которых унаследованы от node-cache-manager.

get / set

// Установить кэш со сроком действия (единица измерения: секунды)
await cache.set('key', 'value', { ttl: 3600 });

// Получить кэш
const value = await cache.get('key');

del / reset

// Удалить отдельный ключ
await cache.del('key');

// Очистить весь кэш
await cache.reset();

wrap

Метод wrap() — это очень полезный инструмент, который сначала пытается получить данные из кэша. Если кэш не содержит данных (промах кэша), он выполняет функцию и сохраняет результат в кэше.

const data = await cache.wrap('user:1', async () => {
  // Эта функция выполняется только при промахе кэша
  return await this.fetchUserFromDatabase(1);
}, { ttl: 3600 });

Массовые операции

// Массовая установка
await cache.mset([
  ['key1', 'value1'],
  ['key2', 'value2'],
  ['key3', 'value3'],
], { ttl: 3600 });

// Массовое получение
const values = await cache.mget(['key1', 'key2', 'key3']);

// Массовое удаление
await cache.mdel(['key1', 'key2', 'key3']);

keys / ttl

// Получить все ключи (примечание: некоторые хранилища могут не поддерживать это)
const allKeys = await cache.keys();

// Получить оставшееся время жизни ключа (единица измерения: секунды)
const remainingTTL = await cache.ttl('key');

Расширенное использование

wrapWithCondition

wrapWithCondition() похож на wrap(), но позволяет решить, использовать ли кэш, на основе условий.

const data = await cache.wrapWithCondition(
  'user:1',
  async () => {
    return await this.fetchUserFromDatabase(1);
  },
  {
    // Внешние параметры контролируют, использовать ли результат из кэша
    useCache: true, // Если установлено в false, функция будет выполнена повторно, даже если кэш существует

    // Решить, кэшировать ли на основе результата данных
    isCacheable: (value) => {
      // Например: кэшировать только успешные результаты
      return value && !value.error;
    },

    ttl: 3600,
  },
);

Операции с кэшем объектов

Когда кэшируемое содержимое является объектом, вы можете использовать следующие методы для непосредственной работы со свойствами объекта, не извлекая весь объект.

// Установить свойство объекта
await cache.setValueInObject('user:1', 'name', 'John');
await cache.setValueInObject('user:1', 'age', 30);

// Получить свойство объекта
const name = await cache.getValueInObject('user:1', 'name');

// Удалить свойство объекта
await cache.delValueInObject('user:1', 'age');

Регистрация пользовательского хранилища

Если вам нужно использовать другие типы кэша (например, Memcached, MongoDB и т. д.), вы можете зарегистрировать их с помощью app.cacheManager.registerStore().

import { Plugin } from '@nocobase/server';
import { redisStore, RedisStore } from 'cache-manager-redis-yet';

export default class PluginCacheDemo extends Plugin {
  async load() {
    // Зарегистрировать хранилище Redis (если оно еще не зарегистрировано в системе)
    this.app.cacheManager.registerStore({
      name: 'redis',
      store: redisStore,
      close: async (redis: RedisStore) => {
        await redis.client.quit();
      },
      // Конфигурация подключения Redis
      url: 'redis://localhost:6379',
    });

    // Создать кэш, используя только что зарегистрированное хранилище
    const redisCache = await this.app.createCache({
      name: 'redisCache',
      store: 'redis',
      prefix: 'app:',
    });
  }
}

Важные замечания

  1. Ограничения кэша в памяти: При использовании хранилища memory убедитесь, что вы установили разумный параметр max, чтобы избежать переполнения памяти.
  2. Стратегия инвалидации кэша: При обновлении данных не забывайте очищать соответствующий кэш, чтобы избежать устаревших данных.
  3. Соглашения об именовании ключей: Рекомендуется использовать осмысленные пространства имен и префиксы, например, module:resource:id.
  4. Настройки TTL: Устанавливайте TTL разумно, исходя из частоты обновления данных, чтобы сбалансировать производительность и согласованность.
  5. Подключение Redis: При использовании Redis убедитесь, что параметры подключения и пароль правильно настроены в производственной среде.