Creating a Message Module Project

Use the msgmodule project template to create a Message Module project.

Background

In this example, we will use the ScaleOut Message Module Package template to create and customize a custom module that implements an airline flight. The message processor in a message module is responsible for persisting, analyzing, and reacting to incoming messages and updating the state of a flight object stored in the ScaleOut StateServer cluster.

Prerequisites

Procedure

1. Create a message module project

In Visual Studio’s New Project dialog, select the ScaleOut Message Module Package project type and name it Flight.

If you are using Linux (or you prefer using the command line to create your project), run the following command to create a project based on the template:

dotnet new msgmodule -n Flight

A new directory called “Flight” will be created under your current directory that contains the project files.

2. Customize state object

Customize the SOSS object used to store data for your module. A skeleton class named “FlightSossObject” was precreated by the template and must be modified to hold state for the module (in this case, information about the flight). Instances of this object will be stored in the ScaleOut StateServer cluster.

namespace Flight
{
    public record Passenger(string FirstName, string LastName);

    /// <summary>
    /// Define any state for the module here. This class defines the objects
    /// stored in the ScaleOut StateServer (SOSS) service that hold state for the 
    /// messaging module.
    /// </summary>
    public class FlightSossObject
    {
        public required string Id { get; init; }

        public DateTime Arrival { get; set; }

        public required List<Passenger> Passengers { get; init; }
    }
}
  • SOSS objects should also contain a string property named Id. While not strictly required, the Id property is used by the ScaleOut Active Caching UI to identify objects in the cluster.

3. Implement the CreateObject() method

Implement the CreateObject method in your message handler class. A skeleton class named “FlightMessageHandler” was precreated by the project template, and its CreateObject() method must be implemented. This method is called when a message arrives and the associated SOSS flight object does not yet exist.

/// <summary>
/// Factory method to create a new instance of a flight for this module.
/// </summary>
/// <param name="objectId">ID of the object in the ScaleOut service.</param>
/// <param name="moduleName">Name of your messaging module</param>
/// <returns>CreateResult instance, containing your object and its expiration policy.</returns>
public override CreateResult<FlightSossObject> CreateObject(string objectId, string moduleName)
{
    return new CreateResult<FlightSossObject>
    {
        Value = new FlightSossObject
        {
            Id = objectId,
            Arrival = DateTime.MinValue,
            Passengers = new List<Passenger>()
        },
        Expiration = TimeSpan.Zero, // No expiration
        ExpirationType = ExpirationType.Sliding
    };
}
  • The CreateResult instance returned by the CreateObject() method should have the following three properties set:

    • Value: The newly created SOSS object (in this case, a freshly-initialized flight object).

    • Expiration: A TimeSpan indicating how long the object should be kept in the cluster before being automatically removed.

    • ExpirationType: An enum value indicating the expiration behavior for the object. Set to Sliding to reset the expiration every time the SossObject is accessed, or Absolute to keep it for a fixed duration.

4. Define the message type

In your project’s Messages project, rename the ExampleMessage class to ArrivalTimeMessage, and modify it to contain arrival time information:

namespace Flight
{
    public class ArrivalTimeMessage
    {
        public DateTime NewArrival { get; set; }
    }
}

Note

See Using Multiple Message Types if you need to send more than one message type to your message processor.

5. Implement ProcessMessageAsync() method

The message handler’s ProcessMessageAsync() method is responsible for persisting, analyzing, and reacting to incoming messages. This method typically deserializes the message and then modifies the associated SOSS object.

/// <summary>
/// Processes a message sent to an object in the ScaleOut service.
/// </summary>
/// <param name="context">The processing context for the operation.</param>
/// <param name="sossObject">The SOSS flight object associated with the message.</param>
/// <param name="msgBytes">The raw message data as a byte array.</param>
/// <returns>A ProcessingResult representing the outcome of the message processing.</returns>
public override Task<ProcessingResult> ProcessMessageAsync(MessageProcessingContext<FlightSossObject> context,
                                                           FlightSossObject sossObject,
                                                           byte[] msgBytes)
{
    ArrivalTimeMessage? message = System.Text.Json.JsonSerializer.Deserialize<ArrivalTimeMessage>(msgBytes);
    if (message is null)
        return Task.FromResult(ProcessingResult.NoUpdate);

    // Update the SOSS object with the message data.
    sossObject.Arrival = message.NewArrival;

    // The SOSS object was modified, so we return DoUpdate to indicate that
    // it should be updated in the ScaleOut service.
    return Task.FromResult(ProcessingResult.DoUpdate);
}
  • The ProcessMessageAsync() method is supplied with a context argument, which is a MessageProcessingContext object that can be used to send messages to other objects in the ScaleOut cluster or raise an alert in the ScaleOut Active Caching UI.

  • A ProcessingResult enum value must be returned. This value indicates what should be done with the flight object in the ScaleOut service after the ProcessMessageAsync() method returns:

    • 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 associated SossObject from the ScaleOut cluster.

6. Publish the project

In Visual Studio, right-click on the Flight project in Visual Studio’s solution explorer and select “Publish”. The publishing window will allow you to select from several predefined targets (Windows vs. Linux). Click the “Publish” button to create a zipped deployment package.

Use the ScaleOut Active Caching UI to upload the package and manage your deployment. Once deployed, your package will run as a worker process on every host in the ScaleOut StateServer cluster.