All files / src/utils RedisCacher.ts

9.86% Statements 7/71
0% Branches 0/30
0% Functions 0/18
10.61% Lines 7/66

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134    5x 5x   5x 5x 5x   5x   5x                                                                                                                                                                                                                                                    
"use strict";
 
const Moleculer = require("moleculer"),
	BaseCacher = Moleculer.Cachers.Base;
 
const redisIO = require("ioredis"), //https://github.com/luin/ioredis
	Promise = require("bluebird"),
	_ = require("lodash");
 
import { Redis } from "../drivers/Redis";
 
export class RedisCacher extends BaseCacher {
	private client: any; //redis client
	constructor(opts) {
		if (typeof opts == "string") opts = { redis_cluster: opts };
		super(opts);
	}
 
	init(broker) {
		super.init(broker);
 
		this.client = new Redis(this.opts.redis_cluster);
		this.client.on("connect", () => {
			this.logger.info("Services' Redis Cache connected.");
		});
 
		this.client.on("error", err => {
			this.logger.error(err);
		});
 
		this.logger.debug("Services' Cacher created. Prefix: " + this.prefix);
	}
 
	close() {
		return this.client.quit();
	}
 
	get(key) {
		this.logger.debug(`GET ${key}`);
		return this.client.get(this.prefix + key).then(data => {
			if (data) {
				this.logger.debug(`FOUND ${key}`);
				try {
					return JSON.parse(data);
				} catch (err) {
					this.logger.error("Redis result parse error.", err, data);
				}
			}
			return null;
		});
	}
 
	set(key, data, ttl) {
		data = JSON.stringify(data);
		this.logger.debug(`SET ${key}`);
		if (ttl == null) ttl = this.opts.ttl;
 
		if (ttl) {
			return this.client.setex(this.prefix + key, ttl, data);
		} else {
			return this.client.set(this.prefix + key, data);
		}
	}
 
	del(key) {
		if (_.isArray(key)) {
			return Promise.all(key.map(m => this.del(m)));
		}
		this.logger.debug(`DELETE ${key}`);
 
		return this.client.del(this.prefix + key).catch(err => {
			this.logger.error("Redis `del` error.", key, err);
		});
	}
 
	clean(match) {
		if (_.isArray(match)) {
			return Promise.all(match.map(m => this.clean(m)));
		}
 
		if (match === undefined || match === null) {
			//default
			match = "*";
		}
 
		if (!_.isString(match))
			return new Error("expecting type string, got " + typeof match);
 
		return new Promise((resolve, reject) => {
			match = this.prefix + match.replace(/\*\*/g, "*");
			this.logger.debug(`CLEAN ${match}`);
			let self = this;
			let scanDel = function(cursor, cb) {
				self.client.scan(cursor, "MATCH", match, "COUNT", 100, function(
					err,
					resp
				) {
					if (err) {
						return cb(err);
					}
					let nextCursor = parseInt(resp[0]);
					let keys = resp[1];
 
					if (!keys.length) {
						if (!nextCursor) return cb(null);
 
						return scanDel(nextCursor, cb);
					}
 
					self.client.del(keys, function(err) {
						if (err) {
							return cb(err);
						}
						if (!nextCursor) {
							return cb(null);
						}
						scanDel(nextCursor, cb);
					});
				});
			};
 
			scanDel(0, err => {
				if (err) {
					this.logger.error("Redis `scanDel` error.", match, err);
 
					return reject(err);
				}
 
				resolve();
			});
		});
	}
}