使用node-cache结合Firebase后端时,设置缓存后无法获取数据
Node-Cache 设置成功但获取始终返回 Undefined(Firebase 后端场景)
我正在基于 Firebase 构建自研后端 API,计划用 node-cache 实现缓存功能,但执行缓存设置(返回真值)后,获取缓存时始终返回 undefined。
缓存类代码
import {injectable} from "inversify"; import * as NodeCache from "node-cache"; import {SearchDataFile} from "../../searching/domain/search_domian"; @injectable() class Caching { private myCache:NodeCache; constructor() { this.myCache = new NodeCache({stdTTL: 7000, checkperiod: 120}); } public get(key: string): SearchDataFile | undefined { return this.myCache.get(key); } public checkKeyAvailable(keyValue: string): boolean { return this.myCache.has(keyValue); } public set(key: string, data: SearchDataFile): boolean { return this.myCache.set(key, data, 3600); } public delete(key: string): string[] | undefined { return this.myCache.take(key); } } export default Caching;
缓存使用场景代码
/* eslint-disable max-len */ /* eslint-disable object-curly-spacing */ import {FirebaseUser} from "../../authentication/domain/userEntity"; import {SearchDataFile} from "../domain/search_domian"; import * as admin from "firebase-admin"; import {SearchServicesRepository} from "./crednetials/searchRepository"; import { injectable, inject } from "inversify"; import Caching from "../../core/application/cache"; import * as logger from "firebase-functions/logger"; @injectable() export class SearchServiceImplementation implements SearchServicesRepository { constructor(@inject(Caching) private caching: Caching ) {} async getAlldata(): Promise<SearchDataFile> { const valueCheck = this.caching.get("allData"); logger.debug(`the checking ==== ${valueCheck}`); if (valueCheck != undefined) { logger.debug(`the checking after check ==== ${valueCheck}`); // const cachedDataFromDB:SearchDataFile = this.caching.get("allData") as SearchDataFile; return valueCheck; } const usersData = await admin.firestore().collection("users").get(); const firbaseusers:FirebaseUser[] = usersData.docs.map((users)=> { const userData = users.data() as FirebaseUser; return userData; }); const data:SearchDataFile = { users: firbaseusers, community: [], library: [], news: [], forum: [], }; const value =this.caching.set("allData", data); logger.debug(`getAllData ${value}`); return data; } async search(searchTerm: string): Promise<SearchDataFile> { const valueCheck = this.caching.checkKeyAvailable("allData"); logger.debug(`the checking if data is store in cache ${valueCheck}`); if (valueCheck) { const cachedDataFromDB:SearchDataFile = this.caching.get("allData") as SearchDataFile; logger.debug(`the data is store in cache ${cachedDataFromDB}`); const filteredUsers = cachedDataFromDB.users.filter((user) => user.username.toLowerCase().includes(searchTerm.toLowerCase()) ); return { users: filteredUsers, community: [], library: [], news: [], forum: [], }; } const usersData = await admin.firestore().collection("users").get(); const firbaseusers:FirebaseUser[] = usersData.docs.map((users)=> { const userData = users.data() as FirebaseUser; return userData; }); const filteredUsers = firbaseusers.filter((user) => user.username.toLowerCase().includes(searchTerm.toLowerCase()) ); return { users: filteredUsers, community: [], library: [], news: [], forum: [], }; } }
调用代码
/* eslint-disable max-len */ import {Request, Response} from "express"; import {myContainer} from "../../core/inversify_config"; import {TYPES} from "../../core/types"; import {SearchServicesRepository} from "../infastructure/crednetials/searchRepository"; export async function getAllFromDB(req: Request, res: Response,) { try { const getAllData = myContainer.get<SearchServicesRepository>(TYPES.SearchServicesRepository); const data = await getAllData.getAlldata(); return res.status(200).send({message: "Succesfull", data}); } catch (error) { return res.status(400).send(error); } }
相关日志信息
Google Cloud Console 日志显示:
- 首次调用
getAlldata时,valueCheck为 undefined,随后缓存设置返回true - 后续调用中,
valueCheck仍为 undefined,checkKeyAvailable返回false
问题排查与解决方案
1. 修正 Inversify 实例作用域
Caching 类默认是瞬态实例(每次请求创建新对象),导致缓存无法跨请求共享。需在 Inversify 配置中将其注册为单例:
// 在 inversify_config.ts 中 import Caching from './path/to/Caching'; myContainer.bind<Caching>(Caching).toSelf().inSingletonScope();
2. 验证数据序列化兼容性
node-cache 默认会对数据做 JSON 序列化,若 SearchDataFile 包含不可序列化内容(如函数、循环引用),会导致缓存失效。可临时关闭克隆测试:
constructor() { this.myCache = new NodeCache({ stdTTL: 7000, checkperiod: 120, useClones: false }); }
3. 应对 Firebase Functions 冷启动
云函数空闲时会被销毁,缓存数据随之丢失。高频访问数据建议改用 Firebase Memorystore(Redis),或调整函数最小实例数减少冷启动频率。
4. 添加实例一致性日志
在缓存类中添加实例ID日志,确认是否为同一缓存实例:
constructor() { this.myCache = new NodeCache({stdTTL: 7000, checkperiod: 120}); logger.debug(`Cache instance ID: ${this.myCache.id}`); } public get(key: string): SearchDataFile | undefined { const value = this.myCache.get(key); logger.debug(`Get ${key} from cache ${this.myCache.id}: ${value}`); return value; }
内容的提问来源于stack exchange,提问作者Gbenga B Ayannuga
相关产品推荐
相关产品推荐

