A lil' helper library for Service Fabric actor's reminders.
It adds two things we found ourselves implementing over and over again:
-
Safe unregistering of reminders
No more try/catch blocks! Huzzah!
-
Single-use reminders
You're meant to unregister reminders, even if you're using the fire-once approach (
dueTime: TimeSpan.FromMilliseconds(-1)
). This makes that process automatic withPromptOnce
. This is currently listed as a functional bug, but this will get you around it. -
Correlation IDs
We use found it super useful to have an ID we could track across all of our services. This let's you track a GUID across reminders.
internal sealed class OrderActor : PromptableActor, IOrderActor
{
public async Task PlaceOrder(OrderRequest req)
{
// Some internal logic, whatever
var token = await SetOrderState(req);
// Register a prompt to come back in seven days
await PromptOnce(token, TimeSpan.FromDays(7));
}
protected override async Task OnPrompt(string name, byte[] context, TimeSpan due, TimeSpan period, Guid cid)
{
var token = name;
var order = await GetOrderState(name);
await SendEmailReminder(order);
}
}
Install it from NuGet (Install-Package Prompter
) and use one of the two options for integration.
internal sealed class MyActor : PromptableActor, IMyActor { }
Setup a callback:
private Task OnPrompt(string name, byte[] context, TimeSpan due, TimeSpan period, Guid cid)
{
// Do stuff
}
then add it to your actor's constructor:
private readonly Prompt _prompt;
public ActorFixture(ActorService svc, ActorId id)
: base(svc, id)
{
_prompt = new Prompt(
OnPrompt,
GetReminder,
RegisterReminderAsync,
UnregisterReminderAsync,
this);
}
and link the reminder callback to Prompter:
public Task ReceiveReminderAsync(string reminderName, byte[] state, TimeSpan dueTime, TimeSpan period) =>
_prompt.ReceivePrompt(reminderName, state, dueTime, period);
It's awful, isn't it? I couldn't figure out a nicer way layer it on but I'm open to suggestions. (We have a bunch of these 'traits' we wanted to use and didn't like the idea of bundling them all into one base class.)
You should be logging everything like crazy, so I chucked in logs here too.
That's why you (should) pass in the current actor when constructing Prompt
.
(I don't do anything else with it, I swear!)
The provider is Prompter-Prompt
and it logs registers, unregisters and receives.