serializationscheduled-taskshazelcasthazelcast-imap

How to schedule a task on Hazelcast that queries on the IMap?


I want to schedule a task on Hazelcast that runs at a fixed interval and updates the IMap with some data that I get after hitting a rest endpoint. Below is a sample code:

// Main class

IScheduledExecutorService service = hazelcast.getScheduledExecutorService("default");

service.scheduleAtFixedRate(TaskUtils.named("my-task", myTask), 30, 1);

// Task

@Singleton
public class MyTask implements Runnable, Serializable {

    RestClient restClient;

    IMap<String, JsonObject> map;

    @Inject
    MyTask() { // Inject hazelcast and restclient
        map = hazelcastInstace.getMap("my-map");
        this.restClient = restClient;
    }

    @Override
    public void run() {
        Collection<JSONObject> values = map.values(new MyCustomFilter());
        for(JSONObject obj : values) {
             // query endpoint based on id
             map.submitToKey(key, response);
        }

    }


    private static class MyCustomFilter implements Predicate<String, JSONObject> {

        public boolean apply(Map.Entry<String, JSONObject> map) {
             // logic to filter relevant keys
        }

    }
}

When I try to execute this on the cluster, I get:

java.io.NotSerializableException: com.hazelcast.map.impl.proxy.MapProxyImpl

Now I need the IMap to selectively query only some keys based on PredicateFilter and this needs to be a background scheduled job so stuck here on how to take this forward. Any help appreciated. TIA


Solution

  • Try making your task also implement HazelcastInstanceAware

    When you submit your task, it is serialized, sent to the grid to run, deserialized when it is received, and the run() method is called.

    If your task implements HazelcastInstanceAware, then between deserialization and run(), Hazelcast will call the method setHazelcastInstance(HazelcastInstance instance) to pass your code a reference to the particular Hazelcast instance it is running in. From there you can just do instance.getMap("my-map") and store the map reference in a transient field that the run() method can use.