第2章 Hot Rod JS クライアントの使用
Data Grid で Hot Rod JS クライアントを使用する例を見てみましょう。
2.1. Hot Rod JS クライアントの例
Hot Rod JS クライアントをインストールして設定した後に、Data Grid とのより複雑な操作に移動する前に、一部の基本キャッシュ操作を試して使用を開始します。
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 プロトコルは、Data Grid に値に関するメタデータを保存します。このメタデータは、特定の条件に対してキャッシュ操作を実行できる決定論的な要因を提供します。たとえば、バージョンに一致しない場合はキーの値を置き換えることができます。
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. */ } }