Running N1QL as a service with Upstart

TL;DR: Copy this script to /etc/init and run start n1ql from the command line to start N1QL as a service.

The 3rd developer preview of N1QL, the new Couchbase query language, has been out for a while now and I've seen several clients developing code for N1QL already. The one compaint they all had was that it doesn't come with a convenient installer that would set it up on their dev/CI/production environments. (Well, actually, clients always complain about everything, but this is what we're solving today.) Obviously, in the production release it will be part of Couchbase Server itself, but for now we have to run it as a separate service.

Setting up N1QL as a service on Linux is actually quite simple, since pretty much every disto these days uses Upstart as its init daemon.

Note that the new 2.0 generation of Couchbase SDKs assumes that the cbq (N1QL) service is running on every Couchbase node in the cluster, so you'll need to repeat the following process on every node.

First, download and extract N1QL DP3 somewhere on your system, for example into /opt/n1ql.

Next, create a file named n1ql.conf in your /etc/init folder with the following content:

#!upstart
description "N1QL Service"
author      "David Ostrovsky"

start on stopped rc RUNLEVEL=[2345]
respawn

script
    export HOME="/root"

    echo $$ > /var/run/n1ql.pid
    exec /opt/n1ql/cbq-engine -couchbase http://localhost:8091 >> /var/log/n1ql.sys.log 2>&1
end script

pre-start script
    # Date format same as (new Date()).toISOString() for consistency
    echo "[`date -u +%Y-%m-%dT%T.%3NZ`] (sys) Starting" >> /var/log/n1ql.sys.log
end script

pre-stop script
    rm /var/run/n1ql.pid
    echo "[`date -u +%Y-%m-%dT%T.%3NZ`] (sys) Stopping" >> /var/log/n1ql.sys.log
end script

post-stop exec sleep 5

We want to start the N1QL service only after Couchbase Server starts. However, because Couchbase still uses the old SysV init stript, we can't configure our Upstart service to start and stop N1QL depending on the status of the Couchbase service itself. The best we can do is start N1QL after all the SysV scripts have finished executing, which is what start on stopped rc RUNLEVEL=[2345] does. We also tell it to respawn if the process exits with a non-zero error code, because even if the Couchbase init script has finished, the server might not be accepting connections just yet, so Upstart will keep trying until cbq-engine connects. Remember to replace the path to cbq-engine in the script with the correct location on your system.

You can now start the N1QL service from the command line:

start n1ql

Unsurprisingly, to stop the service run:

stop n1ql

To check its status:

status n1ql

It will also persist through reboots, so give that a try (extra points for doing it on the production system!) If you run into any issues, whether on start or at runtime, check the N1QL service log, which is set to /var/log/n1ql.sys.log in the example script.

With the service running, you can use N1QL from your application code through the SDK, or from the command line shell that comes with the developer preview:

/opt/n1ql/cbq -engine=http://localhost:8093

Important note: If you're using Couchbase Server 3.0.x, before you can run N1QL queries, you have to create the primary index for every bucket you intend to query. To do so, either run the following command in the cbq shell:

CREATE PRIMARY INDEX ON <bucket>

Or use the HTTP API (the query has to be URL encoded):

curl http://localhost:8093/query?q=CREATE%20PRIMARY%20INDEX%20ON%20<bucket>

That's it. Go forth and query all the things!

PS - Thanks to Tim Smart for the pre and post start log file idea, which I shamelessly "borrowed". Read the rest of his blog to learn how to use Monit to monitor the service and restart it if the process stops responding for any reason.

David Ostrovsky

I'm a level 38 Computer Geek, with experience in everything from databases to mobile apps. I'm also a Senior Solutions Architect at Couchbase, where I often keep clients happy by coding hard.

comments powered by Disqus