v2.0.0
This commit is contained in:
commit
f07410bc14
37
.gitignore
vendored
Normal file
37
.gitignore
vendored
Normal file
@ -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
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -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.
|
148
README.md
Normal file
148
README.md
Normal file
@ -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);
|
||||
});
|
||||
```
|
12
index.js
Normal file
12
index.js
Normal file
@ -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);
|
18
master.js
Normal file
18
master.js
Normal file
@ -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
|
||||
});
|
||||
};
|
73
memstore.js
Normal file
73
memstore.js
Normal file
@ -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;
|
32
package.json
Normal file
32
package.json
Normal file
@ -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"
|
||||
}
|
||||
}
|
46
test.js
Normal file
46
test.js
Normal file
@ -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…
x
Reference in New Issue
Block a user