DEV Community

Wesley Skeen
Wesley Skeen

Posted on • Updated on

F# Orleans reminder grain

This is a simple example of how we set up reminder grains in Orleans and f#.

Here's the code so you can follow along

Grain interface

type IYourReminderGrain =
    inherit IGrainWithStringKey
    inherit IRemindable

    abstract member WakeUp : unit -> Task
Enter fullscreen mode Exit fullscreen mode

We have 2 important parts here that will be implemented in the grain.

  • IRemindable: This forces us to implement the ReceiveReminder function. This is where the logic we want to execute each time the reminder gets triggered.
  • WakeUp : This activates the grain so we can set up the reminder

Grain implementation

type YourReminderGrain() =
    inherit Grain()
    interface IYourReminderGrain with
        member this.WakeUp() = Task.CompletedTask
        member this.ReceiveReminder(reminderName, status) =
            Console.WriteLine(reminderName, status)
            Task.CompletedTask

    override _.OnActivateAsync(cancellationToken:CancellationToken) = 
        let _periodInSeconds = TimeSpan.FromSeconds 60
        let _dueInSeconds = TimeSpan.FromSeconds 60
        let _reminder = base.RegisterOrUpdateReminder(base.GetPrimaryKeyString(), _dueInSeconds, _periodInSeconds)
        base.OnActivateAsync(cancellationToken)
Enter fullscreen mode Exit fullscreen mode

There are 2 important parts here

  • Implement the IYourReminderGrain : The WakeUp is simple as we do not want to do anything here. ReceiveReminder contains our logic. What we want to execute on every trigger of the reminder. Here we are simply writing the reminder name to the console.
  • Overriding OnActivateAsync : This is where we register the reminder and specify at what interval it should trigger at. _periodInSeconds specifies the time between triggers and _dueInSeconds specifies how long to wait until the first trigger

Kicking off the reminder grain

In this example I do this by adding a hosted service GrainActivatorHostedService.

This is responsible for retrieving the reminder grain from the IGrainFctory and calling the WakeUp grain function

let! _ =
    _client
        .GetGrain<IYourReminderGrain>(Guid.NewGuid().ToString())
                    .WakeUp() 
Enter fullscreen mode Exit fullscreen mode

That's it. To run the app just run

> sh run-silo-local.sh
or
> sh run-silo-docker.sh
Enter fullscreen mode Exit fullscreen mode

You can also run it in your IDE or VS Code devcontainers

To verify everything is working correctly:

This is part of the road-to-orleans project. Check it out

GitHub logo PiotrJustyna / road-to-orleans

This repository illustrates the road to orleans with practical, real-life examples. From most basic, to more advanced techniques.

road to orleans

Gitter

This repository illustrates the road to orleans with practical, real-life examples such as .NET solutions. From most basic to more advanced techniques. The code is written using .NET 6 and was tested on macOS (Catalina 10.15.7) and, wherever docker is supported, Linux (Alpine 3.12).

build & run

  • IDE: build + run (first the cluster, then the client)
  • run-[client/silo]-[docker/local].sh

monitoring

Silo dashboards are available by default on localhost:8080 unless configured otherwise in the code/dockerfile/run-[client/silo]-[docker/local].sh. Additionally, Datadog APM support is illustrated in solution 3b.

code

flowchart TD
Solution1(Solution1: One basic silo, no grains.)
Solution2(Solution2: One basic silo, one grain, one console client.)
Solution3(Solution3: One basic silo, one grain, one console client, <br/>everything containerized.)
Solution3a(Solution3a: Solution3 + grain persistence.)
Solution3b(Solution3b: Solution3 + datadog APM.)
Solution4(Solution4: First in-memory clustering example. <br/>Many silos, many clients.)
Solution5(Solution5: Solution4 where

Top comments (0)