feathers-sync
Advanced tools
Comparing version 2.1.0 to 2.2.0
# Change Log | ||
## [v2.1.0](https://github.com/feathersjs-ecosystem/feathers-sync/tree/v2.1.0) (2020-04-09) | ||
[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-sync/compare/v2.0.0...v2.1.0) | ||
**Merged pull requests:** | ||
- Added support for using an existing Redis Client instead of creating … [\#146](https://github.com/feathersjs-ecosystem/feathers-sync/pull/146) ([fbarzin](https://github.com/fbarzin)) | ||
- Update redis to the latest version 🚀 [\#144](https://github.com/feathersjs-ecosystem/feathers-sync/pull/144) ([greenkeeper[bot]](https://github.com/apps/greenkeeper)) | ||
- Update mocha to the latest version 🚀 [\#142](https://github.com/feathersjs-ecosystem/feathers-sync/pull/142) ([greenkeeper[bot]](https://github.com/apps/greenkeeper)) | ||
- Fix flaky Travis CI test [\#139](https://github.com/feathersjs-ecosystem/feathers-sync/pull/139) ([daffl](https://github.com/daffl)) | ||
- Updated README for custom adapters. [\#138](https://github.com/feathersjs-ecosystem/feathers-sync/pull/138) ([deskoh](https://github.com/deskoh)) | ||
## [v2.0.0](https://github.com/feathersjs-ecosystem/feathers-sync/tree/v2.0.0) (2019-11-15) | ||
@@ -4,0 +15,0 @@ [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-sync/compare/v1.2.0...v2.0.0) |
@@ -7,4 +7,3 @@ const amqplib = require('amqplib'); | ||
const open = amqplib.connect(config.uri, config.amqpConnectionOptions); | ||
const { key = 'feathers-sync' } = config; | ||
const { deserialize, serialize } = config; | ||
const { deserialize, serialize, key } = config; | ||
@@ -11,0 +10,0 @@ debug(`Setting up AMQP connection ${config.uri}`); |
@@ -7,14 +7,19 @@ const redis = require('redis'); | ||
return app => { | ||
const key = config.key || 'feathers-sync'; | ||
const { key, serialize, deserialize } = config; | ||
const db = config.uri || config.db; | ||
const { redisClient } = config; | ||
// NOTE: message_buffer (redis) and messageBuffer (ioredis) return buffers | ||
const subscriberEvent = config.subscriberEvent || 'message'; | ||
if (!redisClient && typeof db !== "undefined") | ||
if (!redisClient && typeof db !== 'undefined') { | ||
debug(`Setting up Redis client for db: ${db}`); | ||
} | ||
const [pub, sub] = redisClient | ||
? [redisClient, redisClient.duplicate()] | ||
: [ | ||
redis.createClient(db, config.redisOptions), | ||
redis.createClient(db, config.redisOptions) | ||
]; | ||
const pub = redisClient || redis.createClient(db, config.redisOptions); | ||
const sub = redisClient || redis.createClient(db, config.redisOptions); | ||
const { deserialize, serialize } = config; | ||
app.configure(core); | ||
@@ -39,3 +44,3 @@ app.sync = { | ||
sub.subscribe(key); | ||
sub.on('message', function (e, data) { | ||
sub.on(subscriberEvent, function (e, data) { | ||
if (e.toString() === key) { | ||
@@ -42,0 +47,0 @@ debug(`Got ${key} message from Redis`); |
@@ -19,5 +19,5 @@ const debug = require('debug')('feathers-sync'); | ||
const service = app.service(path); | ||
const hook = context ? Object.assign({ | ||
app, service | ||
}, context) : context; | ||
const hook = context | ||
? Object.assign({ app, service }, context) | ||
: context; | ||
@@ -33,5 +33,5 @@ if (service) { | ||
app.mixins.push((service, path) => { | ||
service._emit = service.emit; | ||
service.mixin({ | ||
emit (event, data, ctx) { | ||
if (typeof service._emit !== 'function') { | ||
service._emit = service.emit; | ||
service.emit = function (event, data, ctx) { | ||
const disabled = ctx && ctx[SYNC] === false; | ||
@@ -45,3 +45,4 @@ | ||
const context = hooks.isHookObject(ctx) | ||
? _.omit(ctx, 'app', 'service') : ctx; | ||
? _.omit(ctx, 'app', 'service') | ||
: ctx; | ||
@@ -53,4 +54,4 @@ debug(`Sending sync-out event '${path} ${event}'`); | ||
})); | ||
} | ||
}); | ||
}; | ||
} | ||
}); | ||
@@ -57,0 +58,0 @@ }; |
@@ -5,4 +5,6 @@ const { URL } = require('url'); | ||
const amqp = require('./adapters/amqp'); | ||
const nats = require('./adapters/nats'); | ||
const adaptors = { | ||
core, | ||
nats, | ||
redis, | ||
@@ -14,4 +16,3 @@ amqp, | ||
const { SYNC } = core; | ||
module.exports = options => { | ||
const init = options => { | ||
const { uri, deserialize, serialize } = options; | ||
@@ -43,2 +44,3 @@ | ||
deserialize: JSON.parse, | ||
key: 'feathers-sync', | ||
...options | ||
@@ -48,2 +50,7 @@ }); | ||
Object.assign(module.exports, adaptors, { SYNC }); | ||
module.exports = init; | ||
Object.assign(module.exports, adaptors, { | ||
default: init, | ||
SYNC | ||
}); |
{ | ||
"name": "feathers-sync", | ||
"description": "Feathers", | ||
"version": "2.1.0", | ||
"version": "2.2.0", | ||
"repository": { | ||
@@ -27,3 +27,3 @@ "type": "git", | ||
"publish": "git push origin --tags && npm run changelog && git push origin", | ||
"changelog": "github_changelog_generator --no-issues && git add CHANGELOG.md && git commit -am \"Updating changelog\"", | ||
"changelog": "github_changelog_generator --user feathersjs-ecosystem --project feathers-sync && git add CHANGELOG.md && git commit -am \"Updating changelog\"", | ||
"release:patch": "npm version patch && npm publish", | ||
@@ -33,5 +33,6 @@ "release:minor": "npm version minor && npm publish", | ||
"lint": "semistandard --fix", | ||
"dtslint": "dtslint types", | ||
"mocha": "mocha --recursive test/", | ||
"test": "npm run lint && npm run coverage", | ||
"coverage": "istanbul cover npm run mocha" | ||
"test": "npm run lint && npm run dtslint && npm run coverage", | ||
"coverage": "nyc npm run mocha" | ||
}, | ||
@@ -47,13 +48,21 @@ "semistandard": { | ||
"dependencies": { | ||
"amqplib": "^0.5.5", | ||
"debug": "^4.1.1", | ||
"lodash": "^4.17.15", | ||
"amqplib": "^0.6.0", | ||
"debug": "^4.3.1", | ||
"lodash": "^4.17.20", | ||
"nats": "^1.4.12", | ||
"redis": "^3.0.2" | ||
}, | ||
"devDependencies": { | ||
"@feathersjs/feathers": "^4.5.2", | ||
"bson": "^4.0.3", | ||
"istanbul": "^1.1.0-alpha.1", | ||
"mocha": "^7.1.0", | ||
"semistandard": "^14.2.0" | ||
"@feathersjs/feathers": "^4.5.11", | ||
"@semantic-release/commit-analyzer": "^8.0.1", | ||
"@semantic-release/npm": "^7.0.10", | ||
"@semantic-release/release-notes-generator": "^9.0.1", | ||
"@types/node": "^14.14.22", | ||
"bson": "^4.2.2", | ||
"dtslint": "^4.0.6", | ||
"mocha": "^8.2.1", | ||
"nyc": "^15.1.0", | ||
"semantic-release": "^17.3.7", | ||
"semistandard": "^16.0.0", | ||
"typescript": "^4.1.3" | ||
}, | ||
@@ -63,3 +72,13 @@ "mocha": { | ||
"exit": true | ||
}, | ||
"release": { | ||
"branches": [ | ||
"release" | ||
], | ||
"plugins": [ | ||
"@semantic-release/commit-analyzer", | ||
"@semantic-release/release-notes-generator", | ||
"@semantic-release/npm" | ||
] | ||
} | ||
} |
# Feathers sync | ||
[![Greenkeeper badge](https://badges.greenkeeper.io/feathersjs-ecosystem/feathers-sync.svg)](https://greenkeeper.io/) | ||
[![Build Status](https://travis-ci.org/feathersjs-ecosystem/feathers-sync.png?branch=master)](https://travis-ci.org/feathersjs-ecosystem/feathers-sync) | ||
[![CI](https://github.com/feathersjs-ecosystem/feathers-sync/workflows/CI/badge.svg)](https://github.com/feathersjs-ecosystem/feathers-sync/actions?query=workflow%3ACI) | ||
[![Dependency Status](https://img.shields.io/david/feathersjs-ecosystem/feathers-sync.svg?style=flat-square)](https://david-dm.org/feathersjs-ecosystem/feathers-sync) | ||
[![Download Status](https://img.shields.io/npm/dm/feathers-sync.svg?style=flat-square)](https://www.npmjs.com/package/feathers-sync) | ||
[![Slack Status](http://slack.feathersjs.com/badge.svg)](http://slack.feathersjs.com) | ||
> Synchronize service events between application instances | ||
<!-- TOC --> | ||
- [Feathers sync](#feathers-sync) | ||
- [About](#about) | ||
- [Usage](#usage) | ||
- [`app.sync`](#appsync) | ||
- [Disabling synchronization](#disabling-synchronization) | ||
- [Adapters](#adapters) | ||
- [Redis](#redis) | ||
- [AMQP](#amqp) | ||
- [NATS](#nats) | ||
- [How it works](#how-it-works) | ||
- [Caveat: Listening to service events](#caveat-listening-to-service-events) | ||
- [Custom Serializer / Deserializer](#custom-serializer--deserializer) | ||
- [Writing custom adapters](#writing-custom-adapters) | ||
- [License](#license) | ||
<!-- /TOC --> | ||
## About | ||
When running multiple instances of your Feathers application (e.g. on several Heroku Dynos), service events (`created`, `updated`, `patched`, `removed`) do not get propagated to other instances. | ||
When running multiple instances of your Feathers application (e.g. on several Heroku Dynos), service events (`created`, `updated`, `patched`, `removed` and any custom defined events) do not get propagated to other instances. | ||
@@ -91,3 +107,3 @@ feathers-sync uses a messaging mechanism to propagate all events to all application instances. It currently supports: | ||
app.configure(sync.redis({ | ||
redisClient: redisClient | ||
redisClient: redisClient | ||
})) | ||
@@ -103,2 +119,3 @@ ``` | ||
- `redisOptions` - Redis [client options](http://redis.js.org/#api-rediscreateclient) | ||
- `subscriberEvent` - The event to listen for. Defaults to `message`. Could be `message_buffer` or `messageBuffer` depending on what Redis library is being used. | ||
@@ -111,2 +128,8 @@ ### AMQP | ||
### NATS | ||
- `uri` - The connection string (must start with `nats://`) | ||
- `key` (default: `feathers-sync`) - The name exchange where sync messages will be published | ||
## How it works | ||
@@ -116,15 +139,11 @@ | ||
## Caveats | ||
## Caveat: Listening to service events | ||
When listening to service events with `feathers-sync`, all events are going to get propagated to all clients. This means, that your event listeners should not perform any actions that change the global state (e.g. write something into the database) because every server instance will perform the same action. | ||
With `feathers-sync` enabled all events are going to get propagated to every application instance. This means, that any event listeners registered _on the server_ should not perform any actions that change the global state (e.g. write something into the database or call to an external API) because it will end up running multiple times (once on each instance). Instead, event listeners should only be used to update the local state (e.g. a local cache) and send real-time updates to all its clients. | ||
Instead, event listeners should only be used to update the local state (e.g. a local cache) and send real-time updates to all its clients. | ||
If you need to perform actions, for example setting up a first blog post after a new user has been created, add it to the service method itself or use a [Feathers hook](https://docs.feathersjs.com/api/hooks.html) (both of which will only run once on the instance that is handling the request). | ||
If you need to perform actions, for example setting up a first blog post after a new user has been created, add it to the service method itself (which will only run on its own instance) or use a [Feathers after hook](https://docs.feathersjs.com/api/hooks.html). | ||
Event data are serialized and deserialized using `JSON.stringify` and `JSON.parse`. This could pose a problem if the event data contains circular reference or has `Date` values (`Date` is not a valid JSON value ([source](https://www.w3schools.com/js/js_json_datatypes.asp)) and will be serialized to a string). | ||
## Custom Serializer / Deserializer | ||
To provide a custom serializer / deserializer: | ||
Event data are serialized and deserialized using `JSON.stringify` and `JSON.parse`. This could pose a problem if the event data contains circular reference or has `Date` values (`Date` is not a valid JSON value ([source](https://www.w3schools.com/js/js_json_datatypes.asp)) and will be serialized to a string). You can provide a custom serializer/deserializer like this: | ||
@@ -144,3 +163,3 @@ ```js | ||
> `Redis` and `AMQP` can support binary serialization / deserialization (i.e. `Buffer` data). | ||
> `Redis` and `AMQP` can support binary serialization / deserialization (i.e. `Buffer` data). `NATS` currently does not support custom serialization / deserialization/ | ||
@@ -197,4 +216,4 @@ ## Writing custom adapters | ||
Copyright (c) 2019 Feathers contributors | ||
Copyright (c) 2021 Feathers contributors | ||
Licensed under the [MIT license](LICENSE). |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
141056
15
240
214
5
12
+ Addednats@^1.4.12
+ Addedamqplib@0.6.0(transitive)
+ Addednats@1.4.12(transitive)
+ Addednuid@1.1.6(transitive)
+ Addedts-nkeys@1.0.16(transitive)
+ Addedtweetnacl@1.0.3(transitive)
- Removedamqplib@0.5.6(transitive)
Updatedamqplib@^0.6.0
Updateddebug@^4.3.1
Updatedlodash@^4.17.20