v2.0.0
This commit is contained in:
commit
f07410bc14
|
@ -0,0 +1,37 @@
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules
|
||||||
|
jspm_packages
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2016 AJ ONeal
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
|
@ -0,0 +1,148 @@
|
||||||
|
cluster-store
|
||||||
|
=============
|
||||||
|
|
||||||
|
Makes any storage strategy similar to `express/session` useful in both `cluster` and non-`cluster` environments
|
||||||
|
by wrapping it with `cluster-rpc`.
|
||||||
|
|
||||||
|
Also works with **level-session-store** (leveldb), **connect-session-knex** (SQLite3), **session-file-store** (fs),
|
||||||
|
and any other embedded / in-process store.
|
||||||
|
|
||||||
|
Note: Most people would probably prefer to just use Redis rather than wrap a dumb memstore as a service...
|
||||||
|
but I am not most people.
|
||||||
|
|
||||||
|
Install
|
||||||
|
=======
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install --save memstore-cluster@2.x
|
||||||
|
```
|
||||||
|
|
||||||
|
v1.x vs v2.x
|
||||||
|
------------
|
||||||
|
|
||||||
|
The old v1 used `ws` which makes it usable when clustering node processes without using `cluster`.
|
||||||
|
|
||||||
|
If you need that functionaliy, use it.
|
||||||
|
|
||||||
|
Usage
|
||||||
|
=====
|
||||||
|
|
||||||
|
### standalone (non-cluster)
|
||||||
|
--------------
|
||||||
|
|
||||||
|
The usage is exactly the same as **master**, no changes necessary.
|
||||||
|
|
||||||
|
### master
|
||||||
|
|
||||||
|
In the **master**/**standalone** process you will create the real store instance
|
||||||
|
and then in the you must pass each worker via `addWorker()` so that it signals
|
||||||
|
the worker to create its own rpc-wrapped instance.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var cluster = require('cluster');
|
||||||
|
|
||||||
|
var cstore = require('cluster-store/master').create({
|
||||||
|
name: 'foo-store'
|
||||||
|
});
|
||||||
|
|
||||||
|
cstore.addWorker(cluster.fork());
|
||||||
|
|
||||||
|
cstore.then(function (store) {
|
||||||
|
store.set('foo', 'bar');
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### worker
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// retrieve the instance
|
||||||
|
var cstore = require('cluster-store/worker').create({
|
||||||
|
name: 'foo-store'
|
||||||
|
});
|
||||||
|
|
||||||
|
cstore.then(function (store) {
|
||||||
|
store.get('foo', function (err, result) {
|
||||||
|
console.log(result);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
API
|
||||||
|
===
|
||||||
|
|
||||||
|
This is modeled after Express'
|
||||||
|
[Session Store Implementation](https://github.com/expressjs/session#session-store-implementation)
|
||||||
|
|
||||||
|
**Note**: These are only exposed if the underlying store supports them.
|
||||||
|
|
||||||
|
CRUD methods
|
||||||
|
------------
|
||||||
|
|
||||||
|
* `store.set(id, data, fn) => (error)`
|
||||||
|
* `store.get(id, fn) => (error, data)`
|
||||||
|
* `store.touch(id, data, fn) => (error)`
|
||||||
|
* `store.destroy(id, fn) => (error)`
|
||||||
|
|
||||||
|
Helpers
|
||||||
|
-------
|
||||||
|
|
||||||
|
* `store.all(fn) => (error, array)`
|
||||||
|
* `store.clear(fn) => (error)`
|
||||||
|
* `store.length(fn) => (error, length)`
|
||||||
|
|
||||||
|
See <https://github.com/expressjs/session#session-store-implementation>@4.x for full details
|
||||||
|
|
||||||
|
Example
|
||||||
|
=======
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var cluster = require('cluster');
|
||||||
|
var cstore;
|
||||||
|
|
||||||
|
|
||||||
|
if (cluster.isMaster) {
|
||||||
|
|
||||||
|
|
||||||
|
cstore = require('./master').create({
|
||||||
|
name: 'foo-level'
|
||||||
|
});
|
||||||
|
cstore.addWorker(cluster.fork());
|
||||||
|
cstore.then(function (store) {
|
||||||
|
store.put('foo', 'bar');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
|
||||||
|
cstore = require('./worker').create({
|
||||||
|
name: 'foo-level'
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cstore.then(function (store) {
|
||||||
|
setTimeout(function () {
|
||||||
|
store.get('foo', function (err, result) {
|
||||||
|
console.log(cluster.isMaster && '0' || cluster.worker.id.toString(), "store.get('foo')", result);
|
||||||
|
|
||||||
|
if (!cluster.isMaster) {
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, 250);
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on('unhandledRejection', function (err) {
|
||||||
|
console.log('unhandledRejection', err);
|
||||||
|
});
|
||||||
|
```
|
|
@ -0,0 +1,12 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
console.error("");
|
||||||
|
console.error("One does not simply require('memstore-cluster');");
|
||||||
|
console.error("");
|
||||||
|
console.error("Usage:");
|
||||||
|
console.error("\trequire('memstore-cluster/master').create({ name: ... });");
|
||||||
|
console.error("\trequire('memstore-cluster/worker').create({ name: ... });");
|
||||||
|
console.error("");
|
||||||
|
console.error("");
|
||||||
|
|
||||||
|
process.exit(1);
|
|
@ -0,0 +1,18 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports.create = function (opts) {
|
||||||
|
opts = opts || {};
|
||||||
|
|
||||||
|
var db = require('./memstore').create();
|
||||||
|
|
||||||
|
return require('cluster-rpc/master').create({
|
||||||
|
instance: opts.store || db
|
||||||
|
, methods: [
|
||||||
|
'set', 'get', 'touch', 'destroy'
|
||||||
|
, 'all', 'length', 'clear'
|
||||||
|
, 'on', 'off', 'removeEventListener', 'addEventListener'
|
||||||
|
]
|
||||||
|
, name: 'memstore.' + (opts.name || '')
|
||||||
|
, master: opts.master
|
||||||
|
});
|
||||||
|
};
|
|
@ -0,0 +1,73 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/*global Promise*/
|
||||||
|
var defer;
|
||||||
|
|
||||||
|
if ('function' === typeof setImmediate) {
|
||||||
|
defer = setImmediate;
|
||||||
|
} else {
|
||||||
|
defer = function (fn) { process.nextTick(fn.bind.apply(fn, arguments)); };
|
||||||
|
}
|
||||||
|
|
||||||
|
function create(opts) {
|
||||||
|
opts = opts || {};
|
||||||
|
// don't leak prototypes as implicitly non-null
|
||||||
|
var db = Object.create(null);
|
||||||
|
|
||||||
|
function log() {
|
||||||
|
if (!opts.debug) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log.apply(console, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
// required / recommended
|
||||||
|
set: function (id, data, fn) {
|
||||||
|
log('set(id, data)', id, data);
|
||||||
|
db[id] = data;
|
||||||
|
|
||||||
|
if (!fn) { return; }
|
||||||
|
defer(fn, null);
|
||||||
|
}
|
||||||
|
, get: function (id, fn) {
|
||||||
|
log('get(id)', id);
|
||||||
|
if (!fn) { return; }
|
||||||
|
defer(fn, null, 'undefined' === typeof db[id] ? null : db[id]);
|
||||||
|
}
|
||||||
|
, touch: function (id, data, fn) {
|
||||||
|
db[id] = data;
|
||||||
|
|
||||||
|
if (!fn) { return; }
|
||||||
|
defer(fn, null);
|
||||||
|
}
|
||||||
|
, destroy: function (id, fn) {
|
||||||
|
log('destroy(id)', id);
|
||||||
|
delete db[id];
|
||||||
|
|
||||||
|
if (!fn) { return; }
|
||||||
|
defer(fn, null);
|
||||||
|
}
|
||||||
|
// optional
|
||||||
|
, all: function (fn) {
|
||||||
|
if (!fn) { return; }
|
||||||
|
defer(fn, null, Object.keys(db).map(function (key) {
|
||||||
|
return db[key];
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
, length: function (fn) {
|
||||||
|
if (!fn) { return; }
|
||||||
|
defer(fn, null, Object.keys(db).length);
|
||||||
|
}
|
||||||
|
, clear: function (fn) {
|
||||||
|
log('clear()', id);
|
||||||
|
db = Object.create(null);
|
||||||
|
|
||||||
|
if (!fn) { return; }
|
||||||
|
defer(fn, null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.create = create;
|
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
"name": "cluster-store",
|
||||||
|
"version": "2.0.0",
|
||||||
|
"description": "A wrapper to enable the use of any in-process store with node cluster via cluster process and worker messages (i.e. for Raspberry Pi servers).",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "node test-cluster.js",
|
||||||
|
"start": "node server.js"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/coolaj86/cluster-store.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"store",
|
||||||
|
"session",
|
||||||
|
"connect",
|
||||||
|
"express",
|
||||||
|
"memstore",
|
||||||
|
"cluster",
|
||||||
|
"rpi2"
|
||||||
|
],
|
||||||
|
"author": "AJ ONeal <coolaj86@gmail.com> (http://coolaj86.com/)",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/coolaj86/cluster-store/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/coolaj86/cluster-store#readme",
|
||||||
|
"dependencies": {
|
||||||
|
"cluster-rpc": "^1.0.3"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var cluster = require('cluster');
|
||||||
|
var cstore;
|
||||||
|
//global.Promise = require('bluebird');
|
||||||
|
|
||||||
|
|
||||||
|
if (cluster.isMaster) {
|
||||||
|
|
||||||
|
|
||||||
|
cstore = require('./master').create({
|
||||||
|
name: 'foo-level'
|
||||||
|
});
|
||||||
|
cstore.addWorker(cluster.fork());
|
||||||
|
cstore.then(function (db) {
|
||||||
|
db.set('foo', 'bar');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
|
||||||
|
cstore = require('./worker').create({
|
||||||
|
name: 'foo-level'
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cstore.then(function (db) {
|
||||||
|
setTimeout(function () {
|
||||||
|
db.get('foo', function (err, result) {
|
||||||
|
console.log(cluster.isMaster && '0' || cluster.worker.id.toString(), "db.get('foo')", result);
|
||||||
|
|
||||||
|
if (!cluster.isMaster) {
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, 250);
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on('unhandledRejection', function (err) {
|
||||||
|
console.log('unhandledRejection', err);
|
||||||
|
});
|
Loading…
Reference in New Issue