Table of Contents

Writing Simple PMI Handlers

The simplest form type of PMI handler is a ForEach handler. Inherit from ForEach and register your class as an invocation event handler to accept PMI requests from clients.

Prerequisites

  • ScaleOut StateServer Pro license

Procedure

  1. Determine the type parameters to use with your ForEach handler.

    • A PMI operation evaluates objects stored in a ScaleOut Cache. Caches in the Scaleout.Client library are strongly-typed, so invocation handlers are also strongly-typed.

    • This example analyzes a cache that tracks the most recent login date for an application's users. The cache's key type is a string (representing a User ID), and its value type is a DateTime (representing a login time).

  2. Create a class that inherits from ForEach<TKey, TValue>.

using System;
using Scaleout.Client;
using Scaleout.Client.MethodInvocation;

class FindInactiveUsers : ForEach<string, DateTime>
{
    public override void Evaluate(string key, OperationContext<string, DateTime> context)
    {
        // ...
    }
}
  1. Implement your custom evaluation code.

    • During a PMI operation, your Evaluate method will be called for every object in the ScaleOut cache.

    • Your method can read, modify, delete, or perform any needed cache operation. In this example, login times are retrieved to identify inactive users.

class FindInactiveUsers : ForEach<string, DateTime>
{
    public override void Evaluate(string key, OperationContext<string, DateTime> context)
    {
        // Use the cache in the PMI context to retrieve the object being evaluated:
        var readResponse = context.Cache.Read(key);
        if (readResponse.Result == ServerResult.NotFound)
        {
            Console.WriteLine($"{key} removed by another client during PMI operation.");
            return;
        }
        else if (readResponse.Result != ServerResult.Retrieved)
        {
            Console.WriteLine($"Unexpected error {readResponse.Result} reading {key}.");
            return;
        }

        // Perform analysis:
        DateTime lastLogin = readResponse.Value;
        TimeSpan inactiveTime = DateTime.UtcNow - lastLogin;
        if (inactiveTime > TimeSpan.FromDays(7))
        {
            Console.WriteLine($"{key} inactive for {inactiveTime.TotalDays} days.");
        }
    }
}
  1. At application startup, register the class as an invocation handler. If you are running your handler in an Invocation Grid, this code should be put in your project's Startup.Configure() method.
class Program
{
    static void Main(string[] args)
    {
        // Connect to the cache that stores login times.
        var conn = GridConnection.Connect("bootstrapGateways=localhost:721");
        var cacheBuilder = new CacheBuilder<string, DateTime>("LoginTimes", conn);
        var cache = cacheBuilder.Build();

        // Register the handler with the cache and give it a name.
        ServiceEvents.SetInvokeHandler(cache, "Find inactive", new FindInactiveUsers());

        // Run indefinitely to handle invocation requests.
        Console.ReadLine();
    }
}
Tip

A PMI application can have multiple invocation handlers registered against multiple caches.

  1. Build your handler application and deploy it to all the servers in your farm that are running the ScaleOut service.

Result

Once your handler app is running on all your ScaleOut hosts, you are ready to process PMI requests.