The Hot Rod Node.js client is an asynchronous event-driven client allowing Node.js users to communicate to JBoss Data Grid servers. This client supports many of the features in the Java client, including the ability to execute and store scripts, utilize cache listeners, and receive the full cluster topology.
The asynchronous operation results are represented with Promise instances, allowing the client to easily chain multiple invocations together and centralizing error handling.
The Hot Rod Node.js client is included in a separate distribution, and must be downloaded independently of JBoss Data Grid. Follow the below instructions to install this client:
Procedure 11.3. Installing the Hot Rod Node.js Client
Download the jboss-datagrid-<version>-nodejs-client.zip from the Red Hat Customer Portal.
Extract the downloaded archive.
Use npm to install the provided tarball, as seen in the following command:
The following example shows how to connect to a JBoss Data Grid server and perform basic operations, such as putting and retrieving data. The following example assumes that a JBoss Data Grid server is available at the default location of localhost:11222:
var infinispan = require('infinispan');
// Obtain a connection to the JBoss Data Grid server
// As no cache is specified all operations will occur on the 'default' cache
var connected = infinispan.client({port: 11222, host: '127.0.0.1'});
connected.then(function (client) {
// Attempt to put a value in the cache.
var clientPut = client.put('key', 'value');
// Retrieve the value just placed
var clientGet = clientPut.then(
function() { return client.get('key'); });
// Print out the value that was retrieved
var showGet = clientGet.then(
function(value) { console.log('get(key)=' + value); });
// Disconnect from the server
return showGet.finally(
function() { return client.disconnect(); });
}).catch(function(error) {
// Log any errors received
console.log("Got error: " + error.message);
});
var infinispan = require('infinispan');
// Obtain a connection to the JBoss Data Grid server
// As no cache is specified all operations will occur on the 'default' cache
var connected = infinispan.client({port: 11222, host: '127.0.0.1'});
connected.then(function (client) {
// Attempt to put a value in the cache.
var clientPut = client.put('key', 'value');
// Retrieve the value just placed
var clientGet = clientPut.then(
function() { return client.get('key'); });
// Print out the value that was retrieved
var showGet = clientGet.then(
function(value) { console.log('get(key)=' + value); });
// Disconnect from the server
return showGet.finally(
function() { return client.disconnect(); });
}).catch(function(error) {
// Log any errors received
console.log("Got error: " + error.message);
});
Copy to ClipboardCopied!Toggle word wrapToggle overflow
Connecting to a Named Cache
To connect to a specific cache the cacheName attribute may be defined when specifying the location of the JBoss Data Grid server instance, as seen in the following example:
var infinispan = require('infinispan');
// Obtain a connection to the JBoss Data Grid server
// and connect to namedCache
var connected = infinispan.client(
{port: 11222, host: '127.0.0.1'}, {cacheName: 'namedCache'});
connected.then(function (client) {
// Log the result of the connection
console.log('Connected to `namedCache`');
// Disconnect from the server
return client.disconnect();
}).catch(function(error) {
// Log any errors received
console.log("Got error: " + error.message);
});
var infinispan = require('infinispan');
// Obtain a connection to the JBoss Data Grid server
// and connect to namedCache
var connected = infinispan.client(
{port: 11222, host: '127.0.0.1'}, {cacheName: 'namedCache'});
connected.then(function (client) {
// Log the result of the connection
console.log('Connected to `namedCache`');
// Disconnect from the server
return client.disconnect();
}).catch(function(error) {
// Log any errors received
console.log("Got error: " + error.message);
});
Copy to ClipboardCopied!Toggle word wrapToggle overflow
Using Data Sets
In addition to placing single entries the putAll and getAll methods may be used to place or retrieve a set of data. The following example walks through these operations:
var infinispan = require('infinispan');
// Obtain a connection to the JBoss Data Grid server
// As no cache is specified all operations will occur on the 'default' cache
var connected = infinispan.client({port: 11222, host: '127.0.0.1'});
connected.then(function (client) {
var data = [
{key: 'multi1', value: 'v1'},
{key: 'multi2', value: 'v2'},
{key: 'multi3', value: 'v3'}];
// Place all of the key/value pairs in the cache
var clientPutAll = client.putAll(data);
// Obtain the values for two of the keys
var clientGetAll = clientPutAll.then(
function() { return client.getAll(['multi2', 'multi3']); });
// Print out the values obtained.
var showGetAll = clientGetAll.then(
function(entries) {
console.log('getAll(multi2, multi3)=%s', JSON.stringify(entries));
}
);
// Obtain an iterator for the cache
var clientIterator = showGetAll.then(
function() { return client.iterator(1); });
// Iterate over the entries in the cache, printing the values
var showIterated = clientIterator.then(
function(it) {
function loop(promise, fn) {
// Simple recursive loop over iterator's next() call
return promise.then(fn).then(function (entry) {
return !entry.done ? loop(it.next(), fn) : entry.value;
});
}
return loop(it.next(), function (entry) {
console.log('iterator.next()=' + JSON.stringify(entry));
return entry;
});
}
);
// Clear the cache of all values
var clientClear = showIterated.then(
function() { return client.clear(); });
// Disconnect from the server
return clientClear.finally(
function() { return client.disconnect(); });
}).catch(function(error) {
// Log any errors received
console.log("Got error: " + error.message);
});
var infinispan = require('infinispan');
// Obtain a connection to the JBoss Data Grid server
// As no cache is specified all operations will occur on the 'default' cache
var connected = infinispan.client({port: 11222, host: '127.0.0.1'});
connected.then(function (client) {
var data = [
{key: 'multi1', value: 'v1'},
{key: 'multi2', value: 'v2'},
{key: 'multi3', value: 'v3'}];
// Place all of the key/value pairs in the cache
var clientPutAll = client.putAll(data);
// Obtain the values for two of the keys
var clientGetAll = clientPutAll.then(
function() { return client.getAll(['multi2', 'multi3']); });
// Print out the values obtained.
var showGetAll = clientGetAll.then(
function(entries) {
console.log('getAll(multi2, multi3)=%s', JSON.stringify(entries));
}
);
// Obtain an iterator for the cache
var clientIterator = showGetAll.then(
function() { return client.iterator(1); });
// Iterate over the entries in the cache, printing the values
var showIterated = clientIterator.then(
function(it) {
function loop(promise, fn) {
// Simple recursive loop over iterator's next() call
return promise.then(fn).then(function (entry) {
return !entry.done ? loop(it.next(), fn) : entry.value;
});
}
return loop(it.next(), function (entry) {
console.log('iterator.next()=' + JSON.stringify(entry));
return entry;
});
}
);
// Clear the cache of all values
var clientClear = showIterated.then(
function() { return client.clear(); });
// Disconnect from the server
return clientClear.finally(
function() { return client.disconnect(); });
}).catch(function(error) {
// Log any errors received
console.log("Got error: " + error.message);
});
Copy to ClipboardCopied!Toggle word wrapToggle overflow
The Hot Rod protocol stores metadata in addition to each value associated with the keys. The getWithMetadata will retrieve the value and any associated metadata with the key.
The following example demonstrates utilizing this metadata:
var infinispan = require('infinispan');
// Obtain a connection to the JBoss Data Grid server
// As no cache is specified all operations will occur on the 'default' cache
var connected = infinispan.client({port: 11222, host: '127.0.0.1'});
connected.then(function (client) {
// Attempt to put a value in the cache if it does not exist
var clientPut = client.putIfAbsent('cond', 'v0');
// Print out the result of the put operation
var showPut = clientPut.then(
function(success) { console.log(':putIfAbsent(cond)=' + success); });
// Replace the value in the cache
var clientReplace = showPut.then(
function() { return client.replace('cond', 'v1'); } );
// Print out the result of the replace
var showReplace = clientReplace.then(
function(success) { console.log('replace(cond)=' + success); });
// Obtain the value and metadata
var clientGetMetaForReplace = showReplace.then(
function() { return client.getWithMetadata('cond'); });
// Replace the value only if the version matches
var clientReplaceWithVersion = clientGetMetaForReplace.then(
function(entry) {
console.log('getWithMetadata(cond)=' + JSON.stringify(entry));
return client.replaceWithVersion('cond', 'v2', entry.version);
}
);
// Print out the result of the previous replace
var showReplaceWithVersion = clientReplaceWithVersion.then(
function(success) { console.log('replaceWithVersion(cond)=' + success); });
// Obtain the value and metadata
var clientGetMetaForRemove = showReplaceWithVersion.then(
function() { return client.getWithMetadata('cond'); });
// Remove the value only if the version matches
var clientRemoveWithVersion = clientGetMetaForRemove.then(
function(entry) {
console.log('getWithMetadata(cond)=' + JSON.stringify(entry));
return client.removeWithVersion('cond', entry.version);
}
);
// Print out the result of the previous remove
var showRemoveWithVersion = clientRemoveWithVersion.then(
function(success) { console.log('removeWithVersion(cond)=' + success)});
// Disconnect from the server
return showRemoveWithVersion.finally(
function() { return client.disconnect(); });
}).catch(function(error) {
// Log any errors received
console.log("Got error: " + error.message);
});
var infinispan = require('infinispan');
// Obtain a connection to the JBoss Data Grid server
// As no cache is specified all operations will occur on the 'default' cache
var connected = infinispan.client({port: 11222, host: '127.0.0.1'});
connected.then(function (client) {
// Attempt to put a value in the cache if it does not exist
var clientPut = client.putIfAbsent('cond', 'v0');
// Print out the result of the put operation
var showPut = clientPut.then(
function(success) { console.log(':putIfAbsent(cond)=' + success); });
// Replace the value in the cache
var clientReplace = showPut.then(
function() { return client.replace('cond', 'v1'); } );
// Print out the result of the replace
var showReplace = clientReplace.then(
function(success) { console.log('replace(cond)=' + success); });
// Obtain the value and metadata
var clientGetMetaForReplace = showReplace.then(
function() { return client.getWithMetadata('cond'); });
// Replace the value only if the version matches
var clientReplaceWithVersion = clientGetMetaForReplace.then(
function(entry) {
console.log('getWithMetadata(cond)=' + JSON.stringify(entry));
return client.replaceWithVersion('cond', 'v2', entry.version);
}
);
// Print out the result of the previous replace
var showReplaceWithVersion = clientReplaceWithVersion.then(
function(success) { console.log('replaceWithVersion(cond)=' + success); });
// Obtain the value and metadata
var clientGetMetaForRemove = showReplaceWithVersion.then(
function() { return client.getWithMetadata('cond'); });
// Remove the value only if the version matches
var clientRemoveWithVersion = clientGetMetaForRemove.then(
function(entry) {
console.log('getWithMetadata(cond)=' + JSON.stringify(entry));
return client.removeWithVersion('cond', entry.version);
}
);
// Print out the result of the previous remove
var showRemoveWithVersion = clientRemoveWithVersion.then(
function(success) { console.log('removeWithVersion(cond)=' + success)});
// Disconnect from the server
return showRemoveWithVersion.finally(
function() { return client.disconnect(); });
}).catch(function(error) {
// Log any errors received
console.log("Got error: " + error.message);
});
Copy to ClipboardCopied!Toggle word wrapToggle overflow
The client may specify multiple server addresses when a connection is defined. When multiple servers are defined it will loop through each one until a successful connection to a node is obtained. An example of this configuration is below:
var infinispan = require('infinispan');
// Accepts multiple addresses and fails over if connection not possible
var connected = infinispan.client(
[{port: 99999, host: '127.0.0.1'}, {port: 11222, host: '127.0.0.1'}]);
connected.then(function (client) {
// Obtain a list of all members in the cluster
var members = client.getTopologyInfo().getMembers();
// Print out the list of members
console.log('Connected to: ' + JSON.stringify(members));
// Disconnect from the server
return client.disconnect();
}).catch(function(error) {
// Log any errors received
console.log("Got error: " + error.message);
});
var infinispan = require('infinispan');
// Accepts multiple addresses and fails over if connection not possible
var connected = infinispan.client(
[{port: 99999, host: '127.0.0.1'}, {port: 11222, host: '127.0.0.1'}]);
connected.then(function (client) {
// Obtain a list of all members in the cluster
var members = client.getTopologyInfo().getMembers();
// Print out the list of members
console.log('Connected to: ' + JSON.stringify(members));
// Disconnect from the server
return client.disconnect();
}).catch(function(error) {
// Log any errors received
console.log("Got error: " + error.message);
});
Copy to ClipboardCopied!Toggle word wrapToggle overflow
The Hot Rod Node.js client supports remote cache listeners, and these may be added using the addListener method. This method takes the event type (create, modify, remove, or expiry) and the function callback as parameter. For more information on Remote Event Listeners refer to Section 8.5, “Remote Event Listeners (Hot Rod)”. An example of this is shown below:
var infinispan = require('infinispan');
var Promise = require('promise');
var connected = infinispan.client({port: 11222, host: '127.0.0.1'});
connected.then(function (client) {
var clientAddListenerCreate = client.addListener(
'create', function(key) { console.log('[Event] Created key: ' + key); });
var clientAddListeners = clientAddListenerCreate.then(
function(listenerId) {
// Multiple callbacks can be associated with a single client-side listener.
// This is achieved by registering listeners with the same listener id
// as shown in the example below.
var clientAddListenerModify = client.addListener(
'modify', function(key) { console.log('[Event] Modified key: ' + key); },
{listenerId: listenerId});
var clientAddListenerRemove = client.addListener(
'remove', function(key) { console.log('[Event] Removed key: ' + key); },
{listenerId: listenerId});
return Promise.all([clientAddListenerModify, clientAddListenerRemove]);
});
var clientCreate = clientAddListeners.then(
function() { return client.putIfAbsent('eventful', 'v0'); });
var clientModify = clientCreate.then(
function() { return client.replace('eventful', 'v1'); });
var clientRemove = clientModify.then(
function() { return client.remove('eventful'); });
var clientRemoveListener =
Promise.all([clientAddListenerCreate, clientRemove]).then(
function(values) {
var listenerId = values[0];
return client.removeListener(listenerId);
});
return clientRemoveListener.finally(
function() { return client.disconnect(); });
}).catch(function(error) {
console.log("Got error: " + error.message);
});
var infinispan = require('infinispan');
var Promise = require('promise');
var connected = infinispan.client({port: 11222, host: '127.0.0.1'});
connected.then(function (client) {
var clientAddListenerCreate = client.addListener(
'create', function(key) { console.log('[Event] Created key: ' + key); });
var clientAddListeners = clientAddListenerCreate.then(
function(listenerId) {
// Multiple callbacks can be associated with a single client-side listener.
// This is achieved by registering listeners with the same listener id
// as shown in the example below.
var clientAddListenerModify = client.addListener(
'modify', function(key) { console.log('[Event] Modified key: ' + key); },
{listenerId: listenerId});
var clientAddListenerRemove = client.addListener(
'remove', function(key) { console.log('[Event] Removed key: ' + key); },
{listenerId: listenerId});
return Promise.all([clientAddListenerModify, clientAddListenerRemove]);
});
var clientCreate = clientAddListeners.then(
function() { return client.putIfAbsent('eventful', 'v0'); });
var clientModify = clientCreate.then(
function() { return client.replace('eventful', 'v1'); });
var clientRemove = clientModify.then(
function() { return client.remove('eventful'); });
var clientRemoveListener =
Promise.all([clientAddListenerCreate, clientRemove]).then(
function(values) {
var listenerId = values[0];
return client.removeListener(listenerId);
});
return clientRemoveListener.finally(
function() { return client.disconnect(); });
}).catch(function(error) {
console.log("Got error: " + error.message);
});
Copy to ClipboardCopied!Toggle word wrapToggle overflow
JBoss Data Grid server instances may be clustered together to provide failover and capabilities for scaling up. While working with a cluster is very similar to using a single instance there are a few considerations:
The client only needs to know about a single server's address to receive information about the entire server cluster, regardless of the cluster size.
For distributed caches, key-based operations are routed in the cluster using the same consistent hash algorithms used by the server. This means that the client can locate where any particular key resides without the need for extra network hops.
For distributed caches, multi-key or key-less operations routed in round-robin fashion.
For replicated and invalidated caches, all operations are routed in round-robin fashion, regardless of whether they are key-based or multi-key/key-less.
All routing and failover is transparent to the client, so operations executed against a cluster look identical to the code examples performed above.
The cluster topology can be obtained using the following example:
var infinispan = require('infinispan');
var connected = infinispan.client({port: 11322, host: '127.0.0.1'});
connected.then(function (client) {
var members = client.getTopologyInfo().getMembers();
// Should show all expected cluster members
console.log('Connected to: ' + JSON.stringify(members));
// Add your own operations here...
return client.disconnect();
}).catch(function(error) {
// Log any errors received
console.log("Got error: " + error.message);
});
var infinispan = require('infinispan');
var connected = infinispan.client({port: 11322, host: '127.0.0.1'});
connected.then(function (client) {
var members = client.getTopologyInfo().getMembers();
// Should show all expected cluster members
console.log('Connected to: ' + JSON.stringify(members));
// Add your own operations here...
return client.disconnect();
}).catch(function(error) {
// Log any errors received
console.log("Got error: " + error.message);
});
Copy to ClipboardCopied!Toggle word wrapToggle overflow
We help Red Hat users innovate and achieve their goals with our products and services with content they can trust. Explore our recent updates.
Making open source more inclusive
Red Hat is committed to replacing problematic language in our code, documentation, and web properties. For more details, see the Red Hat Blog.
About Red Hat
We deliver hardened solutions that make it easier for enterprises to work across platforms and environments, from the core datacenter to the network edge.