Managing amazon translation with redis

272 Views Asked by At

I have to manage a traduction of a json with aws from amazon and saving the cache in redis.

async function translateSomething(trans, p1, sourceLan, targetLan) {
  var paramsName = {
    Text: p1,
    SourceLanguageCode: sourceLan,
    TargetLanguageCode: targetLan,
  };

  let myPromise = () =>
    new Promise((resolve, reject) => {
      trans.translateText(paramsName, function (err, data) {
        if (err) throw err;
        if (data) {
          console.log("translated", data.TranslatedText);
          resolve(data.TranslatedText);
        }
      });
    });

  let res = await myPromise();
  return res;
}
// and this function to check if the value is in the menu or not

function storeOrFound(p1, value, sourceLan, targetLan) {
  return redisClient.get(p1, async (err, result) => {
    if (err) console.log("err", err);
    if (result) {
      console.log("element is already in cache", JSON.parse(result).val);

      let tmp = JSON.parse(result).val;

      return tmp;
    } else {
      var translate = new AWS.Translate({ region: AWS.config.region });

      let val = await translateSomething(
        translate,
        value,
        sourceLan,
        targetLan,
      );

      redisClient.setex(
        p1,
        3600,
        JSON.stringify({ source: "Redis Cache", val }),
      );

      return val;
    }
  });
}
// and after i execute the query of the db i use this function to check if is present or not on the db or not

something().then((doc) => {
  for (let i = 0; i < doc.items.length; i++) {
    const menuRedisKeyName = `name:${doc.items[i].name}21`;
    doc.items[i].name = storeOrFound(
      menuRedisKeyName,
      doc.items[i].name,
      menuLang,
      targetLan,
    );
  }
  console.log("JSON", JSON.stringify(doc));
  res.end(JSON.stringify(doc));
});

The problem is that the method storeOrFound returns true or false (because return redisClient.get return true or false whether the object is present or not . Any ideas for managing this problem? Also on the console i see that the console.log(" element is already in cache"..) is printed at the end. Did i miss something on synchronization?

1

There are 1 best solutions below

1
On BEST ANSWER

You might want something like this.

  • translateSomething and checkCache return promises, so you can use them easily in async/await code.
  • getFromCacheOrTranslate wraps these two in an async function.

There are some future addition TODO comments in the code too.

function translateSomething(translate, text, sourceLan, targetLan) {
  return new Promise((resolve, reject) => {
    translate.translateText(
      {
        Text: text,
        SourceLanguageCode: sourceLan,
        TargetLanguageCode: targetLan,
      },
      function (err, data) {
        if (err && !data) {
          reject(err);
          return;
        }
        console.log("translated", data.TranslatedText);
        resolve(data.TranslatedText);
      },
    );
  });
}

/**
 * Promisified version of `redisClient.get()`.
 */
function checkCache(key) {
  return new Promise((resolve, reject) => {
    redisClient.get(key, (err, result) => {
      if (err) {
        reject(err);
      }
      resolve(result);
    });
  });
}

async function getFromCacheOrTranslate(text, sourceLan, targetLan) {
  const key = `translate:${sourceLan}:${targetLan}:${text}`; // TODO: hash the text here for a shorter cache key
  let result = await checkCache(key);
  if (result) {
    // result was in cache, return it
    return JSON.parse(result);
  }
  // Otherwise save it to the cache and return it
  const translate = new AWS.Translate({ region: AWS.config.region });
  result = await translateSomething(translate, text, sourceLan, targetLan);
  redisClient.setex(key, 3600, JSON.stringify(result)); // Async result ignored here
  return result;
}

something().then(async (doc) => {
  // TODO: this could use `Promise.all` to do this in parallel
  for (let i = 0; i < doc.items.length; i++) {
    doc.items[i].name = await getFromCacheOrTranslate(
      doc.items[i].name,
      menuLang,
      targetLan,
    );
  }
  console.log("JSON", JSON.stringify(doc));
  res.end(JSON.stringify(doc));
});