node-eventstore-client/src/core/subscriptionsManager.js
Nicolas Dextraze 9be67bf7c7 Initial commit
2016-03-09 12:46:15 -08:00

171 lines
6.0 KiB
JavaScript

var util = require('util');
var uuid = require('uuid');
var Hash = require('../common/hash');
var SubscriptionDropReason = require('../subscriptionDropReason');
function SubscriptionsManager(connectionName, settings) {
//Ensure.NotNull(connectionName, "connectionName");
//Ensure.NotNull(settings, "settings");
this._connectionName = connectionName;
this._settings = settings;
this._activeSubscriptions = new Hash();
this._waitingSubscriptions = [];
this._retryPendingSubscriptions = [];
}
SubscriptionsManager.prototype.getActiveSubscription = function(correlationId) {
return this._activeSubscriptions.get(correlationId);
};
SubscriptionsManager.prototype.cleanUp = function() {
var connectionClosedError = new Error(util.format("Connection '%s' was closed.", this._connectionName));
var self = this;
this._activeSubscriptions.forEach(function(correlationId, subscription){
subscription.operation.dropSubscription(SubscriptionDropReason.ConnectionClosed, connectionClosedError);
});
this._waitingSubscriptions.forEach(function(subscription){
subscription.operation.dropSubscription(SubscriptionDropReason.ConnectionClosed, connectionClosedError);
});
this._retryPendingSubscriptions.forEach(function(subscription){
subscription.operation.dropSubscription(SubscriptionDropReason.ConnectionClosed, connectionClosedError);
});
this._activeSubscriptions.clear();
this._waitingSubscriptions = [];
this._retryPendingSubscriptions = [];
};
SubscriptionsManager.prototype.purgeSubscribedAndDroppedSubscriptions = function() {
var self = this;
var subscriptionsToRemove = [];
this._activeSubscriptions.forEach(function(_, subscription) {
if (subscription.isSubscribed && subscription.connectionId == connectionId) {
subscription.operation.connectionClosed();
subscriptionsToRemove.push(subscription);
}
});
subscriptionsToRemove.forEach(function(subscription) {
self._activeSubscriptions.remove(subscription.correlationId);
});
};
SubscriptionsManager.prototype.checkTimeoutsAndRetry = function(connection) {
//Ensure.NotNull(connection, "connection");
var self = this;
var retrySubscriptions = [];
var removeSubscriptions = [];
this._activeSubscriptions.forEach(function(_, subscription) {
if (subscription.isSubscribed) return;
if (subscription.connectionId != connection.connectionId)
{
retrySubscriptions.push(subscription);
}
else if (subscription.timeout > 0 && Date.now() - subscription.lastUpdated > self._settings.operationTimeout)
{
var err = util.format("EventStoreConnection '%s': subscription never got confirmation from server.\n" +
"UTC now: %s, operation: %s.",
self._connectionName, new Date(), subscription);
self._settings.log.error(err);
if (self._settings.failOnNoServerResponse)
{
subscription.operation.dropSubscription(SubscriptionDropReason.SubscribingError, new Error(err));
removeSubscriptions.push(subscription);
}
else
{
retrySubscriptions.push(subscription);
}
}
});
retrySubscriptions.forEach(function(subscription) {
self.scheduleSubscriptionRetry(subscription);
});
removeSubscriptions.forEach(function(subscription) {
self.removeSubscription(subscription);
});
if (this._retryPendingSubscriptions.length > 0)
{
this._retryPendingSubscriptions.forEach(function(subscription) {
subscription.retryCount += 1;
self.startSubscription(subscription, connection);
});
this._retryPendingSubscriptions = [];
}
while (this._waitingSubscriptions.length > 0)
{
this.startSubscription(this._waitingSubscriptions.shift(), connection);
}
};
SubscriptionsManager.prototype.removeSubscription = function(subscription) {
this._activeSubscriptions.remove(subscription.correlationId);
this._logDebug("RemoveSubscription %s.", subscription);
return true;
};
SubscriptionsManager.prototype.scheduleSubscriptionRetry = function(subscription) {
if (!this.removeSubscription(subscription))
{
this._logDebug("RemoveSubscription failed when trying to retry %s.", subscription);
return;
}
if (subscription.maxRetries >= 0 && subscription.retryCount >= subscription.maxRetries)
{
this._logDebug("RETRIES LIMIT REACHED when trying to retry %s.", subscription);
var err = util.format("Retries limit reached. Subscription: %s RetryCount: %d.", subscription, subscription.retryCount);
subscription.operation.dropSubscription(SubscriptionDropReason.SubscribingError, new Error(err));
return;
}
this._logDebug("retrying subscription %s.", subscription);
this._retryPendingSubscriptions.push(subscription);
};
SubscriptionsManager.prototype.enqueueSubscription = function(subscriptionItem) {
this._waitingSubscriptions.push(subscriptionItem);
};
SubscriptionsManager.prototype.startSubscription = function(subscription, connection) {
//Ensure.NotNull(connection, "connection");
if (subscription.isSubscribed)
{
this._logDebug("StartSubscription REMOVING due to already subscribed %s.", subscription);
this.removeSubscription(subscription);
return;
}
subscription.correlationId = uuid.v4();
subscription.connectionId = connection.connectionId;
subscription.lastUpdated = Date.now();
this._activeSubscriptions.add(subscription.correlationId, subscription);
if (!subscription.operation.subscribe(subscription.correlationId, connection))
{
this._logDebug("StartSubscription REMOVING AS COULDN'T SUBSCRIBE %s.", subscription);
this.removeSubscription(subscription);
}
else
{
this._logDebug("StartSubscription SUBSCRIBING %s.", subscription);
}
};
SubscriptionsManager.prototype._logDebug = function(message) {
if (!this._settings.verboseLogging) return;
var parameters = Array.prototype.slice.call(arguments, 1);
this._settings.log.debug("EventStoreConnection '%s': %s.", this._connectionName, parameters.length == 0 ? message : util.format(message, parameters));
};
module.exports = SubscriptionsManager;