Chapter 14. Running scripts and tasks on Data Grid Server Add tasks and scripts to Data Grid Server deployments for remote execution from the Command Line Interface (CLI) and Hot Rod or REST clients. You can implement tasks as custom Java classes or define scripts in languages such as JavaScript. 14.1. Adding tasks to Data Grid Server deployments Add your custom server task classes to Data Grid Server. Prerequisites Stop Data Grid Server if it is running. Data Grid Server does not support runtime deployment of custom classes. Procedure Add a META-INF/services/org.infinispan.tasks.ServerTask file that contains the fully qualified names of server tasks, for example: Package your server task implementation in a JAR file. Copy the JAR file to the USDRHDG_HOME/server/lib directory of your Data Grid Server installation. Add your classes to the deserialization allow list in your Data Grid configuration. Alternatively set the allow list using system properties. Reference Adding Java Classes to Deserialization Allow Lists Data Grid Configuration Schema 14.1.1. Data Grid Server tasks Data Grid Server tasks are classes that extend the org.infinispan.tasks.ServerTask interface and generally include the following method calls: setTaskContext() Allows access to execution context information including task parameters, cache references on which tasks are executed, and so on. In most cases, implementations store this information locally and use it when tasks are actually executed. When using SHARED instantiation mode, the task should use a ThreadLocal to store the TaskContext for concurrent invocations. getName() Returns unique names for tasks. Clients invoke tasks with these names. getExecutionMode() Returns the execution mode for tasks. TaskExecutionMode.ONE_NODE only the node that handles the request executes the script. Although scripts can still invoke clustered operations. This is the default. TaskExecutionMode.ALL_NODES Data Grid uses clustered executors to run scripts across nodes. For example, server tasks that invoke stream processing need to be executed on a single node because stream processing is distributed to all nodes. getInstantiationMode() Returns the instantiation mode for tasks. TaskInstantiationMode.SHARED creates a single instance that is reused for every task execution on the same server. This is the default. TaskInstantiationMode.ISOLATED creates a new instance for every invocation. call() Computes a result. This method is defined in the java.util.concurrent.Callable interface and is invoked with server tasks. Important Server task implementations must adhere to service loader pattern requirements. For example, implementations must have a zero-argument constructors. The following HelloTask class implementation provides an example task that has one parameter. It also illustrates the use of a ThreadLocal to store the TaskContext for concurrent invocations. package example; import org.infinispan.tasks.ServerTask; import org.infinispan.tasks.TaskContext; public class HelloTask implements ServerTask<String> { private static final ThreadLocal<TaskContext> taskContext = new ThreadLocal<>(); @Override public void setTaskContext(TaskContext ctx) { taskContext.set(ctx); } @Override public String call() throws Exception { TaskContext ctx = taskContext.get(); String name = (String) ctx.getParameters().get().get("name"); return "Hello " + name; } @Override public String getName() { return "hello-task"; } } Reference org.infinispan.tasks.ServerTask java.util.concurrent.Callable.call() java.util.ServiceLoader 14.2. Adding scripts to Data Grid Server deployments Use the command line interface to add scripts to Data Grid Server. Prerequisites Data Grid Server stores scripts in the ___script_cache cache. If you enable cache authorization, users must have CREATE permissions to add to ___script_cache . Assign users the deployer role at minimum if you use default authorization settings. Procedure Define scripts as required. For example, create a file named multiplication.js that runs on a single Data Grid server, has two parameters, and uses JavaScript to multiply a given value: // mode=local,language=javascript multiplicand * multiplier Create a CLI connection to Data Grid. Use the task command to upload scripts, as in the following example: Verify that your scripts are available. 14.2.1. Data Grid Server scripts Data Grid Server scripting is based on the javax.script API and is compatible with any JVM-based ScriptEngine implementation. Hello world The following is a simple example that runs on a single Data Grid server, has one parameter, and uses JavaScript: // mode=local,language=javascript,parameters=[greetee] "Hello " + greetee When you run the preceding script, you pass a value for the greetee parameter and Data Grid returns "Hello USD{value}" . 14.2.1.1. Script metadata Metadata provides additional information about scripts that Data Grid Server uses when running scripts. Script metadata are property=value pairs that you add to comments in the first lines of scripts, such as the following example: // name=test, language=javascript // mode=local, parameters=[a,b,c] Use comment styles that match the scripting language ( // , ;; , # ). Separate property=value pairs with commas. Separate values with single (') or double (") quote characters. Table 14.1. Metadata Properties Property Description mode Defines the execution mode and has the following values: local only the node that handles the request executes the script. Although scripts can still invoke clustered operations. distributed Data Grid uses clustered executors to run scripts across nodes. language Specifies the ScriptEngine that executes the script. extension Specifies filename extensions as an alternative method to set the ScriptEngine. role Specifies roles that users must have to execute scripts. parameters Specifies an array of valid parameter names for this script. Invocations which specify parameters not included in this list cause exceptions. datatype Optionally sets the MediaType (MIME type) for storing data as well as parameter and return values. This property is useful for remote clients that support particular data formats only. Currently you can set only text/plain; charset=utf-8 to use the String UTF-8 format for data. 14.2.1.2. Script bindings Data Grid exposes internal objects as bindings for script execution. Binding Description cache Specifies the cache against which the script is run. marshaller Specifies the marshaller to use for serializing data to the cache. cacheManager Specifies the cacheManager for the cache. scriptingManager Specifies the instance of the script manager that runs the script. You can use this binding to run other scripts from a script. 14.2.1.3. Script parameters Data Grid lets you pass named parameters as bindings for running scripts. Parameters are name,value pairs, where name is a string and value is any value that the marshaller can interpret. The following example script has two parameters, multiplicand and multiplier . The script takes the value of multiplicand and multiplies it with the value of multiplier . // mode=local,language=javascript multiplicand * multiplier When you run the preceding script, Data Grid responds with the result of the expression evaluation. 14.2.2. Programmatically Creating Scripts Add scripts with the Hot Rod RemoteCache interface as in the following example: RemoteCache<String, String> scriptCache = cacheManager.getCache("___script_cache"); scriptCache.put("multiplication.js", "// mode=local,language=javascript\n" + "multiplicand * multiplier\n"); Reference org.infinispan.client.hotrod.RemoteCache 14.3. Running scripts and tasks Use the command line interface to run tasks and scripts on Data Grid Server deployments. Alternatively you can execute scripts and tasks from Hot Rod clients. Prerequisites Add scripts or tasks to Data Grid Server. Procedure Create a CLI connection to Data Grid. Use the task command to run tasks and scripts, as in the following examples: Execute a script named multiplier.js and specify two parameters: Execute a task named @@cache@names to retrieve a list of all available caches: Programmatic execution Call the execute() method to run scripts with the Hot Rod RemoteCache interface, as in the following examples: Script execution RemoteCache<String, Integer> cache = cacheManager.getCache(); // Create parameters for script execution. Map<String, Object> params = new HashMap<>(); params.put("multiplicand", 10); params.put("multiplier", 20); // Run the script with the parameters. Object result = cache.execute("multiplication.js", params); Task execution // Add configuration for a locally running server. ConfigurationBuilder builder = new ConfigurationBuilder(); builder.addServer().host("127.0.0.1").port(11222); // Connect to the server. RemoteCacheManager cacheManager = new RemoteCacheManager(builder.build()); // Retrieve the remote cache. RemoteCache<String, String> cache = cacheManager.getCache(); // Create task parameters. Map<String, String> parameters = new HashMap<>(); parameters.put("name", "developer"); // Run the server task. String greet = cache.execute("hello-task", parameters); System.out.println(greet); Additional resources org.infinispan.client.hotrod.RemoteCache

Commands:
example.HelloTask
package example; import org.infinispan.tasks.ServerTask; import org.infinispan.tasks.TaskContext; public class HelloTask implements ServerTask<String> { private static final ThreadLocal<TaskContext> taskContext = new ThreadLocal<>(); @Override public void setTaskContext(TaskContext ctx) { taskContext.set(ctx); } @Override public String call() throws Exception { TaskContext ctx = taskContext.get(); String name = (String) ctx.getParameters().get().get("name"); return "Hello " + name; } @Override public String getName() { return "hello-task"; } }
// mode=local,language=javascript multiplicand * multiplier
task upload --file=multiplication.js multiplication
ls tasks multiplication
// mode=local,language=javascript,parameters=[greetee] "Hello " + greetee
// name=test, language=javascript // mode=local, parameters=[a,b,c]
// mode=local,language=javascript multiplicand * multiplier
RemoteCache<String, String> scriptCache = cacheManager.getCache("___script_cache"); scriptCache.put("multiplication.js", "// mode=local,language=javascript\n" + "multiplicand * multiplier\n");
task exec multiplier.js -Pmultiplicand=10 -Pmultiplier=20 200.0
task exec @@cache@names ["___protobuf_metadata","mycache","___script_cache"]
RemoteCache<String, Integer> cache = cacheManager.getCache(); // Create parameters for script execution. Map<String, Object> params = new HashMap<>(); params.put("multiplicand", 10); params.put("multiplier", 20); // Run the script with the parameters. Object result = cache.execute("multiplication.js", params);
// Add configuration for a locally running server. ConfigurationBuilder builder = new ConfigurationBuilder(); builder.addServer().host("127.0.0.1").port(11222); // Connect to the server. RemoteCacheManager cacheManager = new RemoteCacheManager(builder.build()); // Retrieve the remote cache. RemoteCache<String, String> cache = cacheManager.getCache(); // Create task parameters. Map<String, String> parameters = new HashMap<>(); parameters.put("name", "developer"); // Run the server task. String greet = cache.execute("hello-task", parameters); System.out.println(greet);