hazelcast-client
Version:
Hazelcast - open source In-Memory Data Grid - client for NodeJS
263 lines • 11.5 kB
JavaScript
"use strict";
/*
* Copyright (c) 2008-2018, Hazelcast, Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var Promise = require("bluebird");
var ClientAddMembershipListenerCodec_1 = require("../codec/ClientAddMembershipListenerCodec");
var LoggingService_1 = require("../logging/LoggingService");
var events_1 = require("events");
var ClientInfo_1 = require("../ClientInfo");
var HazelcastError_1 = require("../HazelcastError");
var assert = require("assert");
var Util_1 = require("../Util");
var MEMBER_ADDED = 1;
var MEMBER_REMOVED = 2;
var EMIT_MEMBER_ADDED = 'memberAdded';
var EMIT_MEMBER_REMOVED = 'memberRemoved';
var EMIT_ATTRIBUTE_CHANGE = 'memberAttributeChange';
var ATTRIBUTE_CHANGE = {
1: 'put',
2: 'remove',
};
/**
* Manages the relationship of this client with the cluster.
*/
var ClusterService = /** @class */ (function (_super) {
__extends(ClusterService, _super);
function ClusterService(client) {
var _this = _super.call(this) || this;
/**
* The unique identifier of the owner server node. This node is responsible for resource cleanup
*/
_this.ownerUuid = null;
/**
* The unique identifier of this client instance. Assigned by owner node on authentication
*/
_this.uuid = null;
_this.knownAddresses = [];
_this.members = [];
_this.logger = LoggingService_1.LoggingService.getLoggingService();
_this.client = client;
_this.members = [];
return _this;
}
/**
* Starts cluster service.
* @returns
*/
ClusterService.prototype.start = function () {
this.initHeartbeatListener();
this.initConnectionListener();
return this.connectToCluster();
};
/**
* Connects to cluster. It uses the addresses provided in the configuration.
* @returns
*/
ClusterService.prototype.connectToCluster = function () {
var _this = this;
return this.getPossibleMemberAddresses().then(function (res) {
_this.knownAddresses = [];
res.forEach(function (value) {
_this.knownAddresses.push(Util_1.createAddressFromString(value));
});
var attemptLimit = _this.client.getConfig().networkConfig.connectionAttemptLimit;
var attemptPeriod = _this.client.getConfig().networkConfig.connectionAttemptPeriod;
return _this.tryConnectingToAddresses(0, attemptLimit, attemptPeriod);
});
};
ClusterService.prototype.getPossibleMemberAddresses = function () {
var addresses = new Set();
this.getMembers().forEach(function (member) {
addresses.add(member.address.toString());
});
var providerAddresses = new Set();
var promises = [];
this.client.getConnectionManager().addressProviders.forEach(function (addressProvider) {
var _this = this;
promises.push(addressProvider.loadAddresses().then(function (res) {
providerAddresses = new Set(Array.from(providerAddresses).concat(res));
}).catch(function (err) {
_this.logger.warning('Error from AddressProvider: ' + addressProvider, err);
}));
});
return Promise.all(promises).then(function () {
return Array.from(new Set(Array.from(addresses).concat(Array.from(providerAddresses))));
});
};
/**
* Returns the list of members in the cluster.
* @returns
*/
ClusterService.prototype.getMembers = function (selector) {
if (selector === undefined) {
return this.members;
}
else {
var members_1 = [];
this.members.forEach(function (member) {
if (selector.select(member)) {
members_1.push(member);
}
});
return members_1;
}
};
/**
* Returns the number of nodes in cluster.
* @returns {number}
*/
ClusterService.prototype.getSize = function () {
return this.members.length;
};
/**
* Returns information about this client.
* @returns {ClientInfo}
*/
ClusterService.prototype.getClientInfo = function () {
var info = new ClientInfo_1.ClientInfo();
info.uuid = this.uuid;
info.localAddress = this.getOwnerConnection().getLocalAddress();
return info;
};
/**
* Returns the connection associated with owner node of this client.
* @returns {ClientConnection}
*/
ClusterService.prototype.getOwnerConnection = function () {
return this.ownerConnection;
};
ClusterService.prototype.initMemberShipListener = function () {
var _this = this;
var request = ClientAddMembershipListenerCodec_1.ClientAddMembershipListenerCodec.encodeRequest(false);
var handler = function (m) {
var handleMember = _this.handleMember.bind(_this);
var handleMemberList = _this.handleMemberList.bind(_this);
var handleAttributeChange = _this.handleMemberAttributeChange.bind(_this);
ClientAddMembershipListenerCodec_1.ClientAddMembershipListenerCodec.handle(m, handleMember, handleMemberList, handleAttributeChange, null);
};
return this.client.getInvocationService().invokeOnConnection(this.getOwnerConnection(), request, handler)
.then(function (resp) {
_this.logger.trace('ClusterService', 'Registered listener with id '
+ ClientAddMembershipListenerCodec_1.ClientAddMembershipListenerCodec.decodeResponse(resp).response);
});
};
ClusterService.prototype.initHeartbeatListener = function () {
this.client.getHeartbeat().addListener({
onHeartbeatStopped: this.onHeartbeatStopped.bind(this),
});
};
ClusterService.prototype.initConnectionListener = function () {
this.client.getConnectionManager().on('connectionClosed', this.onConnectionClosed.bind(this));
};
ClusterService.prototype.onConnectionClosed = function (connection) {
this.logger.warn('ClusterService', 'Connection closed to ' + connection.toString());
if (connection.isAuthenticatedAsOwner()) {
this.ownerConnection = null;
this.connectToCluster().catch(this.client.shutdown.bind(this.client));
}
};
ClusterService.prototype.onHeartbeatStopped = function (connection) {
this.logger.warn('ClusterService', connection.toString() + ' stopped heartbeating.');
if (connection.isAuthenticatedAsOwner()) {
this.client.getConnectionManager().destroyConnection(connection.getAddress());
}
};
ClusterService.prototype.tryConnectingToAddresses = function (index, remainingAttemptLimit, attemptPeriod, cause) {
var _this = this;
this.logger.debug('ClusterService', 'Trying to connect to addresses, remaining attempt limit: ' + remainingAttemptLimit
+ 'attempt period: ' + attemptPeriod);
if (this.knownAddresses.length <= index) {
remainingAttemptLimit = remainingAttemptLimit - 1;
if (remainingAttemptLimit === 0) {
var errorMessage = 'Unable to connect to any of the following addresses: ' +
this.knownAddresses.map(function (element) {
return element.toString();
}).join(', ');
this.logger.debug('ClusterService', errorMessage);
var error = new HazelcastError_1.IllegalStateError(errorMessage, cause);
return Promise.reject(error);
}
else {
var deferred_1 = Promise.defer();
setTimeout(function () {
_this.tryConnectingToAddresses(0, remainingAttemptLimit, attemptPeriod).then(function () {
deferred_1.resolve();
}).catch(function (e) {
deferred_1.reject(e);
});
}, attemptPeriod);
return deferred_1.promise;
}
}
else {
var currentAddress = this.knownAddresses[index];
return this.client.getConnectionManager().getOrConnect(currentAddress, true).then(function (connection) {
connection.setAuthenticatedAsOwner(true);
_this.ownerConnection = connection;
return _this.initMemberShipListener();
}).catch(function (e) {
_this.logger.warn('ClusterService', e);
return _this.tryConnectingToAddresses(index + 1, remainingAttemptLimit, attemptPeriod, e);
});
}
};
ClusterService.prototype.handleMember = function (member, eventType) {
if (eventType === MEMBER_ADDED) {
this.logger.info('ClusterService', member.toString() + ' added to cluster');
this.memberAdded(member);
}
else if (eventType === MEMBER_REMOVED) {
this.logger.info('ClusterService', member.toString() + ' removed from cluster');
this.memberRemoved(member);
}
this.client.getPartitionService().refresh();
};
ClusterService.prototype.handleMemberList = function (members) {
this.members = members;
this.client.getPartitionService().refresh();
this.logger.info('ClusterService', 'Members received.', this.members);
};
ClusterService.prototype.handleMemberAttributeChange = function (uuid, key, operationType, value) {
this.emit(EMIT_ATTRIBUTE_CHANGE, uuid, key, ATTRIBUTE_CHANGE[operationType], value);
};
ClusterService.prototype.memberAdded = function (member) {
this.members.push(member);
this.emit(EMIT_MEMBER_ADDED, member);
};
ClusterService.prototype.memberRemoved = function (member) {
var memberIndex = this.members.findIndex(member.equals, member);
if (memberIndex !== -1) {
var removedMemberList = this.members.splice(memberIndex, 1);
assert(removedMemberList.length === 1);
}
this.client.getConnectionManager().destroyConnection(member.address);
this.emit(EMIT_MEMBER_REMOVED, member);
};
return ClusterService;
}(events_1.EventEmitter));
exports.ClusterService = ClusterService;
//# sourceMappingURL=ClusterService.js.map