第 2 章 使用 Hot Rod JS 客户端
了解将 Hot Rod JS 客户端与 Data Grid 搭配使用的一些示例。
2.1. hot Rod JS 客户端示例
在安装和配置 Hot Rod JS 客户端后,请先尝试一些基本的缓存操作,然后再继续与数据网格进行更复杂的交互。
2.1.1. hello world
在 Data Grid Server 上创建一个名为 "myCache" 的缓存,然后添加并检索条目。
var infinispan = require('infinispan'); // Connect to Data Grid Server. // Use an existing cache named "myCache". var connected = infinispan.client( {port: 11222, host: '127.0.0.1'}, { cacheName: 'myCache', clientIntelligence: 'BASIC', authentication: { enabled: true, saslMechanism: 'DIGEST-MD5', userName: 'username', password: 'changeme' } } ); connected.then(function (client) { console.log('Connected to `myCache`'); // Add an entry to the cache. var clientPut = client.put('hello', 'world'); // Retrieve the entry you added. var clientGet = clientPut.then( function() { return client.get('hello'); }); // Print the value of the entry. var showGet = clientGet.then( function(value) { console.log('get(hello)=' + value); }); // Disconnect from Data Grid Server. return client.disconnect(); }).catch(function(error) { // Log any errors. console.log("Got error: " + error.message); });
2.1.2. 使用条目和检索缓存统计信息
添加、检索、删除单个条目和查看缓存统计信息。
var infinispan = require('infinispan'); var connected = infinispan.client( {port: 11222, host: '127.0.0.1'}, { cacheName: 'myCache', authentication: { enabled: true, saslMechanism: 'DIGEST-MD5', userName: 'username', password: 'changeme' } } ); connected.then(function (client) { var clientPut = client.put('key', 'value'); var clientGet = clientPut.then( function() { return client.get('key'); }); var showGet = clientGet.then( function(value) { console.log('get(key)=' + value); }); var clientRemove = showGet.then( function() { return client.remove('key'); }); var showRemove = clientRemove.then( function(success) { console.log('remove(key)=' + success); }); var clientStats = showRemove.then( function() { return client.stats(); }); var showStats = clientStats.then( function(stats) { console.log('Number of stores: ' + stats.stores); console.log('Number of cache hits: ' + stats.hits); console.log('All statistics: ' + JSON.stringify(stats, null, " ")); }); return showStats.finally( function() { return client.disconnect(); }); }).catch(function(error) { console.log("Got error: " + error.message); });
2.1.3. 使用多个缓存条目
使用简单递归循环创建多个缓存条目。
var infinispan = require('infinispan'); var connected = infinispan.client( {port: 11222, host: '127.0.0.1'}, { cacheName: 'myCache', authentication: { enabled: true, saslMechanism: 'DIGEST-MD5', userName: 'username', password: 'changeme' } } ); connected.then(function (client) { var data = [ {key: 'multi1', value: 'v1'}, {key: 'multi2', value: 'v2'}, {key: 'multi3', value: 'v3'}]; var clientPutAll = client.putAll(data); var clientGetAll = clientPutAll.then( function() { return client.getAll(['multi2', 'multi3']); }); var showGetAll = clientGetAll.then( function(entries) { console.log('getAll(multi2, multi3)=%s', JSON.stringify(entries)); } ); var clientIterator = showGetAll.then( function() { return client.iterator(1); }); var showIterated = clientIterator.then( function(it) { function loop(promise, fn) { // Simple recursive loop over the iterator's next() call. return promise.then(fn).then(function (entry) { return entry.done ? it.close().then(function () { return entry.value; }) : loop(it.next(), fn); }); } return loop(it.next(), function (entry) { console.log('iterator.next()=' + JSON.stringify(entry)); return entry; }); } ); var clientClear = showIterated.then( function() { return client.clear(); }); return clientClear.finally( function() { return client.disconnect(); }); }).catch(function(error) { console.log("Got error: " + error.message); });
2.1.4. 使用 Async 和 Await 结构
Node.js 提供 async
和 await
结构,可简化缓存操作。
单个缓存条目
const infinispan = require("infinispan"); const log4js = require('log4js'); log4js.configure('example-log4js.json'); async function test() { await new Promise((resolve, reject) => setTimeout(() => resolve(), 1000)); console.log('Hello, World!'); let client = await infinispan.client({port: 11222, host: '127.0.0.1'}); console.log(`Connected to Infinispan dashboard data`); await client.put('key', 'value'); let value = await client.get('key'); console.log('get(key)=' + value); let success = await client.remove('key'); console.log('remove(key)=' + success); let stats = await client.stats(); console.log('Number of stores: ' + stats.stores); console.log('Number of cache hits: ' + stats.hits); console.log('All statistics: ' + JSON.stringify(stats, null, " ")); await client.disconnect(); } test();
多个缓存条目
const infinispan = require("infinispan"); const log4js = require('log4js'); log4js.configure('example-log4js.json'); async function test() { let client = await infinispan.client({port: 11222, host: '127.0.0.1'}); console.log(`Connected to Infinispan dashboard data`); let data = [ {key: 'multi1', value: 'v1'}, {key: 'multi2', value: 'v2'}, {key: 'multi3', value: 'v3'}]; await client.putAll(data); let entries = await client.getAll(['multi2', 'multi3']); console.log('getAll(multi2, multi3)=%s', JSON.stringify(entries)); let iterator = await client.iterator(1); let entry = {done: true}; do { entry = await iterator.next(); console.log('iterator.next()=' + JSON.stringify(entry)); } while (!entry.done); await iterator.close(); await client.clear(); await client.disconnect(); } test();
2.1.5. 运行服务器端脚本
您可以将自定义脚本添加到 Data Grid Server,然后从 Hot Rod JS 客户端运行它们。
脚本示例
// mode=local,language=javascript,parameters=[k, v],datatype='text/plain; charset=utf-8' cache.put(k, v); cache.get(k);
脚本执行
var infinispan = require('infinispan'); var readFile = Promise.denodeify(require('fs').readFile); var connected = infinispan.client( {port: 11222, host: '127.0.0.1'} { // Configure client connections with authentication and encryption here. } ); connected.then(function (client) { var addScriptFile = readFile('sample-script.js').then( function(file) { return client.addScript('sample-script', file.toString()); }); var clientExecute = addScriptFile.then( function() { return client.execute('sample-script', {k: 'exec-key', v: 'exec-value'}); }); var showExecute = clientExecute.then( function(ret) { console.log('Script execution returned: ' + ret); }); return showExecute.finally( function() { return client.disconnect(); }); }).catch(function(error) { console.log("Got error: " + error.message); });
2.1.6. 注册事件监听程序
事件监听器在缓存更新发生时通知 Hot Rod JS 客户端,包括创建、修改、删除或过期条目。
用于条目创建和修改通知客户端有关键和值的事件。仅删除条目和过期通知客户端有关密钥的事件。
事件监听程序注册
var infinispan = require('infinispan'); var connected = infinispan.client( {port: 11222, host: '127.0.0.1'} { // Configure client connections with authentication and encryption here. } ); connected.then(function (client) { var clientAddListenerCreate = client.addListener('create', onCreate); var clientAddListeners = clientAddListenerCreate.then( function(listenerId) { // Associate multiple callbacks with a single client-side listener. // To do this, register listeners with the same listener ID. var clientAddListenerModify = client.addListener('modify', onModify, {listenerId: listenerId}); var clientAddListenerRemove = client.addListener('remove', onRemove, {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); }); function onCreate(key, version) { console.log('[Event] Created key: ' + key + ' with version: ' + JSON.stringify(version)); } function onModify(key, version) { console.log('[Event] Modified key: ' + key + ', version after update: ' + JSON.stringify(version)); } function onRemove(key) { console.log('[Event] Removed key: ' + key); }
您可以调整来自事件监听程序的通知,以避免使用 key-value-with-previous-converter-factory
转换程序进行不必要的往返。例如,这允许您查找与事件内键关联的值,而不是在以后检索它们。
远程事件转换器
var infinispan = require('infinispan'); var connected = infinispan.client( {port: 11222, host: '127.0.0.1'} , { dataFormat : { keyType: 'application/json', valueType: 'application/json' } } ); connected.then(function (client) { // Include the remote event converter to avoid unnecessary roundtrips. var opts = { converterFactory : { name: "key-value-with-previous-converter-factory" } }; var clientAddListenerCreate = client.addListener('create', logEvent("Created"), opts); var clientAddListeners = clientAddListenerCreate.then( function(listenerId) { // Associate multiple callbacks with a single client-side listener. // To do this, register listeners with the same listener ID. var clientAddListenerModify = client.addListener('modify', logEvent("Modified"), {opts, listenerId: listenerId}); var clientAddListenerRemove = client.addListener('remove', logEvent("Removed"), {opts, listenerId: listenerId}); return Promise.all([clientAddListenerModify, clientAddListenerRemove]); }); var clientCreate = clientAddListeners.then( function() { return client.putIfAbsent('converted', 'v0'); }); var clientModify = clientCreate.then( function() { return client.replace('converted', 'v1'); }); var clientRemove = clientModify.then( function() { return client.remove('converted'); }); 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); }); function logEvent(prefix) { return function(event) { console.log(prefix + " key: " + event.key); console.log(prefix + " value: " + event.value); console.log(prefix + " previous value: " + event.prev); } }
您可以将自定义转换器添加到 Data Grid Server。如需更多信息,请参阅 Data Grid 文档。
2.1.7. 使用条件操作
Hot Rod 协议存储有关数据网格值的元数据。这个元数据提供了一个确定性因素,可让您为特定条件执行缓存操作。例如,如果版本不匹配,则需要替换键的值。
使用 getWithMetadata
方法检索与键值关联的元数据。
var infinispan = require('infinispan'); var connected = infinispan.client( {port: 11222, host: '127.0.0.1'} { // Configure client connections with authentication and encryption here. } ); connected.then(function (client) { var clientPut = client.putIfAbsent('cond', 'v0'); var showPut = clientPut.then( function(success) { console.log(':putIfAbsent(cond)=' + success); }); var clientReplace = showPut.then( function() { return client.replace('cond', 'v1'); } ); var showReplace = clientReplace.then( function(success) { console.log('replace(cond)=' + success); }); var clientGetMetaForReplace = showReplace.then( function() { return client.getWithMetadata('cond'); }); // Call the getWithMetadata method to retrieve the value and its metadata. var clientReplaceWithVersion = clientGetMetaForReplace.then( function(entry) { console.log('getWithMetadata(cond)=' + JSON.stringify(entry)); return client.replaceWithVersion('cond', 'v2', entry.version); } ); var showReplaceWithVersion = clientReplaceWithVersion.then( function(success) { console.log('replaceWithVersion(cond)=' + success); }); var clientGetMetaForRemove = showReplaceWithVersion.then( function() { return client.getWithMetadata('cond'); }); var clientRemoveWithVersion = clientGetMetaForRemove.then( function(entry) { console.log('getWithMetadata(cond)=' + JSON.stringify(entry)); return client.removeWithVersion('cond', entry.version); } ); var showRemoveWithVersion = clientRemoveWithVersion.then( function(success) { console.log('removeWithVersion(cond)=' + success)}); return showRemoveWithVersion.finally( function() { return client.disconnect(); }); }).catch(function(error) { console.log("Got error: " + error.message); });
2.1.8. 使用临时数据
使用 getWithMetadata
和 size
方法使缓存条目过期。
var infinispan = require('infinispan'); var connected = infinispan.client( {port: 11222, host: '127.0.0.1'} { // Configure client connections with authentication and encryption here. } ); connected.then(function (client) { var clientPutExpiry = client.put('expiry', 'value', {lifespan: '1s'}); var clientGetMetaAndSize = clientPutExpiry.then( function() { // Compute getWithMetadata and size in parallel. return Promise.all([client.getWithMetadata('expiry'), client.size()]); }); var showGetMetaAndSize = clientGetMetaAndSize.then( function(values) { console.log('Before expiration:'); console.log('getWithMetadata(expiry)=' + JSON.stringify(values[0])); console.log('size=' + values[1]); }); var clientContainsAndSize = showGetMetaAndSize.then( function() { sleepFor(1100); // Sleep to force expiration. return Promise.all([client.containsKey('expiry'), client.size()]); }); var showContainsAndSize = clientContainsAndSize.then( function(values) { console.log('After expiration:'); console.log('containsKey(expiry)=' + values[0]); console.log('size=' + values[1]); }); return showContainsAndSize.finally( function() { return client.disconnect(); }); }).catch(function(error) { console.log("Got error: " + error.message); }); function sleepFor(sleepDuration){ var now = new Date().getTime(); while(new Date().getTime() < now + sleepDuration){ /* Do nothing. */ } }