Evaluating All Objects in Parallel

API modules can run a custom evaluation method in parallel against all objects in the module. Inherit from ForEachApiProcessor and register your class to perform parallel operations.

Background

Unlike an API Processor endpoint method, which only operates against a single SOSS object at a time, a ForEachApiProcessor implementation runs against every SOSS object instance in your module. These distributed “foreach” operations can be used to perform bulk mutations or removals.

This walkthrough will implement a ForEachApiProcessor for the shopping cart project created in the previous topic.

Prerequisites

  • Java 8 or higher

  • Maven

  • The completed ShoppingCart API module

Procedure

1. Create a ForEachApiProcessor subclass

Create a new class that inherits from the ForEachApiProcessor class. This class will be used to perform bulk removal of empty shopping carts.

The base class takes the type of your API module’s SOSS object as a type parameter. It has a single abstract method, valuate, that must be implemented. This method will be called for every SOSS object in the API module. Clients can supply an arbitrary argument value as a byte array, which is available to the evaluate method as a parameter.

package com.mycompany.shopping.server;

import com.scaleoutsoftware.modules.abstractions.ApiProcessingContext;
import com.scaleoutsoftware.modules.abstractions.ForEachApiProcessor;
import com.scaleoutsoftware.modules.abstractions.ProcessingResult;

public class ShoppingCartForEachApiProcessor extends ForEachApiProcessor<ShoppingCart> {

    @Override
    public ProcessingResult evaluate(ApiProcessingContext<ShoppingCart> apiProcessingContext, ShoppingCart shoppingCart, byte[] payload) {
        if(shoppingCart.isEmpty()) {
            return ProcessingResult.Remove;
        } else {
            return ProcessingResult.NoUpdate;
        }
    }
}
  • The evaluate implementation must be marked with the @SossEvalMethod annotation, indicating whether the supplied SOSS object should be exclusively locked for the duration of the evaluate call. Use ApiProcessorLockingMode.ExclusiveLock in the @SossEvalMethod attribute if you need to ensure that only one request can modify the SOSS object at a time.

  • The evaluate method must return a ProcessingResult value to indicate what should be done with the object in the ScaleOut service after the method has returned:

    • DoUpdate: Indicates that the object was (or may have been) modified and must be updated in the ScaleOut service.

    • NoUpdate: Indicates the object was not modified and does not need to be updated in the ScaleOut service. (If you are unsure of whether the object was modified, always return DoUpdate.)

    • Remove: Remove the SOSS object from the ScaleOut service.

2. Register the ForEachApiProcessor implementation

In your API module’s Main.java class, find the line where your API module is registered using ModulePackage.addApiModule(). The ApiModule instance that is returned by this call can be used to add parallel “foreach” operations.

ApiModule<ShoppingCart> apiModule = modulePackage.addApiModule("ShoppingCart", new ShoppingCartApiProcessor(), apiModuleOptions);
apiModule.addForEachOperation("removeEmpty", new ShoppingCartForEachApiProcessor(), new ParallelOperationOptionsBuilder<ShoppingCart, Void>(ShoppingCart.class).build());

3. Expose the ForEach operation to clients

In a client application, the ExampleClient subclass that was created in the Creating an API Module Project topic can be used to invoke the new removeEmpty operation. Use the ApiModuleClient.invokeAll() method to run a parallel operation, supplying the name of the operation and an optional byte array as an argument (not used in this example):

public void removeEmptyCarts() throws ApiModuleException {
    invokeAll("removeEmpty", null, Duration.ofSeconds(10));
}