Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

zcache

Package Overview
Dependencies
Maintainers
7
Versions
49
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

zcache - npm Package Compare versions

Comparing version 0.3.0-beta to 0.3.1

lib/MultiplexingCache.js

1

index.js

@@ -7,2 +7,3 @@ module.exports = {

MemcacheConnection: require('./lib/MemcacheConnection'),
MultiplexingCache: require('./lib/MultiplexingCache'),
InMemoryCache: require('./lib/InMemoryCache'),

@@ -9,0 +10,0 @@ RedisConnection: require('./lib/RedisConnection'),

93

lib/CacheCluster.js

@@ -16,9 +16,7 @@ // Copyright 2014 The Obvious Corporation.

/**
* @param {Object=} options Additional options for this connection.
* 'requestTimeoutMs' specifies the timeout of a cache request.
* @constructor
* @extends {CacheInstance}
*/
function CacheCluster(options) {
CacheInstance.call(this, options)
function CacheCluster() {
CacheInstance.call(this)

@@ -70,3 +68,3 @@ this._isConnected = false

/** @inheritDoc */
/** @override */
CacheCluster.prototype.isAvailable = function () {

@@ -79,3 +77,3 @@ for (var uri in this._servers) {

/** @inheritDoc */
/** @override */
CacheCluster.prototype.connect = function () {

@@ -90,3 +88,3 @@ this._isConnected = true

/** @inheritDoc */
/** @override */
CacheCluster.prototype.disconnect = function () {

@@ -101,3 +99,3 @@ this._isConnected = false

/** @inheritDoc */
/** @override */
CacheCluster.prototype.destroy = function () {

@@ -112,3 +110,3 @@ this.disconnect()

/** @inheritDoc */
/** @override */
CacheCluster.prototype.mget = function (keys) {

@@ -141,3 +139,3 @@ var keysPerInstance = {}

} else {
self.getPartialFailureCount('mget').inc()
self._getPartialFailureCounter('mget').inc()
throw new PartialResultError(values, errors)

@@ -147,18 +145,18 @@ }

return this._wrapPromiseWithTimeout(promise, 'mget')
return this._wrapPromiseWithProfiling(promise, 'mget')
}
/** @inheritDoc */
/** @override */
CacheCluster.prototype.get = function (key) {
var cacheInstance = this._servers[this._hashRing.get(key)]
return this._wrapPromiseWithTimeout(cacheInstance.get(key), 'get')
return this._wrapPromiseWithProfiling(cacheInstance.get(key), 'get')
}
/** @inheritDoc */
/** @override */
CacheCluster.prototype.set = function (key, val, maxAgeMs) {
var cacheInstance = this._servers[this._hashRing.get(key)]
return this._wrapPromiseWithTimeout(cacheInstance.set(key, val, maxAgeMs), 'set')
return this._wrapPromiseWithProfiling(cacheInstance.set(key, val, maxAgeMs), 'set')
}
/** @inheritDoc */
/** @override */
CacheCluster.prototype.mset = function (items, maxAgeMs) {

@@ -189,3 +187,3 @@ var itemsPerInstance = {}

if (Object.keys(errors).length > 0) {
self.getPartialFailureCount('mset').inc()
self._getPartialFailureCounter('mset').inc()
throw new PartialResultError({}, errors)

@@ -195,6 +193,6 @@ }

return this._wrapPromiseWithTimeout(promise, 'mset')
return this._wrapPromiseWithProfiling(promise, 'mset')
}
/** @inheritDoc */
/** @override */
CacheCluster.prototype.del = function (key) {

@@ -206,8 +204,45 @@ var cacheInstance = this._servers[this._hashRing.get(key)]

/**
* Get the sum of timeout count from all servers in the cluster.
*
* @param {string} op The name of the operation, e.g., get, set, etc.
* @return {number}
*/
CacheCluster.prototype.getTimeoutCount = function (op) {
var total = 0
for (var uri in this._servers) total += this._servers[uri].getTimeoutCount(op)
return total
}
/** @override */
CacheCluster.prototype.resetTimeoutCount = function (op) {
for (var uri in this._servers) this._servers[uri].resetTimeoutCount(op)
}
/**
* Get the partial failure count of a certain operation.
*
* @param {string} op The name of the operation, e.g., mget or mset.
* @return {number}
*/
CacheCluster.prototype.getPartialFailureCount = function (op) {
return this._getPartialFailureCounter(op).count
}
/**
* Reset the partial failure count of a certain operation.
*
* @param {string} op The name of the operation, e.g., mget or mset.
* @return {number}
*/
CacheCluster.prototype.resetPartialFailureCount = function (op) {
return this._getPartialFailureCounter(op).clear()
}
/**
* Get the Counter object that tracks the number of partial failures of a certain operation.
*
* @param {string} op The name of the operation, e.g., mget or mset.
* @return {metrics.Counter}
*/
CacheCluster.prototype.getPartialFailureCount = function (op) {
CacheCluster.prototype._getPartialFailureCounter = function (op) {
if (!this._partialFailureCount[op]) this._partialFailureCount[op] = new metrics.Counter()

@@ -218,27 +253,17 @@ return this._partialFailureCount[op]

/**
* Wrap a promise and add two more features to it - latency measurement and timeout.
* Wrap a promise and measure how long it takses to resolve/reject.
*
* @param {Promise} origPromise The promise to wrap.
* @param {string} opName The name of the cache operation, e.g., 'get', 'set', etc.
* @param {string=} timeoutMsg A message to put into the timeout error.
* @return {Promise} A promise that behaves the same as the 'origPromise' with its latency
* measured and also timeout.
* measured.
*/
CacheCluster.prototype._wrapPromiseWithTimeout = function (origPromise, opName, timeoutMsg) {
var promiseWithTimeout = origPromise.timeout(this._reqTimeoutMs, 'Timeout Error')
CacheCluster.prototype._wrapPromiseWithProfiling = function (origPromise, opName) {
var startTime = Date.now()
var self = this
return promiseWithTimeout
return origPromise
.then(function (data) {
self.getStats(opName).update(Date.now() - startTime)
return data
},
function (err) {
if ('Timeout Error' === err.message) {
self.getTimeoutCount(opName).inc()
throw new TimeoutError(timeoutMsg || opName + ' Request timeout after ' + self._reqTimeoutMs + ' ms')
} else {
throw err
}
})

@@ -245,0 +270,0 @@ }

@@ -197,10 +197,18 @@ // Copyright 2014 The Obvious Corporation.

* @param {string} op The name of the operation, e.g., get, set, etc.
* @return {metrics.Count}
* @return {number}
*/
CacheInstance.prototype.getTimeoutCount = function (op) {
if (!this._timeoutCount[op]) this._timeoutCount[op] = new metrics.Counter()
return this._timeoutCount[op]
return this._getTimeoutCounter(op).count
}
/**
* Reset the timeout count of a certain operation.
*
* @param {string} op The name of the operation, e.g., get, set, etc.
*/
CacheInstance.prototype.resetTimeoutCount = function (op) {
this._getTimeoutCounter(op).clear()
}
/**
* Get the stats of a certain operation in a human-readable format.

@@ -218,2 +226,14 @@ *

/**
* Get the Counter object that tracks the number of timeouts of a certain
* operations.
*
* @param {string} op The name of the operation, e.g., get, set, etc.
* @return {metrics.Counter}
*/
CacheInstance.prototype._getTimeoutCounter = function (op) {
if (!this._timeoutCount[op]) this._timeoutCount[op] = new metrics.Counter()
return this._timeoutCount[op]
}
module.exports = CacheInstance

@@ -10,2 +10,3 @@ // Copyright 2014 The Obvious Corporation.

var CacheInstance = require('./CacheInstance')
var TimeoutError = require('./TimeoutError')

@@ -20,2 +21,4 @@ var CACHE_LATENCY_MS = 5

function FakeCache(logger) {
CacheInstance.call(this)
this.flush()

@@ -25,2 +28,3 @@ this._logger = logger

this._latencyMs = CACHE_LATENCY_MS
this._nextFailure = null
}

@@ -31,3 +35,3 @@ util.inherits(FakeCache, CacheInstance)

FakeCache.prototype.mget = function (keys) {
if (this._failureCount > 0) return this._fakeFail()
if (this._failureCount > 0) return this._fakeFail('mget')

@@ -46,3 +50,4 @@ var self = this

FakeCache.prototype.get = function (key) {
if (this._failureCount > 0) return this._fakeFail()
if (this._failureCount > 0) return this._fakeFail('get')
this._logger.fine('FakeCache - get', key)

@@ -61,7 +66,13 @@ var self = this

FakeCache.prototype.del = function (key) {
if (this._failureCount > 0) return this._fakeFail()
if (this._failureCount > 0) return this._fakeFail('del')
this._logger.fine('FakeCache - del', key)
this._requestCounts.del += 1
delete this._data[key]
return Q.resolve()
var self = this
// Add an artificial delay to mimic real world cache latency.
return Q.delay(this._latencyMs)
.then(function actualDel() {
self._requestCounts.del += 1
delete self._data[key]
return Q.resolve()
})
}

@@ -71,3 +82,3 @@

FakeCache.prototype.set = function (key, value) {
if (this._failureCount > 0) return this._fakeFail()
if (this._failureCount > 0) return this._fakeFail('set')
this._logger.fine('FakeCache - set', key, value)

@@ -87,3 +98,3 @@

FakeCache.prototype.mset = function (items) {
if (this._failureCount > 0) return this._fakeFail()
if (this._failureCount > 0) return this._fakeFail('mset')

@@ -174,2 +185,9 @@ var self = this

/**
* Set failure count
*/
FakeCache.prototype.setNextFailure = function (err) {
this._nextFailure = err
}
/**
* Set the latency for all cache operations.

@@ -196,9 +214,17 @@ *

FakeCache.prototype._fakeFail = function () {
FakeCache.prototype._fakeFail = function (op) {
this._failureCount -= 1
return Q.reject(new Error('Fake Error'))
var failure
if (this._nextFailure) {
if (this._nextFailure instanceof TimeoutError) this._getTimeoutCounter(op).inc()
failure = this._nextFailure
this._nextFailure = null
} else {
failure = new Error('Fake Error')
}
return Q.reject(failure)
}
FakeCache.prototype._getInternal = function (key) {
this._logger.fine('FakeCache - get', key, (typeof this._data[key] !== 'undefined') ? '[HIT]' : '[MISS]')
this._logger.fine('FakeCache - getInternal', key, (typeof this._data[key] !== 'undefined') ? '[HIT]' : '[MISS]')
var val = this._data[key]

@@ -205,0 +231,0 @@ if (typeof val === 'undefined') {

@@ -107,2 +107,7 @@ // Copyright 2014 The Obvious Corporation.

/** @inheritDoc */
MultiWriteCacheGroup.prototype.resetTimeoutCount = function (op) {
return this._instance.resetTimeoutCount(op)
}
/**

@@ -109,0 +114,0 @@ * A helper function that does write operations, set, mset and del, to all

@@ -192,3 +192,3 @@ var redis = require('redis')

isTimeout = true
self.getTimeoutCount(opName).inc()
self._getTimeoutCounter(opName).inc()
}, this._reqTimeoutMs)

@@ -195,0 +195,0 @@

{
"name": "zcache",
"description": "AWS zone-aware multi-layer cache",
"version": "0.3.0-beta",
"version": "0.3.1",
"homepage": "https://github.com/Obvious/zcache",

@@ -22,2 +22,3 @@ "authors": [

"redis": "0.8.2",
"hiredis": "0.1.16",
"metrics": "0.1.6",

@@ -24,0 +25,0 @@ "hashring": "1.0.3"

@@ -107,3 +107,3 @@ // Copyright 2014 The Obvious Corporation.

test.ok(err instanceof PartialResultError)
test.equal(1, cluster.getPartialFailureCount('mget').count)
test.equal(1, cluster.getPartialFailureCount('mget'))
var data = err.getData()

@@ -147,3 +147,3 @@ var error = err.getError()

test.ok(err instanceof PartialResultError)
test.equal(1, cluster.getPartialFailureCount('mset').count)
test.equal(1, cluster.getPartialFailureCount('mset'))
var data = err.getData()

@@ -162,31 +162,2 @@ var error = err.getError()

builder.add(function testTimeoutFailure(test) {
var cluster = new zcache.CacheCluster({requestTimeoutMs: 10})
var fakeCache1 = new zcache.FakeCache(logger)
cluster.addNode('FakeCache1', fakeCache1, 1, 0)
cluster.addNode('FakeCache2', new zcache.FakeCache(logger), 1, 0)
cluster.addNode('FakeCache3', new zcache.FakeCache(logger), 1, 0)
cluster.connect()
var items = []
for (var i = 0; i < 100; i++) {
items.push({
key: 'key' + i,
value: 'value' + i
})
}
fakeCache1.setLatencyMs(20)
return cluster.mset(items)
.then(function () {
test.fail('The mget() call is supposed to fail')
})
.fail(function (err) {
test.ok(err instanceof TimeoutError)
test.equals('mset Request timeout after 10 ms', err.message)
test.equals(1, cluster.getTimeoutCount('mset').count, 'The timeout count should be 1')
test.equals(0, cluster.getStats('mset').count(), 'There should be no stats data')
})
})
builder.add(function testDel(test) {

@@ -295,3 +266,3 @@ var cluster = new zcache.CacheCluster()

test.ok(cluster.getStats('set').mean() > 28)
test.ok(cluster.getStats('set').mean() < 33)
test.ok(cluster.getStats('set').mean() < 35)

@@ -307,3 +278,3 @@ var getPromises = []

test.ok(cluster.getStats('get').mean() > 28)
test.ok(cluster.getStats('get').mean() < 33)
test.ok(cluster.getStats('get').mean() < 35)

@@ -322,3 +293,3 @@ var items = []

test.ok(cluster.getStats('mset').mean() > 28)
test.ok(cluster.getStats('mset').mean() < 33)
test.ok(cluster.getStats('mset').mean() < 35)

@@ -334,3 +305,3 @@ var keys = []

test.ok(cluster.getStats('mget').mean() > 28)
test.ok(cluster.getStats('mget').mean() < 33)
test.ok(cluster.getStats('mget').mean() < 35)
})

@@ -372,1 +343,38 @@

})
builder.add(function testTimeoutFailure(test) {
var cluster = new zcache.CacheCluster()
var fakeCache1 = new zcache.FakeCache(logger)
var fakeCache2 = new zcache.FakeCache(logger)
cluster.addNode('FakeCache1', fakeCache1, 1, 0)
cluster.addNode('FakeCache2', fakeCache2, 1, 0)
cluster.addNode('FakeCache3', new zcache.FakeCache(logger), 1, 0)
cluster.connect()
var items = []
for (var i = 0; i < 100; i++) {
items.push({
key: 'key' + i,
value: 'value' + i
})
}
// Both fakeCache1 and fakeCache2 will timeout in the next requests.
// We should see timeout count to be 2.
fakeCache1.setFailureCount(1)
fakeCache1.setNextFailure(new TimeoutError())
fakeCache2.setFailureCount(1)
fakeCache2.setNextFailure(new TimeoutError())
return cluster.mset(items)
.then(function () {
test.fail('The mget() call is supposed to fail')
})
.fail(function (err) {
test.equal(1, cluster.getPartialFailureCount('mset'), 'One partail failure from mset')
test.equal(2, cluster.getTimeoutCount('mset'), 'Two timeouts from all cache servers')
cluster.resetTimeoutCount('mset')
test.equal(0, cluster.getTimeoutCount('mset'), 'Return 0 after reset')
})
})
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc