Skip to main content
Redhat Developers  Logo
  • AI

    Get started with AI

    • Red Hat AI
      Accelerate the development and deployment of enterprise AI solutions.
    • AI learning hub
      Explore learning materials and tools, organized by task.
    • AI interactive demos
      Click through scenarios with Red Hat AI, including training LLMs and more.
    • AI/ML learning paths
      Expand your OpenShift AI knowledge using these learning resources.
    • AI quickstarts
      Focused AI use cases designed for fast deployment on Red Hat AI platforms.
    • No-cost AI training
      Foundational Red Hat AI training.

    Featured resources

    • OpenShift AI learning
    • Open source AI for developers
    • AI product application development
    • Open source-powered AI/ML for hybrid cloud
    • AI and Node.js cheat sheet

    Red Hat AI Factory with NVIDIA

    • Red Hat AI Factory with NVIDIA is a co-engineered, enterprise-grade AI solution for building, deploying, and managing AI at scale across hybrid cloud environments.
    • Explore the solution
  • Learn

    Self-guided

    • Documentation
      Find answers, get step-by-step guidance, and learn how to use Red Hat products.
    • Learning paths
      Explore curated walkthroughs for common development tasks.
    • See all learning

    Hands-on

    • Developer Sandbox
      Spin up Red Hat's products and technologies without setup or configuration.
    • Interactive labs
      Learn by doing in these hands-on, browser-based experiences.
    • Interactive demos
      Click through product features in these guided tours.

    Browse by topic

    • AI/ML
    • Automation
    • Java
    • Kubernetes
    • Linux
    • See all topics

    Training & certifications

    • Courses and exams
    • Certifications
    • Skills assessments
    • Red Hat Academy
    • Learning subscription
    • Explore training
  • Build

    Get started

    • Red Hat build of Podman Desktop
      A downloadable, local development hub to experiment with our products and builds.
    • Developer Sandbox
      Spin up Red Hat's products and technologies without setup or configuration.

    Download products

    • Access product downloads to start building and testing right away.
    • Red Hat Enterprise Linux
    • Red Hat AI
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform
    • See all products

    Featured

    • Red Hat build of OpenJDK
    • Red Hat JBoss Enterprise Application Platform
    • Red Hat OpenShift Dev Spaces
    • Red Hat Developer Toolset

    References

    • E-books
    • Documentation
    • Cheat sheets
    • Architecture center
  • Community

    Get involved

    • Events
    • Live AI events
    • Red Hat Summit
    • Red Hat Accelerators
    • Community discussions

    Follow along

    • Articles & blogs
    • Developer newsletter
    • Videos
    • Github

    Get help

    • Customer service
    • Customer support
    • Regional contacts
    • Find a partner

    Join the Red Hat Developer program

    • Download Red Hat products and project builds, access support documentation, learning content, and more.
    • Explore the benefits

How to run a custom server task in Red Hat Data Grid

