Skip to content

Commit

Permalink
Add KeepAlive attribute details (#36843)
Browse files Browse the repository at this point in the history
* Touch ms.date

* Edit pass

* Add keep alive bits

* Minor cleanup

* Fix misplaced backtick
  • Loading branch information
IEvangelist authored Aug 29, 2023
1 parent 9fbfdab commit 28ca719
Showing 1 changed file with 52 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: Activation garbage collection
description: Learn about activation garbage collection in .NET Orleans.
ms.date: 05/22/2023
ms.date: 08/25/2023
---

# Activation garbage collection
Expand All @@ -10,11 +10,11 @@ This article applies to: ✔️ Orleans 3.x and earlier versions

A *grain activation* is an in-memory instance of a grain class that gets automatically created by the Orleans runtime on an as-needed basis as a temporary physical embodiment of a grain.

Activation Garbage Collection (Activation GC) is the process of removal from memory of unused grain activations. It is conceptually similar to how garbage collection of memory works in .NET. However, Activation GC only takes into consideration how long a particular grain activation has been idle. Memory usage is not used as a factor.
Activation Garbage Collection (Activation GC) is the process of removal from memory of unused grain activations. It's conceptually similar to how garbage collection of memory works in .NET. However, Activation GC only takes into consideration how long a particular grain activation has been idle. Memory usage isn't used as a factor.

## How activation GC works

The general process of Activation GC involves Orleans runtime in a silo periodically scanning for grain activations that have not been used at all for the configured period (Collection Age Limit). Once a grain activation has been idle for that long, it gets deactivated. The deactivation process begins by the runtime calling the grain's <xref:Orleans.Grain.OnDeactivateAsync> method, and completes by removing references to the grain activation object from all data structures of the silo, so that the memory is reclaimed by the .NET GC.
The general process of Activation GC involves Orleans runtime in a silo periodically scanning for grain activations that haven't been used at all for the configured period (Collection Age Limit). Once a grain activation has been idle for that long, it gets deactivated. The deactivation process begins by the runtime calling the grain's <xref:Orleans.Grain.OnDeactivateAsync> method, and completes by removing references to the grain activation object from all data structures of the silo, so that the memory is reclaimed by the .NET GC.

As a result, with no burden put on the application code, only recently used grain activations stay in memory while activations that aren't used anymore get automatically removed, and system resources used by them get reclaimed by the runtime.

Expand Down Expand Up @@ -44,33 +44,33 @@ A grain activation can delay its own Activation GC, by calling <xref:Orleans.Gra
protected void DelayDeactivation(TimeSpan timeSpan)
```

This call will ensure that this activation is not deactivated for at least the specified time duration. It takes priority over Activation Garbage Collection settings specified in the config, but does not cancel them. Therefore, this call provides an additional hook to **delay the deactivation beyond what is specified in the Activation Garbage Collection settings**. This call can not be used to expedite Activation Garbage Collection.
This call ensures that this activation isn't deactivated for at least the specified time duration. It takes priority over Activation Garbage Collection settings specified in the config, but doesn't cancel them. Therefore, this call provides another hook to **delay the deactivation beyond what is specified in the Activation Garbage Collection settings**. This call can't be used to expedite Activation Garbage Collection.

A positive `timeSpan` value means "prevent GC of this activation for that time".
A positive `timeSpan` value means "prevent GC of this activation for that time."

A negative `timeSpan` value means "cancel the previous setting of the `DelayDeactivation` call and make this activation behave based on the regular Activation Garbage Collection settings".
A negative `timeSpan` value means "cancel the previous setting of the `DelayDeactivation` call and make this activation behave based on the regular Activation Garbage Collection settings."

**Scenarios:**

1. Activation Garbage Collection settings specify an age limit of 10 minutes and the grain is making a call to `DelayDeactivation(TimeSpan.FromMinutes(20))`, it will cause this activation to not be collected for at least 20 min.
1. Activation Garbage Collection settings specify an age limit of 10 minutes and the grain is making a call to `DelayDeactivation(TimeSpan.FromMinutes(20))`, which causes this activation to not be collected for at least 20 min.

1. Activation Garbage Collection settings specify an age limit of 10 minutes and the grain is making a call to `DelayDeactivation(TimeSpan.FromMinutes(5))`, the activation will be collected after 10 min, if no extra calls were made.

1. Activation Garbage Collection settings specify an age limit of 10 minutes and the grain is making a call to `DelayDeactivation(TimeSpan.FromMinutes(5))`, and after 7 minutes there is another call on this grain, the activation will be collected after 17 min from time zero, if no extra calls were made.
1. Activation Garbage Collection settings specify an age limit of 10 minutes and the grain is making a call to `DelayDeactivation(TimeSpan.FromMinutes(5))`, and after 7 minutes there's another call on this grain, the activation will be collected after 17 min from time zero if no extra calls were made.

1. Activation Garbage Collection settings specify an age limit of 10 minutes and the grain is making a call to `DelayDeactivation(TimeSpan.FromMinutes(20))`, and after 7 minutes there is another call on this grain, the activation will be collected after 20 min from time zero, if no extra calls were made.
1. Activation Garbage Collection settings specify an age limit of 10 minutes and the grain is making a call to `DelayDeactivation(TimeSpan.FromMinutes(20))`, and after 7 minutes there's another call on this grain, the activation will be collected after 20 min from time zero if no extra calls were made.

Note that `DelayDeactivation` does not 100% guarantee that the grain activation will not get deactivated before the specified time expires. Certain failure cases may cause 'premature' deactivation of grains. That means that `DelayDeactivation` **can not be used as a means to 'pin' a grain activation in memory forever or to a specific silo**. `DelayDeactivation` is merely an optimization mechanism that can help reduce the aggregate cost of a grain getting deactivated and reactivated over time, if that matters. In most cases, there should be no need to use `DelayDeactivation` at all.
The `DelayDeactivation` doesn't 100% guarantee that the grain activation won't be deactivated before the specified time expires. Certain failure cases may cause 'premature' deactivation of grains. That means that `DelayDeactivation` **can not be used as a means to 'pin' a grain activation in memory forever or to a specific silo**. `DelayDeactivation` is merely an optimization mechanism that can help reduce the aggregate cost of a grain getting deactivated and reactivated over time. In most cases, there should be no need to use `DelayDeactivation` at all.

### Expedite activation GC

A grain activation can also instruct the runtime to deactivate it next time it becomes idle by calling <xref:Orleans.Grain.DeactivateOnIdle> method:
A grain activation can also instruct the runtime to deactivate it the next time it becomes idle by calling <xref:Orleans.Grain.DeactivateOnIdle> method:

```csharp
protected void DeactivateOnIdle()
```

A grain activation is considered idle if it is not processing any message at the moment. If you call `DeactivateOnIdle` while a grain is processing a message, it will get deactivated as soon as the processing of the current message is finished. If there are any requests queued for the grain, they will be forwarded to the next activation.
A grain activation is considered idle if it isn't processing any message at the moment. If you call `DeactivateOnIdle` while a grain is processing a message, it gets deactivated as soon as the processing of the current message is finished. If there are any requests queued for the grain, they'll be forwarded to the next activation.

`DeactivateOnIdle` takes priority over any Activation Garbage Collection settings specified in the config or `DelayDeactivation`.

Expand All @@ -92,3 +92,43 @@ mySiloHostBuilder.Configure<GrainCollectionOptions>(options =>
TimeSpan.FromMinutes(5);
})
```

## Keep alive

To keep a grain alive, you apply the <xref:Orleans.KeepAliveAttribute?displayProperty=fullName> to the grain implementation. The `KeepAlive` attribute instructs the Orleans runtime to avoid collecting the grain by the idle activation collector. Avoiding collection is useful for grains that are used infrequently but that you want to keep alive to avoid any potential creation overhead.

```csharp
public interface IPlayerGrain : IGrainWithGuidKey
{
Task<IGameGrain> GetCurrentGame();
Task JoinGame(IGameGrain game);
Task LeaveGame(IGameGrain game);
}

[KeepAlive]
public class PlayerGrain : Grain, IPlayerGrain
{
private IGameGrain _currentGame;

public Task<IGameGrain> GetCurrentGame()
{
return Task.FromResult(_currentGame);
}

public Task JoinGame(IGameGrain game)
{
// Omitted for brevity.
return Task.CompletedTask;
}

public Task LeaveGame(IGameGrain game)
{
// Omitted for brevity.
return Task.CompletedTask;
}
}
```

The preceding code prevents the idle activation collector from collecting the `PlayerGrain`.

0 comments on commit 28ca719

Please sign in to comment.