Table of Contents

Using Parameters in PMI

Inherit from the ForEachWithParam or ReduceWithParam base classes to implement an invocation handler that accepts a parameter value from a client.

Procedure

  1. Create a new class to process the PMI operation, supplying the appropriate type parameters to the base invocation handler class.

    • In addition to the TKey and TValue that a ForEach or Reduce handler uses, a parameterized handler requires a TParam to indicate the parameter type.

    • 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). The invocation handler uses a TimeSpan as its parameter type (representing a threshold for inactive users).

    using System;
    using Scaleout.Client;
    using Scaleout.Client.MethodInvocation;
    
    class FindInactiveUsersByTime : ForEachWithParam<string, DateTime, TimeSpan>
    {
        public override TimeSpan DeserializeParam(byte[] paramBytes)
        {
            // ...
        }
    
        public override void Evaluate(string key, 
                                      TimeSpan param, 
                                      OperationContext<string, DateTime> context)
        {
            // ...
        }
    
    }	
    
  2. Implement deserialization of the parameter.

    • Clients that execute a PMI operation will supply a serialized parameter to the handler through the Cache.Invoke call. A parameterized invocation handler must override the abstract DeserializeParam method to convert it to the expected TParam type.
    public override TimeSpan DeserializeParam(byte[] paramBytes)
    {
        // Convert byte[] to TimeSpan.
    
        if (paramBytes?.Length != sizeof(long))
            throw new ArgumentException("Expecting 8-byte parameter");
    
        long ticks = BitConverter.ToInt64(paramBytes, startIndex: 0);
        return new TimeSpan(ticks);
    }
    
  3. Implement your custom evaluation code. The deserialized parameter value is supplied to your Evaluate method.

    public override void Evaluate(string key, 
                                  TimeSpan param, 
                                  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 result {readResponse.Result} reading {key}.");
            return;
        }
    
        // Perform analysis using the parameter:
        DateTime lastLogin = readResponse.Value;
        TimeSpan inactiveTime = DateTime.UtcNow - lastLogin;
        if (inactiveTime > param)
        {
            Console.WriteLine($"{key} has been inactive for {inactiveTime.TotalDays} days.");
        }
    }
    
  4. At application startup, register the class as an invocation handler.

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 by time", 
										 new FindInactiveUsersByTime());

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

If you are running your handler in an Invocation Grid, this code should be put in your project's Startup.Configure() method.

  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.