July 18, 2023
Torbjorn Dahlen
Related topics:
Containers
Related products:
Red Hat Data GridRed Hat OpenShift

    Custom server tasks can be deployed to the Red Hat Data Grid server for remote execution from the command line interface (CLI) and Hot Rod or REST clients. Tasks can be implemented as custom Java classes or as scripts in languages such as JavaScript.

    In this article, we will deploy a Java class that will evict and reload the cache in order to pick up modified entries in the original database table from which we loaded the cache. Data Grid will automatically load new entries added to the database table, however modified rows will require reloading using a server task, as shown in the following example.

    How to deploy PostgreSQL with a custom image

    SQL cache stores let you load Red Hat Data Grid caches from existing database tables. Data Grid offers two types of SQL cache stores: table and query. In the following example, Data Grid will load entries from a single database table. It is also possible to use SQL queries to load entries from single or multiple database tables.

    For more details, refer to SQL cache stores. All source code for this tutorial can be found on GitHub.

    We will use PostgreSQL to contain the table that will be loaded by Data Grid. To deploy PostgreSQL in Red Hat OpenShift, we will use a modified image that initializes the database with a table and a Data Grid user with granted privileges to read from the table.

    FROM registry.redhat.io/rhel8/postgresql-12
    
    LABEL description="This is a custom PostgreSQL container image which loads the database schema definitions and the data into the model and inventory tables "
    
    COPY db/load_db.sh /opt/app-root/src/postgresql-start/ 
    COPY db/rpi-store-ddl.sql /opt/app-root/src/postgresql-start/ 
    COPY db/rpi-store-dml.sql /opt/app-root/src/postgresql-start/ 
    COPY db/rpi-store-role.sql /opt/app-root/src/postgresql-start/
    
    USER root 
    RUN chmod 774 /opt/app-root/src/postgresql-start/*.sh 
    USER 26

    The load_db.sh script populates the table used to load the Data Grid cache and creates the user infinispan with privileges to SELECT from the model table:

    #!/bin/bash
    
    START_DIR="$APP_DATA/src/postgresql-start"
    
    run_sql_script () {
    
       SQL_FILE=$1
    
       psql -U postgres \
    
          --echo-all \
    
          -f $SQL_FILE \
    
          -d $POSTGRESQL_DATABASE
    
    
    }
    
    run_sql_script $START_DIR/rpi-store-ddl.sql
    
    run_sql_script $START_DIR/rpi-store-dml.sql
    
    run_sql_script $START_DIR/rpi-store-role.sql

    Note that the user needs to be postgres to create a new user.

    The rpi-store-ddl.sql script will run the following SQL commands to create the model table which will be used to load keys and values into the Data Grid cache:

    drop table if exists model;
    
    create table model (
       id integer primary key,
       name varchar(20),
       model varchar(20),
       soc varchar(20),
       memory_mb integer,
       ethernet boolean,
       release_year integer
    );

    The rpi-store-dml.sqlscript will create three rows in the model table:

    insert into model (id, name, model, soc, memory_mb, ethernet, release_year) values (1, 'Raspberry Pi', 'B', 'BCM2835', 256, TRUE, 2012);
    insert into model (id, name, model, soc, memory_mb, ethernet, release_year) values (2, 'Raspberry Pi Zero', 'Zero', 'BCM2835', 512, FALSE, 2015);
    insert into model (id, name, model, soc, memory_mb, ethernet, release_year) values (3, 'Raspberry Pi Zero', '2W', 'BCM2835', 512, FALSE, 2021);

    Finally, the rpi-store-role.sql script will create the user infinispan and grant SELECT privileges on the model table. This user will be provided to the JDBC connector used by Data Grid.

    CREATE USER infinispan WITH PASSWORD 'secret';
    GRANT SELECT ON model TO infinispan;

    We can now deploy PostgreSQL in OpenShift using the modified image:

    $ oc new-project infinispan-demo
    $ oc new-build \ 
    > https://github.com/torbjorndahlen/infinispan-evict-cache \
    > --strategy=docker \
    > --name='postgresql-12-custom'
    
    $ oc new-app \
    > -e POSTGRESQL_USER=db \
    > -e POSTGRESQL_PASSWORD=secret \
    > -e POSTGRESQL_DATABASE=rpi-store \
    > postgresql-12-custom

    After deployment is complete, we can verify that the user infinispan, the DB rpi-store, and the model table were created as expected:

    $ oc get pods
    NAME                                    READY	STATUS		RESTARTS	AGE
    postgresql-12-custom-1-build           	0/1	Completed   	0          	2m40s
    postgresql-12-custom-0   	        1/1	Running     	0          	38s
    
    $ oc exec postgresql-12-custom-0 -- psql -U infinispan -d rpi-store -c "select * from model;"
     id |       name        | model |   soc   | memory_mb | ethernet | release_year 
    ----+-------------------+-------+---------+-----------+----------+--------------
      1 | Raspberry Pi      | B     | BCM2835 |       256 | t        |         2012
      2 | Raspberry Pi Zero | Zero  | BCM2835 |       512 | f        |         2015
      3 | Raspberry Pi Zero | 2W    | BCM2835 |       512 | f        |         2021
    (3 rows)

    Server task implementation

    The EvictReloadTask class implements the org.infinispan.tasks.ServerTask interface where the call() method is invoked by Data Grid when called from the Hot Rod client:

    @MetaInfServices(ServerTask.class)
    public class EvictReloadTask implements ServerTask, java.io.Serializable {
    
       private static final ThreadLocal taskContext = new ThreadLocal<>();
    
       @Override
       public String call() throws Exception {
        TaskContext ctx = taskContext.get();
        AdvancedCache<?, ?> cache = ctx.getCacheManager().getCache("rpi-store").getAdvancedCache();
        cache.withFlags(Flag.SKIP_CACHE_STORE).clear();
        cache.getComponentRegistry().getComponent(PreloadManager.class).start();
        return null;
      }
    }

    Before deploying Data Grid, the server task is packaged in a JAR file containing the server task classes and a file in the META-INF/services directory. This file is named org.infinispan.tasks.ServerTask and contains the fully qualified name of the server task.

    example.EvictReloadTask

    You also need to add your server task classes to a deserialization allow list, since Data Grid does not allow deserialization of arbitrary Java classes for security reasons. To do this, we create a ConfigMap containing an allow-list for serializing of the server task class:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: cluster-config
      namespace: infinispan-demo
    data:
      infinispan-config.xml: >
        <infinispan>
          <cache-container>
             <serialization
               marshaller="org.infinispan.commons.marshall.JavaSerializationMarshaller">
               <allow-list>
                 <class>example.EvictReloadTask</class>
               </allow-list>
             </serialization>
          </cache-container>
        </infinispan>

    Then, we deploy the ConfigMap:

    $ oc apply -f cluster-config.yaml

    Deploy Data Grid

    To deploy the Data Grid cluster in OpenShift we use the Data Grid operator.

    Install the operator:

    $ oc apply -f infinispan-operator.yaml
    $ oc apply -f subscription.yaml

    In this example, we will use the following custom resource to let the operator create a Data Grid cluster:

    apiVersion: infinispan.org/v1
    kind: Infinispan
    metadata:
     name: infinispan
     namespace: infinispan-demo
    spec:
     security:
       endpointEncryption:
         type: None
         clientCert: None
     expose:
       type: LoadBalancer
     dependencies:
       artifacts:
         - maven: 'org.postgresql:postgresql:42.3.1'
         - url: >-
             https://github.com/torbjorndahlen/infinispan-evict-cache/raw/main/ServerTask/server/target/ServerTask.jar
     service:
       type: DataGrid
     replicas: 1
     configMapName: cluster-config

    The Maven artifact refers to the JDBC driver for PostgreSQL. The URL artifact refers to the Git repository where the server task JAR file can be downloaded.

    The Data Grid cluster is created with oc create:

    $ oc create -f infinispan-cr.yaml

    Use oc get svc to find the URL to the Data Grid console:

    $ oc get svc
    NAME                         TYPE          CLUSTER-IP   EXTERNAL-IP         PORT(S)           AGE
    example-infinispan-external  LoadBalancer  172.30.5.74  my_host.example.com 11222:31797/TCP   6m39s

    In this example, we exposed Data Grid through a loadbalancer. The URL to the Data Grid contains the loadbalancer hostname and port. The Data Grid console can be accessed at http://my_host.example.com:11222. The console username and password is stored in the infinispan-generated-secret.

    $ oc get secret infinispan-generated-secret -o jsonpath="{.data.identities\.yaml}" | base64 --decode
    
    credentials:
    - username: developer
      password: my_password
      roles:
      - admin

    Create the cache

    You can use SQL stores with database tables that contain composite primary keys or composite values.

    To use composite keys or values, you must provide Data Grid with protobuf schema that describe the data types. You must also add schema configuration to your SQL store and specify the message names for keys and values.

    You can find more information on cache encoding and marshaling.

    Using the Data Grid console, create a cache using a protobuf schema and SQL cache store configuration, as shown in Figure 1:

    A screenshot of the Data Grid console, creating a cache using a protobuf schema.
    Figure 1: Creating a cache using a protobuf schema in the Data Grid console.

    Use the following configuration for the cache. In the configuration, table-name refers to the model table created when PostgreSQL was deployed. The message-name and package refers to the protobuf schema. Notice the user infinispan that was previously created is used by the JDBC driver.

    {
       "distributed-cache": {
         "mode": "SYNC",
         "encoding": {
           "key": {
             "media-type": "application/x-protostream"
           },
           "value": {          
             "media-type": "application/x-protostream"        
           }
         },
         "persistence": {
           "table-jdbc-store": {
             "shared": true,
             "segmented": false,
             "dialect": "POSTGRES",
             "table-name": "model",
             "schema": {
               "message-name": "model_value",
               "package": "example"
             },
             "connection-pool": {            
               "connection-url": "jdbc:postgresql://postgresql-12-custom:5432/rpi-store",            
               "driver": "org.postgresql.Driver",            
               "username": "infinispan",            
               "password": "secret"          
             }
           }
         }
       }
     }

    When created, the cache will automatically load the model table, as shown in Figure 2:

    Shows the cache with entries from the model table.
    Figure 2: The cache is loaded with entries from the model table.

    Run the server task

    In our example, the table from which Data Grid loaded the entries to the cache will be modified without notifying Data Grid. To update the cache with the modified entry, the server task will be called from a Hot Rod client.

    First, we update a row in the model table:

    $ oc exec postgresql-12-custom-0 -- psql -U postgres -d rpi-store -c "update model set name = 'Raspberry Pi UPDATED' where id = 1;"
    
    
    $ oc exec postgresql-12-custom-0 -- psql -U infinispan -d rpi-store -c "select * from model;"                                  
     id |       name            | model |   soc   | memory_mb | ethernet | release_year 
    ----+-----------------------+-------+---------+-----------+----------+--------------
      2 | Raspberry Pi Zero     | Zero  | BCM2835 |       512 | f        |         2015
      3 | Raspberry Pi Zero     | 2W    | BCM2835 |       512 | f        |         2021
      1 | Raspberry Pi UPDATED  | B     | BCM2835 |       256 | t        |         2012
    (3 rows)

    Verify that the cache doesn't contain the updated entry by using the Infinispan CLI to lookup the key 1 in the cache:

    $ oc get pods
    NAME             READY   STATUS      RESTARTS   AGE
    infinispan-0     1/1     Running     0          86s
    
    $ oc rsh infinispan-0
    
    sh-4.4$./bin/cli.sh 
    [disconnected]> connect
    Username: developer
    Password: my_password
    [infinispan-0-28040@infinispan//containers/default]> cd caches
    [infinispan-0-28040@infinispan//containers/default/caches]> cd rpi-store
    [infinispan-0-28040@infinispan//containers/default/caches/rpi-store]> get 1
    {
      "_type" : "example.model_value",
      "name" : "Raspberry Pi",
      "model" : "B",
      "soc" : "BCM2835",
      "memory_mb" : 256,
      "ethernet" : true,
      "release_year" : 2012
    }

    The cache hasn't been notified about the modified row and still contains the name, Raspberry Pi.

    To load the modified entry into the cache, we run the client. The username and password are located under Secrets in infinispan-generated-secret. The Data Grid server can be accessed from the infinispan loadbalancer hostname and port.

    $ git clone https://github.com/torbjorndahlen/infinispan-evict-cache.git
    
    $ cd infinispan-evict-cache/ServerTask/client
    
    $ mvn clean package
    $ mvn assembly:assembly -DdescriptorId=jar-with-dependencies
    
    $ java -cp target/ServerTaskClient-jar-with-dependencies.jar \
    > example.CacheServerTaskInvocation \
    > my_host.example.com 11222 \
    > developer my_password rpi-store

    Verify that the cache now contains the modified entries by using the Infinispan CLI to lookup the key 1 in the cache:

    $ oc rsh infinispan-0
    
    sh-4.4$./bin/cli.sh 
    [disconnected]> connect
    Username: developer
    Password: my_password
    [infinispan-0-28040@infinispan//containers/default]> cd caches
    [infinispan-0-28040@infinispan//containers/default/caches]> cd rpi-store
    [infinispan-0-28040@infinispan//containers/default/caches/rpi-store]> get 1
    {
      "_type" : "example.model_value",
      "name" : "Raspberry Pi UPDATED",
      "model" : "B",
      "soc" : "BCM2835",
      "memory_mb" : 256,
      "ethernet" : true,
      "release_year" : 2012
    }

    The updated value for key 1 has been loaded into the cache.

    Summary

    In this article, we demonstrated how a cache using a PostgreSQL database as a cache store can be refreshed by using a server task invoked from a Hot Rod client when a table is being updated by other means than passing through Data Grid.

    Thanks to Tristan Tarrant at Red Hat for providing advice and suggestions on the implementation of this tutorial.

    Last updated: September 19, 2023

    Related Posts

    • Create and manage Data Grid services

    • Securely connect Quarkus and Red Hat Data Grid on Red Hat OpenShift

    • How to connect to Red Hat Data Grid without SSL

    • Five layers of security for Red Hat Data Grid on OpenShift

    Recent Posts

    • Federated identity across the hybrid cloud using zero trust workload identity manager

    • Confidential virtual machine storage attack scenarios

    • Introducing virtualization platform autopilot

    • Integrate zero trust workload identity manager with Red Hat OpenShift GitOps

    • Best Practice Configuration and Tuning for Linux and Windows VMs

    What’s up next?

    Learn how to deploy an application on a cluster using Red Hat OpenShift Service on AWS. This learning path uses a pre-built application to allow you to become more familiar with OpenShift and Kubernetes features.

    Start learning
    Red Hat Developers logo LinkedIn YouTube Twitter Facebook

    Platforms

    • Red Hat AI
    • Red Hat Enterprise Linux
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform
    • See all products

    Build

    • Developer Sandbox
    • Developer tools
    • Interactive tutorials
    • API catalog

    Quicklinks

    • Learning resources
    • E-books
    • Cheat sheets
    • Blog
    • Events
    • Newsletter

    Communicate

    • About us
    • Contact sales
    • Find a partner
    • Report a website issue
    • Site status dashboard
    • Report a security problem

    RED HAT DEVELOPER

    Build here. Go anywhere.

    We serve the builders. The problem solvers who create careers with code.

    Join us if you’re a developer, software engineer, web designer, front-end designer, UX designer, computer scientist, architect, tester, product manager, project manager or team lead.

    Sign me up

    Red Hat legal and privacy links

    • About Red Hat
    • Jobs
    • Events
    • Locations
    • Contact Red Hat
    • Red Hat Blog
    • Inclusion at Red Hat
    • Cool Stuff Store
    • Red Hat Summit
    © 2026 Red Hat

    Red Hat legal and privacy links

    • Privacy statement
    • Terms of use
    • All policies and guidelines
    • Digital accessibility

    Chat Support

    Please log in with your Red Hat account to access chat support.