11. Function Implementations & Executions

11.1 Background

Distributed processing, particularly in conjunction with data access and mutation operations, is a very effective and efficient use of clustered computing resources. This is along the same lines as MapReduce.

A naively conceived query returning potentially hundreds of thousands, or even millions of rows of data in a result set back to the application that queried and requested the data can be very costly, especially under load. Therefore, it is typically more efficient to move the processing and computations on the predicated data set to where the data resides, perform the required computations, summarize the results and then send the reduced data set back to the client.

Additionally, when the computations are handled in parallel, across the cluster of computing resources, the operation can be performed much faster. This typically involves intelligently organizing the data using various partitioning (a.k.a. sharding) strategies to uniformly balance the data set across the cluster.

Well, both Apache Geode and Pivotal GemFire address this very important application concern in its Function Execution framework.

Spring Data for Apache Geode/Pivotal GemFire builds on this Function Execution framework by enabling developers to implement and execute GemFire/Geode Functions using a very simple POJO-based, annotation configuration model.

[Tip]Tip

See here for the difference between Function implementation & executions.

Taking this 1 step further, Spring Boot for Apache Geode/Pivotal GemFire auto-configures and enables both Function implementation and execution out-of-the-box. Therefore, you can immediately begin writing Functions and invoking them without having to worry about all the necessary plumbing to begin with. You can rest assured that it will just work as expected.

11.2 Applying Functions

Earlier, when we talked about caching, we described a FinancialLoanApplicationService class that could process eligibility when a Person applied for a financial loan.

This can be a very resource intensive & expensive operation since it might involve collecting credit and employment history, gathering information on existing, outstanding/unpaid loans, and so on and so forth. We applied caching in order to not have to recompute, or redetermine eligibility every time a loan office may want to review the decision with the customer.

But what about the process of computing eligibility in the first place?

Currently the application’s FinancialLoanApplicationService class seems to be designed to fetch the data and perform the eligibility determination in place. However, it might be far better to distribute the processing and even determine eligibility for a larger group of people all at once, especially when multiple, related people are involved in a single decision, as is typically the case.

We implement an EligibilityDeterminationFunction class using SDG very simply as:

Function implementation. 

@Component
class EligibilityDeterminationFunction {

    @GemfireFunction(HA = true, hasResult = true, optimizeForWrite=true)
    public EligibilityDecision determineEligibility(FunctionContext functionContext, Person person, Timespan timespan) {
        ...
    }
}

Using the SDG @GemfireFunction annotation, it is easy to implement our Function as a POJO method. SDG handles registering this POJO method as a proper Function with GemFire/Geode appropriately.

If we now want to call this Function from our Spring Boot, ClientCache application, then we simply define a Function Execution interface with a method name matching the Function name, and targeting the execution on the "EligibilityDecisions" Region:

Function execution. 

@OnRegion("EligibilityDecisions")
interface EligibilityDeterminationExecution {

  EligibilityDecision determineEligibility(Person person, Timespan timespan);

}

We can then inject the EligibilityDeterminationExecution into our FinancialLoanApplicationService like any other object/Spring bean:

Function use. 

@Service
class FinancialLoanApplicationService {

    private final EligibilityDeterminationExecution execution;

    public LoanApplicationService(EligibilityDeterminationExecution execution) {
        this.execution = execution;
    }

    @Cacheable("EligibilityDecisions", ...)
    EligibilityDecision processEligility(Person person, Timespan timespan) {
        return this.execution.determineEligibility(person, timespan);
    }
}

Just like caching, no addition configuration is required to enable and find your application Function implementations and executions. Simply build and run. Spring Boot for Apache Geode/Pivotal GemFire handles the rest.

[Tip]Tip

It is common to implement and register your application Functions on the server and execute them from the client.