Intro to Lua and Openresty, Part 5: Redis

Posted on March 5, 2017

In Part 4 of this series, we used envvars to tell our Lua webapp how to connect to Postgres. This next post will demonstrate how to interact with redis (connect/read/write).

For this example, we will use the resty.redis lua module.

If you are following along in the code, we are here.

Connecting and Writing to Redis with Lua

To demonstrate the basics, this example will:

We should then be able to send in some test messages and then cat the keys on the queue table.

worker_processes  1;
env REDIS_HOST;
error_log error.log;
events {
    worker_connections 1024;
}
http {
    server {
        listen        8000;
        charset       utf-8;
        charset_types application/json;
        default_type  application/json;
        location / {
            content_by_lua '
                local cjson = require "cjson"
                local redis = require "resty.redis"
                local r     = redis:new()
                local ok, err = r:connect(os.getenv("REDIS_HOST"), 6379)
                if not ok then
                  ngx.say(cjson.encode({status = "error", msg =  "failed to connect: " .. err}))
                  return
                end
                local get, post, files = require "resty.reqargs"()
                assert(r:lpush("queue", cjson.encode(post)))
                r = nil
                ngx.status  = ngx.HTTP_OK
                ngx.say(cjson.encode({status = "saved", msg=post}))
                return ngx.exit(ngx.HTTP_OK)
            ';
        }
    }
}

The lua application will now use the REDIS_HOST envvar when connecting to the redis host, so we need to include that in our Dockerfile. We are using the resty.redis lua module, so we also need to install that with luarocks:

FROM openresty/openresty:alpine-fat

EXPOSE 8000
ENV REDIS_HOST 127.0.0.1
RUN /usr/local/openresty/luajit/bin/luarocks install lua-resty-reqargs
ADD nginx.conf /usr/local/openresty/nginx/conf/nginx.conf
RUN echo 'hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4' > /etc/nsswitch.conf

Makefile

We won’t use Postgres for this example, but our Makefile is similar to the last few examples:

build:
	docker build --tag=app:6    --rm=true .

# add "-v `pwd`:/usr/local/openresty/nginx/conf/" to the app for local dev
run:
	docker run -d --name redis  --net host -p 127.0.0.1:6379:6379 redis:alpine
	docker run -d --name app    --net host -p 127.0.0.1:8000:8000 app:6

clean:
	docker stop redis  || true
	docker stop app    || true
	docker rm   redis  || true
	docker rm   app    || true

reload:
	docker exec -it app   /usr/local/openresty/nginx/sbin/nginx -s reload

logs:
	docker exec -it app   tail -f /usr/local/openresty/nginx/error.log

cat-posts:
	docker exec -it redis redis-cli -c LRANGE queue 0 -1

app-shell:
	docker exec -it app   /bin/sh

redis-shell:
	docker exec -it redis redis-cli

test:
	curl -H "Content-Type: application/json" -X POST -d '{"username":"xyz","password":"xyz"}' localhost:8000/

This gives us a number of make targets which are very helpful when developing and debugging unexpected issues.

Build / Test / Run

Use make build to create the Docker image:

ᐅ make build
docker build --tag=app:6    --rm=true ./
Sending build context to Docker daemon  16.9 kB
Step 1 : FROM openresty/openresty:alpine-fat
 ---> 366babf2b04d
Step 2 : EXPOSE 8000
 ---> Using cache
 ---> 35a8c6e42825
Step 3 : ENV REDIS_HOST 127.0.0.1
 ---> Using cache
 ---> 43fc68284411
Step 4 : RUN /usr/local/openresty/luajit/bin/luarocks install lua-resty-reqargs
 ---> Using cache
 ---> e17bae3848b8
Step 5 : ADD nginx.conf /usr/local/openresty/nginx/conf/nginx.conf
 ---> Using cache
 ---> 306d00c38cee
Step 6 : RUN echo 'hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4' > /etc/nsswitch.conf
 ---> Using cache
 ---> 9ae83b74b72a
Successfully built 9ae83b74b72a

Run:

ᐅ make run
docker run -d --name redis  --net host -p 127.0.0.1:6379:6379 redis:6
399c0c7f815d0e4ab7660b7e2852fb64f6f82ec42586c232a70bc11f5b577d2c
docker run -d --name app    --net host -p 127.0.0.1:8000:8000 app:6
39e71e2333452730960e60c09afe4a6ad1bc8f8a4d625f49c2f3859ad1c0634f

Test:

ᐅ make test
curl -H "Content-Type: application/json" -X POST -d '{"username":"xyz","password":"xyz"}' localhost:8000/
{"status":"saved","msg":{"password":"xyz","username":"xyz"}}

I repeated that test 4 times, let’s see what is in redis:

ᐅ make cat-posts
docker exec -it redis redis-cli -c LRANGE queue 0 -1
1) "{\"password\":\"xyz\",\"username\":\"xyz\"}"
2) "{\"password\":\"xyz\",\"username\":\"xyz\"}"
3) "{\"password\":\"xyz\",\"username\":\"xyz\"}"
4) "{\"password\":\"xyz\",\"username\":\"xyz\"}"

Yay!

Then teardown the running containers with make clean.


Time Tracking: since last check: 1 hour; total: 7 hours


Continue on to an Interlude, Issues with luarocks and Alpine