#NestJS Cache Manager Cant’t Get Keys

15 messages · Page 1 of 1 (latest)

echo briar
#

Greetings everyone! Recently I noticed that my fallback caching to local cache stopped working as intended.

The issue in short is extremely similar to https://github.com/nestjs/nest/issues/11145

If I set my key and instantly retrieve it using get It works, but when I’m trying to retrieve my keys elsewhere (after the fact they have been set) they are retrieved as “undefined”

This works:

  async setLocalCache() {
    try {
      const myObj = {
        myData: data,
        timestamp: Date.now(),
      };
      const stringData = JSON.stringify(myObj);
      this.cacheManager.set('MY_KEY_NAME', stringData, 14410000);
      
      const retrievedData = await this.cacheManager.get('MY_KEY_NAME');
      console.log(JSON.parse(retreivedData))
    } catch (error) {
      this.logger.error(error);
    }
  }

This doesn’t work:


 async setLocalCache() {
    try {
      const myObj = {
        myData: data,
        timestamp: Date.now(),
      };
      const stringData = JSON.stringify(myObj);
      this.cacheManager.set('MY_KEY_NAME', stringData, 14410000);
    } catch (error) {
      this.logger.error(error);
    }
  }

async getLocalCache(keyName: string)  {
    try {
      const localRate = await this.cacheManager.get<string>(keyName);
      return localRate ? JSON.parse(localRate) : null;
    } catch (error) {
      this.logger.error(error);
    }
  }

It fails when I am trying to retrieve values from cache out of the scope of the setting of the value.

First post here, hopefully I put my issue on the paper humanly!

GitHub

Is there an existing issue for this? I have searched the existing issues Current behavior After upgradation @nestjs version 9.2.1, cache manager Get values are coming as undefined. Before upgradati...

obsidian helm
#

Assuming you call your getLocalCache with 'MY_KEY_NAME', that is weird behaviour. Could you please create a minimal reproduction so I can have a look?

echo briar
# obsidian helm Assuming you call your `getLocalCache` with `'MY_KEY_NAME'`, that is weird behav...

Yeah, I’m retrieving the key using the get method and providing 1:1 the name for the key, basically the same key that was used for setting.


import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { Inject, Injectable, Logger } from '@nestjs/common';
import { Cache } from 'cache-manager';

@Injectable()
export class myClass {
  constructor(
    @Inject(CACHE_MANAGER) private cacheManager: Cache,
    private readonly logger = new Logger('(exchangeService)'),
  ) {}
  async setLocalCache(keyName: string, data: any) {
    try {
      const myObj = {
        data,
        timestamp: Date.now(),
      };
      const stringData = JSON.stringify(myObj);
      this.cacheManager.set(keyName, stringData, 14400000);
      console.log(await this.cacheManager.get(keyName));
    } catch (error) {
      this.logger.error(error);
    }
  }

  async getLocalCache(keyName: string) {
    try {
      const localRate = await this.cacheManager.get<string>(keyName);
      console.log(localRate);
      return localRate ? JSON.parse(localRate) : null;
    } catch (error) {
      this.logger.error(error);
    }
  }
}

Hopefully this is what you asked, module injection is needed and the functions should be called in order and the get should fail to retrieve the key.

obsidian helm
#

I've just tried and it's working as expected (the value passed to setLocalCache is properly returned from getLocalCache).
How do you import the cache module?

echo briar
echo briar
#

What confuses me is that I haven’t changed anything, not even dependencies. The only thing that I’ve recently added is a CRON Job that Nest provides that makes a callouts and the sets the response data as localCache Keys in scenario where Redis is not running. The logic for Redis is 1:1 copy to localCache operations and works perfectly.

true zephyr
#

this.cacheManager.set() returns a Promise btw, you should await it

rustic ivyBOT
#

A "floating" Promise is a Promise that is created without any code set up to handle any errors it might throw. Floating Promises can cause several issues, such as improperly sequenced operations and ignored Promise rejections.

In the example below, a Promise is created and executed. However, since there is no await keyword to wait for its resolution, the program continues to run without waiting for the Promise to complete.

async function someAsyncFunction() {
  throw new Error('Whoops! 😥');
}

try {
  someAsyncFunction(); // no await
} catch (e) {
  // It won't catch the error
}

// Uncaught (in promise) Error: Whoops! 😥
// at someAsyncFunction (<anonymous>:2:9)
// at <anonymous>:6:3

The Promise returned by someAsyncFunction() starts executing, but the code execution continues immediately without waiting for the Promise to resolve.
As a result, any error or thrown exception inside someAsyncFunction() will not be caught by the try/catch block because the Promise is not being awaited. This can lead to unexpected behavior or unhandled rejections, as the code does not handle the asynchronous operation correctly.

To ensure that the Promise is awaited and its result is properly handled, you should use the await keyword when invoking an asynchronous function:

try {
  await someAsyncFunction(); // properly awaited
} catch (e) {
  // It will catch the error
  console.log(e.message); // Whoops! 😥
}
echo briar
#

The interesting thing when awaiting the set, the first 50 or so of 169 keys get set as undefined. Probably will have to restructure my code fully to fix this.

#

But that’s not the reason why get retrieves “undefined”, since when not setting with await, they all get set normally, but still get retrieved as undefined when calling in a different scope

obsidian helm
#

Hard to tell what could be wrong. If using just inmemory storage, maybe you have multiple cache manager/service instances floating around.
Check that you don't have it in providers array in some module. You could also tweak your service to use a local array/object for a a moment, to rule out whether it's a service issue or cache manager issue.
I could imagine there could also be an issue if you're using HMR, so it'd be a good idea to check that it behaves the same in production build.

echo briar
#

I’ll look into every possibility, anyways thank you a lot for providing input on my issue.

I’ll write what was the issue when I find it out, right now I’m leaning mostly towards a module initialization issue.

echo briar
#

Managed to solve the issue, and it was something really simple in the end, but no where documented properly.

But in short - the issue was that by default the cache-manager library has amount limit set to 100 keys, so I had to change the CacheModule settings property “max” to fit the amount of keys I’m setting.

And the case where the keys were available within the same scope as the setting of the keys, was because I was logging the key that was just set, before it was pushed out of the memory.

rustic ivyBOT
#

This post has been marked as resolved. :white_check_mark:
Please read through the conversation and resolution if you are having the same issue, and then re-open the post if you are still having trouble, providing as much extra information as possible.