Search code examples
javascriptamazon-web-servicessvelteamazon-translate

Managing amazon translation with redis


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?


Solution

  • 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));
    });