├── .eslintrc.json ├── renovate.json ├── .jshintrc ├── .github └── pull_request_template.md ├── .gitignore ├── package.json ├── LICENSE ├── README.md └── index.js /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "mixmax/node" 3 | } -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "local>mixmaxhq/renovate-config" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | // If you are using SublimeLinter, after modifying this config file, be sure to close and reopen 3 | // the file(s) you were editing to see the changes take effect. 4 | 5 | // Prohibit the use of undeclared variables. 6 | "undef": true, 7 | 8 | // Make JSHint aware of Node globals. 9 | "node": true, 10 | 11 | // Warn for unused variables and function parameters. 12 | "unused": true 13 | } 14 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | #### Changes Made 2 | 3 | #### Potential Risks 4 | 5 | 6 | #### Test Plan 7 | 8 | 9 | #### Checklist 10 | - [ ] I've increased test coverage 11 | - [ ] Since this is a public repository, I've checked I'm not publishing private data in the code, commit comments, or this PR. 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # Compiled binary addons (http://nodejs.org/api/addons.html) 20 | build/Release 21 | 22 | # Dependency directory 23 | # Commenting this out is preferred by some people, see 24 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 25 | node_modules 26 | 27 | # Users Environment Variables 28 | .lock-wscript 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "redis-status", 3 | "version": "1.0.3", 4 | "description": "A node module that checks the health of a Redis server.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "lint": "eslint ." 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/mixmaxhq/redis-status.git" 13 | }, 14 | "keywords": [ 15 | "redis", 16 | "status", 17 | "health", 18 | "monitoring" 19 | ], 20 | "author": "Jeff Wear (https://mixmax.com/)", 21 | "license": "MIT", 22 | "bugs": { 23 | "url": "https://github.com/mixmaxhq/redis-status/issues" 24 | }, 25 | "homepage": "https://github.com/mixmaxhq/redis-status", 26 | "dependencies": { 27 | "redis": "^0.12.1" 28 | }, 29 | "devDependencies": { 30 | "eslint": ">=3", 31 | "eslint-config-mixmax": "^0.6.0", 32 | "pre-commit": "^1.2.2" 33 | }, 34 | "pre-commit": [ 35 | "lint" 36 | ] 37 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Mixmax, Inc 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # redis-status 2 | 3 | A node module that checks the health of a Redis server, suitable for use by a 4 | service's "health" route. 5 | 6 | ## Installation 7 | 8 | ```sh 9 | npm install redis-status 10 | ``` 11 | or 12 | ```sh 13 | npm install redis-status --save 14 | ``` 15 | 16 | ## Usage 17 | 18 | ```js 19 | var express = require('express'); 20 | var router = express.Router(); 21 | 22 | // Construct a `RedisStatus` object configured to check the status of 23 | // the Redis server named 'foo' at `redis//localhost:6379`. 24 | var fooStatus = require('redis-status')({ 25 | name: 'foo', 26 | port: 6379, 27 | host: 'localhost' 28 | }); 29 | 30 | // If 'foo' is healthy, this route will print 'great'; otherwise it will print 31 | // the reason that 'foo' is not healthy. A monitoring service like Webmon or 32 | // Pingdom can raise non-'great' responses as alerts. 33 | router.get('/health', function(req, res) { 34 | fooStatus.checkStatus(function(err) { 35 | res.send(err || 'great'); 36 | }); 37 | }); 38 | ``` 39 | 40 | ## Contributing 41 | 42 | We welcome pull requests! Please lint your code. 43 | 44 | ## Release History 45 | 46 | * 1.0.3 Connect to Redis only to check the status and then disconnect. 47 | * 1.0.2 Keep a persistent connection to Redis. 48 | * 1.0.1 Fix typo and clean up documentation. 49 | * 1.0.0 Initial release. 50 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var redis = require('redis'); 2 | 3 | /** 4 | * Creates a `RedisStatus` object configured to check the status of the specified Redis server. 5 | * 6 | * @param {object} config 7 | * @property {string} name - An arbitrary name for the server, included in error messages. 8 | * @property {int} port - The port of the Redis server to which to connect. 9 | * @property {string} host - The host of the Redis server to which to connect. 10 | * @property {string=} password - (Optional) The password of the Redis server to which to connect. 11 | * Defaults to none. 12 | * @property {number=} memoryThreshold - (Optional) The maximum amount of memory which the Redis 13 | * server is expected to use when healthy: 14 | * - If you use Redis as an LRU cache, set this to the value of the server's `maxmemory` 15 | * configuration directive. 16 | * - If you use Redis for pub/sub, set this (via observation) to the amount of memory used by 17 | * the server 's runtime operations (most likely something like 10MB). 18 | * - Leave this unset if your Redis deployment is autoscaled. 19 | * Defaults to none. 20 | */ 21 | function RedisStatus(config) { 22 | if (!(this instanceof RedisStatus)) { 23 | return new RedisStatus(config); 24 | } 25 | 26 | this._name = config.name; 27 | this._port = config.port; 28 | this._host = config.host; 29 | this._password = config.password; 30 | this._memoryThreshold = config.memoryThreshold; 31 | } 32 | 33 | /** 34 | * Checks the status of the Redis server. 35 | * 36 | * The server is considered healthy if: 37 | * - it is reachable; 38 | * - and if the server is using less memory than is specified by this object's memory threshold 39 | * (if a threshold was specified when this object was created). 40 | * 41 | * @param {function} callback - A function to call with the status: `undefined` if the 42 | * server is healthy, or a string describing the reason that the server is unhealthy. 43 | */ 44 | RedisStatus.prototype.checkStatus = function(callback) { 45 | var redisClient = redis.createClient(this._port, this._host, { 46 | auth_pass: this._password 47 | }).on('error', function() { 48 | // If Redis is not responsive, `node_redis` will emit an error on the next turn of the event 49 | // loop. If we don't provide an error handler, that error will bring down the process. Providing 50 | // an error handler will cause `node_redis` to begin attempting to reconnect--but the ping below 51 | // will force the matter. 52 | }); 53 | 54 | var closingCallback = function() { 55 | redisClient.quit(); 56 | callback.apply(null, arguments); 57 | }; 58 | 59 | // Ensure that our Redis instance is responsive. 60 | var self = this; 61 | redisClient.ping(function(err, pong) { 62 | if (err || (pong !== 'PONG')) { 63 | closingCallback(self._name + ' Redis instance is not responsive.'); 64 | return; 65 | } 66 | 67 | if (!self._memoryThreshold) { 68 | closingCallback(); // Success. 69 | } else { 70 | redisClient.info('memory', function(err, info) { 71 | if (err) { 72 | closingCallback(self._name + ' Redis instance is not responsive.'); 73 | return; 74 | } 75 | 76 | // '# Memory\r\nused_memory:1086352…' -> ['# Memory', 'used_memory:1086352'] -> 77 | // 'used_memory:1086352' -> ['used_memory', '1086352'] -> 1086352 78 | var usedMemory = parseInt(info.split('\r\n')[1].split(':')[1]); 79 | if (usedMemory > self._memoryThreshold) { 80 | closingCallback(self._name + ' Redis instance is using abnormally high memory.'); 81 | } else { 82 | closingCallback(); // Success. 83 | } 84 | }); 85 | } 86 | }); 87 | }; 88 | 89 | module.exports = RedisStatus; --------------------------------------------------------------------------------