How should I connect to a Redis instance from an AWS Lambda function?
<p>I'm trying to build an API for a single-page web app using <a href="https://aws.amazon.com/lambda/" rel="noreferrer">AWS Lambda</a> and the <a href="https://github.com/serverless/serverless" rel="noreferrer">Serverless Framework</a>. I want to use <a href="https://redislabs.com/redis-cloud" rel="noreferrer">Redis Cloud</a> for storage, mostly for its combination of speed and data persistence. I may use more Redis Cloud features in the future, so I'd prefer to avoid using ElastiCache for this. My Redis Cloud instance is running in the same AWS region as my function.</p>

<p>I have a function called <code>related</code> that takes a hashtag from a GET request to an API endpoint, and checks to see if there's an entry for it in the database. If it's there, it should return the results immediately. If not, it should query <a href="https://ritetag.com/" rel="noreferrer">RiteTag</a>, write the results to Redis, and then return the results to the user.</p>

<p>I'm pretty new to this, so I'm probably doing something adorably naive. Here's the event handler:</p>

<pre><code>'use strict'

const lib = require('../lib/related')

module.exports.handler = function (event, context) {
  lib.respond(event, (err, res) =&gt; {
    if (err) {
      return context.fail(err)
    } else {
      return context.succeed(res)
    }
  })
}
</code></pre>

<p>Here's the <code>../lib/related.js</code> file:</p>

<pre><code>var redis = require('redis')
var jsonify = require('redis-jsonify')
var rt = require('./ritetag')
var redisOptions = {
  host: process.env.REDIS_URL,
  port: process.env.REDIS_PORT,
  password: process.env.REDIS_PASS
}
var client = jsonify(redis.createClient(redisOptions))

module.exports.respond = function (event, callback) {
  var tag = event.hashtag.replace(/^#/, '')
  var key = 'related:' + tag

  client.on('connect', () =&gt; {
    console.log('Connected:', client.connected)
  })

  client.on('end', () =&gt; {
    console.log('Connection closed.')
  })

  client.on('ready', function () {
    client.get(key, (err, res) =&gt; {
      if (err) {
        client.quit()
        callback(err)
      } else {
        if (res) {
          // Tag is found in Redis, so send results directly.
          client.quit()
          callback(null, res)
        } else {
          // Tag is not yet in Redis, so query Ritetag.
          rt.hashtagDirectory(tag, (err, res) =&gt; {
            if (err) {
              client.quit()
              callback(err)
            } else {
              client.set(key, res, (err) =&gt; {
                if (err) {
                  callback(err)
                } else {
                  client.quit()
                  callback(null, res)
                }
              })
            }
          })
        }
      }
    })
  })
}
</code></pre>

<p>All of this works as expected, to a point. If I run the function locally (using <code>sls function run related</code>), I have no problems whatsoever—tags are read from and written to the Redis database as they should be. However, when I deploy it (using <code>sls dash deploy</code>), it works the <em>first time it's run after deployment</em>, and then stops working. All subsequent attempts to run it simply return <code>null</code> to the browser (or Postman, or curl, or the web app). This is true regardless of whether the tag I use for testing is already in the database or not. If I then re-deploy, making no changes to the function itself, it works again—once.</p>

<p>On my local machine, the function first logs <code>Connected: true</code> to the console, then the results of the query, then <code>Connection closed.</code> On AWS, it logs <code>Connected: true</code>, then the results of the query, and that's it. On the second run, it logs <code>Connection closed.</code> and nothing else. On the third and all subsequent runs, it logs nothing at all. Neither environment ever reports any errors.</p>

<p>It seems pretty clear that the problem is with the connection to Redis. If I don't close it in the callbacks, then subsequent attempts to call the function just time out. I've also tried using <code>redis.unref</code> instead of <code>redis.quit</code>, but that didn't seem to make any difference.</p>

<p>Any help would be greatly appreciated.</p>