middleware() {
		return {
			name: "Cacher",
			localAction: (handler, action) => {
				const opts = _.defaultsDeep(
					{},
					isObject(action.cache) ? action.cache : { enabled: !!action.cache }
				);
				opts.lock = _.defaultsDeep(
					{},
					isObject(opts.lock) ? opts.lock : { enabled: !!opts.lock }
				);
				if (opts.enabled !== false) {
					const isEnabledFunction = isFunction(opts.enabled);

					return function cacherMiddleware(ctx) {
						if (isEnabledFunction) {
							if (!opts.enabled.call(ctx.service, ctx)) {
								// Cache is disabled. Call the handler only.
								return handler(ctx);
							}
						}

						// Disable caching with `ctx.meta.$cache = false`
						if (ctx.meta["$cache"] === false) return handler(ctx);

						// Cache is enabled but not in healthy state
						// More info: https://github.com/moleculerjs/moleculer/issues/978
						if (this.connected === false) {
							this.logger.debug(
								"Cacher is enabled but it is not connected at the moment... Calling the handler"
							);
							return handler(ctx);
						}

						const cacheKey = this.getCacheKey(
							action.name,
							ctx.params,
							ctx.meta,
							opts.keys,
							opts.keygen
						);
						// Using lock
						if (opts.lock.enabled !== false) {
							let cachePromise;
							if (opts.lock.staleTime && this.getWithTTL) {
								// If enable cache refresh
								cachePromise = this.getWithTTL(cacheKey).then(({ data, ttl }) => {
									if (data != null) {
										if (
											opts.lock.staleTime &&
											ttl &&
											ttl < opts.lock.staleTime
										) {
											// Cache is stale, try to refresh it.
											this.tryLock(cacheKey, opts.lock.ttl)
												.then(unlock => {
													return handler(ctx)
														.then(result => {
															// Save the result to the cache and realse the lock.
															return this.set(
																cacheKey,
																result,
																opts.ttl
															).then(() => unlock());
														})
														.catch((/*err*/) => {
															return this.del(cacheKey).then(() =>
																unlock()
															);
														});
												})
												.catch((/*err*/) => {
													// The cache is refreshing on somewhere else.
												});
										}
									}
									return data;
								});
							} else {
								cachePromise = this.get(cacheKey);
							}
							return cachePromise.then(data => {
								if (data != null) {
									// Found in the cache! Don't call handler, return with the content
									ctx.cachedResult = true;
									return data;
								}
								// Not found in the cache! Acquire a lock
								return this.lock(cacheKey, opts.lock.ttl).then(unlock => {
									return this.get(cacheKey).then(content => {
										if (content != null) {
											// Cache found. Realse the lock and return the value.
											ctx.cachedResult = true;
											return unlock().then(() => {
												return content;
											});
										}
										// Call the handler
										return handler(ctx)
											.then(result => {
												// Save the result to the cache and realse the lock.
												this.set(cacheKey, result, opts.ttl).then(() =>
													unlock()
												);
												return result;
											})
											.catch(e => {
												return unlock().then(() => {
													return Promise.reject(e);
												});
											});
									});
								});
							});
						}
						// Not using lock
						return this.get(cacheKey).then(content => {
							if (content != null) {
								// Found in the cache! Don't call handler, return with the content
								ctx.cachedResult = true;
								return content;
							}

							// Call the handler
							return handler(ctx).then(result => {
								// Save the result to the cache
								this.set(cacheKey, result, opts.ttl);

								return result;
							});
						});
					}.bind(this);
				}

				return handler;
			}
		};
	}
Register cacher as a middleware

@memberof Cacher