Skip to content

Commit

Permalink
Merge pull request #36 from boschrexroth/bugfix/missing_subscription
Browse files Browse the repository at this point in the history
fix: improve diagnostics for misconfigured subscriptions. E.g. when a…
  • Loading branch information
Sebastian Krauskopf committed Mar 3, 2022
2 parents 1fca8a8 + be76a6d commit 97adcdb
Show file tree
Hide file tree
Showing 6 changed files with 2,915 additions and 2,757 deletions.
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -93,6 +93,7 @@ Any use of the source code and related documents of this repository in applicati
* 2021-10-22: 1.8.11 - fix: prevent "Failed login attempts" after flow gets redeployed with correct credentials (Bug392030).
* 2021-10-22: 1.8.12 - fix: make subscription to properly report error and reconnect when authorization token expires (Bug405282).
* 2022-01-27: 1.8.13 - refactor: update dependency versions. No functional change.
* 2022-03-02: 1.8.14 - fix: improve diagnostics for misconfigured subscriptions. E.g. when a single node of a subscription is missing (Bug449366).

## About

Expand Down
46 changes: 35 additions & 11 deletions ctrlx-config-subscription.js
Expand Up @@ -24,7 +24,7 @@
*
*/


const CtrlxProblemError = require('./lib/CtrlxProblemError');

module.exports = function(RED) {
'use strict';
Expand Down Expand Up @@ -110,6 +110,8 @@ module.exports = function(RED) {
} else {
node.subscription = subscription;



// This is the handler function which dispatches incoming update messages to the nodes.
node.subscription.on('update', (data, lastEventId) => {
Object.values(node.users).forEach((element) => {
Expand All @@ -119,23 +121,45 @@ module.exports = function(RED) {
});
});

// This is the handler which is called on error. E.g. on authorization errors


// This is the handler which is called on error. E.g. on authorization errors of the whole subscription
// or when a single node address has a problem.
node.subscription.on('error', (err) => {

// Distribute the error to all registered nodes.
Object.values(node.users).forEach((element) => {
element.callback(err);
});
let isSingleNodeError = false;

// To recover from the error state, let's reset the subscription.
node.dirty = true;
setTimeout(() => {
node.updateSubscription();
}, 2000);
// Check if we have an error, that is only attached to a single node and
// not to the whole subscription
if (err instanceof CtrlxProblemError && err._instance) {

// Distribute the error to actual node.
Object.values(node.users).forEach((element) => {
if (element.path === err._instance) {
element.callback(err);
isSingleNodeError = true;
}
});

}

if (!isSingleNodeError) {
// Distribute the error to all registered nodes.
Object.values(node.users).forEach((element) => {
element.callback(err);
});

// To recover from the error state, let's reset the subscription.
node.dirty = true;
setTimeout(() => {
node.updateSubscription();
}, 2000);
}

});



// This is the handler if the connection gets closed by the server.
node.subscription.on('end', () => {

Expand Down
11 changes: 9 additions & 2 deletions ctrlx-datalayer-subscribe.js
Expand Up @@ -24,6 +24,8 @@
*
*/

const CtrlxProblemError = require('./lib/CtrlxProblemError');


module.exports = function(RED) {
'use strict';
Expand Down Expand Up @@ -67,8 +69,13 @@
node.configSubscription.register(node, node.path, (err, data, lastEventId) => {

if (err) {
node.status({fill: 'red', shape: 'ring', text: 'subscription failed'});
node.error(err.message);
if (err.message) {
node.status({fill: 'red', shape: 'ring', text: `subscription failed: ${err.message}`});
node.error(err.message);
} else {
node.status({fill: 'red', shape: 'ring', text: `subscription failed`});
node.error('unknown error');
}
} else {
node.eventCounter++;
node.status({fill: 'green', shape: 'dot', text: `received data #${node.eventCounter}`});
Expand Down
27 changes: 23 additions & 4 deletions lib/CtrlxDatalayerSubscription.js
Expand Up @@ -29,6 +29,7 @@
const EventSource = require('launchdarkly-eventsource').EventSource;
const EventEmitter = require("events").EventEmitter;
const CtrlxDatalayer = require('./CtrlxDatalayerV2');
const CtrlxProblemError = require('../lib/CtrlxProblemError');
const debug = require('debug')('ctrlxcore:datalayer:subscription');
const debugUpdate = require('debug')('ctrlxcore:datalayer:subscription:update');

Expand Down Expand Up @@ -193,12 +194,30 @@ class CtrlxDatalayerSubscription extends EventEmitter {
};

// @ts-ignore
this._es.onerror = (err) => {
debug(`onerror(${err.message})`);
this._es.onerror = (e) => {
debug(`onerror(${e.type})`);

if (e.data !== 'undefined') {

// The error is of type 'MessageEvent'. This means, that not the stream has an error, but
// an 'error' message is send over the stream (in contrast to an 'update' message if everything is fine).
// This could mean, that one of the subscribed nodes might have a problem.
// For a 'MessageEvent' of type 'error', we expect a 'Problem' object to be transferred in the 'data' element.
let err = CtrlxProblemError.fromHttpResponse(e.data.status, e.data);

if (this.listeners('error').length > 0) {
this.emit('error', err);
}

} else {

// The error is of type Event or Error. The subscription might be broken.
if (this.listeners('error').length > 0) {
this.emit('error', e);
}

if (this.listeners('error').length > 0) {
this.emit('error', err);
}

};

this._es.addEventListener('update', (e) => {
Expand Down

0 comments on commit 97adcdb

Please sign in to comment.