Redis не будет извлекать данные из кеша - PullRequest
7 голосов
/ 24 февраля 2020

Я следую учебному пособию и создал кеш. js файл, который принимает запрос mon goose и JSON .stringizes его в ключ для значений, возвращаемых этим запросом. Цель состоит в том, чтобы кэшировать это и затем добавить .cache() в приложение. js, где mongoose.find() равно

В настоящее время, если кэш пустой, я получаю GET из БД и затем сохраняю его в кеше. У меня есть

console.log("CACHE VALUE #2");
console.log(cacheValue1);

, который обеспечивает сохранение данных и их успешный вывод. Эта линия работает. Но с этой строкой

console.log("CACHE VALUE #1");
console.log(cacheValue);

cacheValue равно нулю.

Почему это так?

В нижней части хранится значение, а ключ никогда не меняется, поэтому Я не понимаю, почему он не возвращает данные вместо нуля.

Так что Cache Value #1 всегда равен нулю, а Cache Value #2 содержит правильные данные.

ВЫХОД КОНСОЛИ:

GRABBING FROM DB
CLIENT CONNECTION STATUS: true
Setting CACHE to True
ABOUT TO RUN A QUERY
{"$and":[{"auctionType":{"$eq":"publicAuction"}},{"auctionEndDateTime":{"$gte":1582903244869}},{"blacklistGroup":{"$ne":"5e52cca7180a7605ac94648f"}},{"startTime":{"$lte":1582903244869}}],"collection":"listings"}
CACHE VALUE #1
null
CACHE VALUE #2
(THIS IS WHERE ALL MY DATA SHOWS UP)
const mongoose = require('mongoose');
const redis = require('redis');
const util = require('util');
var env = require("dotenv").config({ path: './.env' });

const client = redis.createClient(6380, process.env.REDISCACHEHOSTNAME + '.redis.cache.windows.net', {
  auth_pass: process.env.REDISCACHEKEY,
  tls: { servername: process.env.REDISCACHEHOSTNAME + '.redis.cache.windows.net' }
});


client.get = util.promisify(client.get);


const exec = mongoose.Query.prototype.exec;

mongoose.Query.prototype.cache = function () {
  this.useCache = true;
  console.log("Setting CACHE to True")
  return this;
}

mongoose.Query
  .prototype.exec = async function () {
    if (!this.useCache) {
      console.log("GRABBING FROM DB")
      console.log("CLIENT CONNECTION STATUS: " + client.connected);

      return exec.apply(this, arguments);
    }

    console.log("ABOUT TO RUN A QUERY")
    const key = JSON.stringify(Object.assign({}, this.getQuery(), {
      collection: this.mongooseCollection.name
    }));


    //See if we have a value for 'key' in redis
    console.log(key);
    const cacheValue = await client.get(key);
    console.log("CACHE VALUE #1");
    console.log(cacheValue);
    //If we do, return that
    if (cacheValue) {
      console.log("cacheValue IS TRUE");
      const doc = JSON.parse(cacheValue);
      return Array.isArray(doc)
        ? doc.map(d => new this.model(d))
        : new this.model(doc);
    }

    //Otherwise, issue the query and store the result in redis
    const result = await exec.apply(this, arguments);

    let redisData = JSON.stringify(result);
    //stores the mongoose query result in redis



    await client.set(key, JSON.stringify(redisData)), function (err) {
      console.error(err);

    }
    const cacheValue1 = await client.get(key);
    console.log("CACHE VALUE #2");
    console.log(cacheValue1);




    return result;
  }


Ответы [ 2 ]

1 голос
/ 29 февраля 2020

На основании ссылки pastebin , которую вы связали, ваши запросы используют Date.now() для своих значений. Это означает, что каждый раз, когда выполняется запрос, у вас есть разные значения для метки времени.

Поскольку ваши ключи являются фактическим запросом, а запрос имеет значения c в динамическом формате, основанные на Date.now(), ваши ключи никогда не будут прежними, поэтому вы не сможете найти их в кеше позже каждый запрос генерирует уникальный ключ из-за динамических c значений Date.now().

0 голосов
/ 01 марта 2020

Я воспроизвел ваш код в минимальном примере, и он работал так, как вы хотели. Он передает ответ из кэша redis после первого запроса. Я только что зарегистрировал значения и обнаружил некоторые небольшие ошибки в вашем коде, вы легко их заметите (вызовом this.model с помощью do c, исправьте набор и удалите последний get для клиента redis). Я не думаю, что это лучший способ кеширования ответов, потому что вы устанавливаете переменную в true в каждом запросе, а также достигаете mon go и mon goose, прежде чем использовать кеш. С промежуточным ПО все это может быть предотвращено, и вы уберете еще несколько мс, но все равно это не самый плохой способ, так что вот мой минимальный рабочий пример.

const http = require('http')
const mongoose = require('mongoose')
const redis = require('redis')
const port = 3000;
const util = require('util');

const client = redis.createClient()
client.get = util.promisify(client.get);
mongoose.connect('mongodb://localhost:27017/testdb', {useNewUrlParser: true});
const exec = mongoose.Query.prototype.exec;
  var Schema = mongoose.Schema;

  var testSchema = new Schema({
    testfield:  String, // String is shorthand for {type: String}
  });


 var Test = mongoose.model('Test', testSchema);

mongoose.Query.prototype.cache = function() {
  this.useCache = true;
  console.log("Setting CACHE to True")
  return this;
}

mongoose.Query
  .prototype.exec = async function () {
    if (!this.useCache) {
      console.log("GRABBING FROM DB")
      console.log("CLIENT CONNECTION STATUS: " + client.connected);

      return exec.apply(this, arguments);
    }

    console.log("ABOUT TO RUN A QUERY")
      console.log("Query ==", this.getQuery())
      console.log("Collection == ", this.mongooseCollection.name);
    const key = JSON.stringify(Object.assign({}, this.getQuery(), {
      collection: this.mongooseCollection.name
    }));


    //See if we have a value for 'key' in redis
    console.log("KEY FROM QUERY AND COLLECTION",key);
    const cacheValue = await client.get(key);
    console.log("CACHE VALUE #1");
    console.log(cacheValue);
    //If we do, return that
    if (cacheValue) {
      console.log("cacheValue IS TRUE");
      const doc = JSON.parse(cacheValue);
        console.log("DOC == ",doc);
      return Array.isArray(doc)
        ? doc.map(d => d)
        : doc
           // return exec( Array.isArray(doc)
       // ? doc.map(d => new this.model(d))
        //: new this.model(doc))
    }

    //Otherwise, issue the query and store the result in redis
    const result = await exec.apply(this, arguments);
   // console.log("EXEC === ", exec);
   // console.log("result from query == ", result);
    let redisData = JSON.stringify(result);
    //stores the mongoose query result in redis

    console.log("REDis data ===", redisData);

    await client.set(key, redisData, function (err) {
      console.error(err);

    })




    return result;
  }

const server = http.createServer(function(req, res) {
    if(req.url === '/'){
        Test.find({}).cache().exec().then(function( docs) {
          console.log("DOCS in response == ", docs);
          res.writeHead(200, { 'Content-Type': 'text/plain' });
          res.end(JSON.stringify(docs))
        })
    }

})


server.listen(port, function() {

    console.log(`Server listening on port ${port}`)
 })
...