dotnet/orleans (Microsoft.Orleans.Client)
### [`v8.2.0`](https://redirect.github.com/dotnet/orleans/releases/tag/v8.2.0)
##### New features
##### Activation repartitioning
[!Activation Repartitioning in action](https://redirect.github.com/user-attachments/assets/d12764e9-ec04-433d-bff1-cdb33b3c1b1f)
> Above: a demonstration showing Activation Repartitioning in action. The red lines represent cross-silo communication. As the red lines are eliminated by the partitioning algorithm, throughput improves to over 2x the initial throughput.
[Ledjon Behluli](https://redirect.github.com/ledjon-behluli) and [@ReubenBond](https://redirect.github.com/ReubenBond) implemented **activation repartitioning** in [#8877](https://redirect.github.com/dotnet/orleans/pull/8877). When enabled, **activation repartitioning** collocates grains based on observed communication patterns to improve performance while keeping load balanced across your cluster. In initial benchmarks, we observe throughput improvements in the range of 30% to 110%. The following paragraphs provide more background and implementation details for those who are interested. The feature is currently *experimental* and to enable it you need to opt-in on every silo in your cluster using the `ISiloBuilder.AddActivationRepartitioner()` extension method, suppressing the experimental feature warning:
```csharp
#pragma warning disable ORLEANSEXP001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
siloBuilder.AddActivationRepartitioner();
#pragma warning restore ORLEANSEXP001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
```
The fastest and cheapest grains calls are ones which don't cross process boundaries. These grain calls do not need to be serialized and do not need to incur network transmission costs. For that reason, collocating related grains within the same host can significantly improve the performance of your application. On the other hand, if all grains were placed in a single host, that host may become overloaded and crash, and you would not be able to scale your application across multiple hosts. How can we maximize collocation of related grains while keeping load across your hosts balanced? Before describing our solution, we need to provide some background.
[Grain placement in Orleans](https://learn.microsoft.com/dotnet/orleans/grains/grain-placement) is flexible: Orleans executes a user-defined function when deciding where in a cluster to place each grain, providing your function with a list of the compatible silos in your cluster, that is, the silos which support the grain type and interface version which triggered placement. Grains calls are *location-transparent*, so callers do not need to know where a grain is located, allowing grains to be placed anywhere across your cluster of hosts. Each grain's current location is stored in a [distributed directory](https://learn.microsoft.com/dotnet/orleans/host/grain-directory) and lookups to the directory are cached for performance.
[**Resource-optimized placement**](https://learn.microsoft.com/dotnet/orleans/grains/grain-placement#resource-optimized-placement) was implemented by [@ledjon-behluli](https://redirect.github.com/ledjon-behluli) in [#8815](https://redirect.github.com/dotnet/orleans/pull/8815). Resource-optimized placement uses runtime statistics such as total and available memory, CPU usage, and grain count, collected from all hosts in the cluster, smooths them, and combines them to calculate a load score. It selects the least-loaded silo from a subset of hosts to balance load evenly across the cluster\[^4]. If the load score of the local silo is within some configured range of the best candidate's load score, the local silo is chosen preferentially. This improves grain locality by leveraging the knowledge that the local silo initiated a call to the grain and therefore has some relation to that grain.
Ledjon wrote more about Resource-optimized placement in [this blog post](https://www.ledjonbehluli.com/posts/orleans_resource_placement_kalman/).
Originally, there was no straightforward way to move an active grain from one host to another without needing to fully deactivate the grain, unregister it from the grain directory, contend with concurrent callers on where to place the new activation, and reload its state from the database when the new activation is created. [**Live grain migration** was introduced in #8452](https://redirect.github.com/dotnet/orleans/pull/8452), allowing grains to transparently migrate from one silo to another on-demand without needing to reload state from the database, and without affecting pending requests. **Live grain migration** introduced two new lifecycle stages: *dehydration* and *rehydration*. The grain's in-memory state (application state, enqueued messages, metadata) is dehydrated into a migration packet which is sent to the destination silo where it's rehydrated. Live grain migration provided the mechanism for grains to migrate across hosts, but did not provide any out-of-the-box policies to automate migration. Users trigger grain migration by calling `this.MigrateOnIdle()` from within a grain, optionally providing a placement hint which the grain's configured placement director can use to select a destination host for the grain activation.
Finally, we have the pieces in place for **activation repartitioning**: grain activations are load-balanced across the cluster, and they are able to migrate from host to host quickly. While **live grain migration** gives developers a mechanism to migrate grain activations from one host to another, it does not provide any automated *policy* to do so. Remember, we want grains to be balanced across the cluster and collocated with related grains to reduce networking and serialization cost. This is a difficult challenge since:
- An application can have millions of in-memory grains spread across tens or hundreds of silos.
- Each grain can message any other grain.
- The set of grains which each grain communicates with can change from minute to minute. For example, in an online game, player grains may join one match and communicate with each other for some time and then join a different match with an entirely different set of players afterwards.
- Computing the [minimum edge-cut](https://en.wikipedia.org/wiki/Minimum_cut) for an arbitrary graph is [NP-hard](https://en.wikipedia.org/wiki/NP-hardness).
- No single host has full knowledge of which grains are hosted on which other host and which grains they communicate with: the graph is distributed across the cluster and changes dynamically.
- Storing the entire communication graph in memory could be prohibitively expensive.
Folks at Microsoft Research studied this problem and proposed a solution in a paper titled [Optimizing Distributed Actor Systems for Dynamic Interactive Services](https://www.microsoft.com/research/publication/optimizing-distributed-actor-systems-for-dynamic-interactive-services/). The paper, dubbed *ActOp*, proposes a decentralized approximate solution which achieves good results in their benchmarks. Their implementation was never merged into Orleans and we were unable to find the original implementation on Microsoft's internal network. So, after first implementing **resource-optimized placement**, community contributor [@ledjon-behluli](https://redirect.github.com/ledjon-behluli) set out to implement **activation repartitioning** from scratch based on the ActOp paper. The following paragraphs describe the algorithm and the enhancements we made along the way.
The **activation repartitioning** algorithm involves pair-wise exchange of grains between two hosts at a time. Silos compute a candidate set of grains to send to a peer, then the peer does similarly, and uses a greedy algorithm to determine a final exchange set which minimizes cost while keeping silos balanced.
To compute the candidate sets, silos track which grains communicate with which other grains and how frequently. The whole graph would be unwieldy, so we only maintain the top-K communication edges using a variant of the *Space-Saving*\[^1] algorithm. Messages are sampled via a [multi-producer, single consumer ring buffer](https://redirect.github.com/dotnet/orleans/blob/92e0bf37048cd8e6c728fba008fd4cfbbd647435/src/Orleans.Runtime/Utilities/StripedMpscBuffer.cs) which drops messages if the partition is full. They are then processed by a single thread, which yields frequently to give other threads CPU time. When the distribution has low skew and the K parameter is fairly small, *Space-Saving* can require a lot of costly shuffling at the bottom of its max-heap (we use the heap variant to reduce memory). To address this, we use *Filtered Space-Saving*\[^2] instead of *Space-Saving*. *Filtered Space-Saving* involves putting a 'sketch' data structure at the bottom of the max heap for the lower end of the distribution, which can greatly reduce churn at the bottom and improve performance by up to ~2x in our tests.
If the top-K communication edges are all internal (eg, because the algorithm has already optimized partitioning somewhat), silos won't find many good transfer candidates. We need to track internal edges to work out which grains should/shouldn't be transferred (cost vs benefit). To address this, we introduced a bloom filter to track grains where the cost of movement is greater than the benefit, removing them from the top-K data structure. From our experiments, this works very well with even a 10x smaller *K*. This performance improvement will come with a reduced ability to handle dynamic graphs, so in the future we may need to implement a decay strategy to address this as the bloom filter becomes saturated. To improve lookup performance, [@ledjon-behluli](https://redirect.github.com/ledjon-behluli) implemented a [blocked bloom filter](https://redirect.github.com/dotnet/orleans/blob/92e0bf37048cd8e6c728fba008fd4cfbbd647435/src/Orleans.Runtime/Placement/Repartitioning/BlockedBloomFilter.cs)\[^3], which is used instead of a classic bloom filter.
\[^1]: [*Efficient Computation of Frequent and Top-k Elements in Data Streams* by Metwally, Agrawal, and Abbadi](https://www.cs.emory.edu/~cheung/Courses/585/Syllabus/papers/Frequency-count/2005-Metwally-Top-k-elements.pdf)
\[^2]: [*Finding top-k elements in data streams* by Nuno Homem & Joao Paulo Carvalho](https://www.hlt.inesc-id.pt/~fmmb/references/misnis.ref0a.pdf)
\[^3]: [*Cache-, Hash- and Space-Efficient Bloom Filters* by Felix Putze, Peter Sanders and Johannes Single](https://www.cs.amherst.edu/~ccmcgeoch/cs34/papers/cacheefficientbloomfilters-jea.pdf)
\[^4]: [The Power of Two Choices in Randomized Load Balancing by Michael David Mitzenmacher](https://www.eecs.harvard.edu/~michaelm/postscripts/mythesis.pdf)
##### Enhancements to grain timers
Orleans v8.2.0 introduces a new API, `RegisterGrainTimer`, for managing [grain timers](https://learn.microsoft.com/dotnet/orleans/grains/timers-and-reminders#timers). For compatibility, the existing `RegisterTimer` API is still available, but it is marked `[Obsolete]` and developers should migrate to the new grain timer API, `RegisterGrainTimer`.
Grain timers have been a common source of confusion for new and experienced developers because grain timer callbacks can execute concurrently with other grain calls, rather than being executed one-by-one like grain calls are. That is, timer callbacks are *interleaving*. With v8.2.0, this issue can be avoided by using the new `RegisterGrainTimer` API. The new API has the following advantages:
- Grain timers can be updated using the `Change(TimeSpan, TimeSpan)` method on the returned `IGrainTimer` instance.
- Callbacks do not interleave by default. Interleaving can be enabled by setting `Interleave` to `true` on `GrainTimerCreationOptions`.
- Callbacks can keep the grain active, preventing it from being collected if the timer period is relatively short. This can be enabled by setting `KeepAlive` to `true` on `GrainTimerCreationOptions`.
- Callbacks can receive a `CancellationToken` which is canceled when the timer is disposed or the grain starts to deactivate.
- Callbacks can dispose the grain timer which fired them.
- Callbacks are now subject to grain call filters.
- Callbacks are visible in distributed tracing, when distributed tracing is enabled.
- POCO grains (grain classes which do not inherit from `Grain`) can register grain timers using the `RegisterGrainTimer` extension method.
The core API is as-follows:
```csharp
public static IGrainTimer RegisterGrainTimer(this IGrainBase grain, Func callback, TState state, GrainTimerCreationOptions options);
```
There are various overloads for convenience:
```csharp
public static IGrainTimer RegisterGrainTimer(this IGrainBase grain, Func callback, TState state, GrainTimerCreationOptions options);
public static IGrainTimer RegisterGrainTimer(this IGrainBase grain, Func callback, GrainTimerCreationOptions options);
public static IGrainTimer RegisterGrainTimer(this IGrainBase grain, Func callback, GrainTimerCreationOptions options);
public static IGrainTimer RegisterGrainTimer(this IGrainBase grain, Func callback, TState state, GrainTimerCreationOptions options);
public static IGrainTimer RegisterGrainTimer(this IGrainBase grain, Func callback, TimeSpan dueTime, TimeSpan period);
public static IGrainTimer RegisterGrainTimer(this IGrainBase grain, Func callback, TimeSpan dueTime, TimeSpan period);
public static IGrainTimer RegisterGrainTimer(this IGrainBase grain, Func callback, TState state, TimeSpan dueTime, TimeSpan period);
public static IGrainTimer RegisterGrainTimer(this IGrainBase grain, Func callback, TState state, TimeSpan dueTime, TimeSpan period);
```
The `RegisterGrainTimer` API returns instances of `IGrainTimer` instead of `IDisposable`:
```csharp
///
/// Represents a timer belonging to a grain.
///
public interface IGrainTimer : IDisposable
{
/// Changes the start time and the interval between method invocations for a timer, using values to measure time intervals.
///
/// A representing the amount of time to delay before invoking the callback method specified when the was constructed.
/// Specify to prevent the timer from restarting.
/// Specify to restart the timer immediately.
///
///
/// The time interval between invocations of the callback method specified when the timer was constructed.
/// Specify to disable periodic signaling.
///
/// The or parameter, in milliseconds, is less than -1 or greater than 4294967294.
void Change(TimeSpan dueTime, TimeSpan period);
}
```
##### MessagePack serialization support
[@n-sidorov](https://redirect.github.com/n-sidorov) implemented support for serializing messages using [MessagePack](https://redirect.github.com/MessagePack-CSharp/MessagePack-CSharp).
To use MessagePack for message serialization, you will need to install `Microsoft.Orleans.Serialization.MessagePack` by inserting the following into your project files:
```xml
```
Enable MessagePack serialization by calling `ISerializerBuilder.AddMessagePackSerializer()` on your clients and silos:
```csharp
builder.AddSerializer(serializer => serializer.AddMessagePackSerializer());
```
Upon doing so, Orleans will be able to serialize types with the `[MessagePackObject]` attribute, for example:
```csharp
[MessagePackObject]
public sealed record MyMessagePackClass
{
[Key(0)]
public int IntProperty { get; init; }
[Key(1)]
public string StringProperty { get; init; }
[Key(2)]
public MyMessagePackSubClass SubClass { get; init; }
}
```
##### Cassandra clustering provider
[@rkargMsft](https://redirect.github.com/rkargMsft) implemented support for using Cassandra as a backing store for clustering in [https://github.com/dotnet/orleans/pull/8925](https://redirect.github.com/dotnet/orleans/pull/8925).
To use Cassandra for clustering, you will need to install `Microsoft.Orleans.Clustering.Cassandra` by inserting the following into your project files:
```xml
```
On your clients and silos, you can enable Cassandra clustering by calling:
```csharp
builder.UseCassandraClustering(connectionString);
```
##### ADO.NET Streaming Provider (alpha)
[@JorgeCandeias](https://redirect.github.com/JorgeCandeias) implemented an ADO.NET streams provider in [https://github.com/dotnet/orleans/pull/8974](https://redirect.github.com/dotnet/orleans/pull/8974).
ADO.NET streaming is currently an *alpha* version. You can add it to your project files like so:
```xml
```
Configure ADO.NET streaming like so:
```csharp
builder.AddAdoNetStreams("provider name", options =>
{
options.Invariant = "ADO.NET invariant name";
options.ConnectionString = "Connection string";
});
```
##### What's Changed
- Fix potential grain timer deadlock during disposal by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8950](https://redirect.github.com/dotnet/orleans/pull/8950)
- Add missing description node to XML docs by [@scottaddie](https://redirect.github.com/scottaddie) in [https://github.com/dotnet/orleans/pull/8959](https://redirect.github.com/dotnet/orleans/pull/8959)
- Clean up `SafeTimer` usage, replace with `PeriodicTimer` where possible by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8953](https://redirect.github.com/dotnet/orleans/pull/8953)
- Fix capitalization of 'MachineName' structured logging parameter by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8980](https://redirect.github.com/dotnet/orleans/pull/8980)
- Ensure PeriodicTimer period >= 1ms by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8981](https://redirect.github.com/dotnet/orleans/pull/8981)
- Ensure reminder table is initialized before access by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8982](https://redirect.github.com/dotnet/orleans/pull/8982)
- Update Npgsql by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8994](https://redirect.github.com/dotnet/orleans/pull/8994)
- Fix serialization of types inheriting from `Dictionary` which add values in their constructor by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8993](https://redirect.github.com/dotnet/orleans/pull/8993)
- Prevent generated types from appearing in IDE by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8987](https://redirect.github.com/dotnet/orleans/pull/8987)
- Use dotnet-public instead of nuget.org by [@benjaminpetit](https://redirect.github.com/benjaminpetit) in [https://github.com/dotnet/orleans/pull/8931](https://redirect.github.com/dotnet/orleans/pull/8931)
- Add Orleans.Runtime to implicit usings by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8996](https://redirect.github.com/dotnet/orleans/pull/8996)
- Stop watchdog when container is disposed by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8998](https://redirect.github.com/dotnet/orleans/pull/8998)
- Stop silo on Dispose by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/9000](https://redirect.github.com/dotnet/orleans/pull/9000)
- Dispose all activations when host is disposed by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/9001](https://redirect.github.com/dotnet/orleans/pull/9001)
- Dispose cluster & silo health monitors are disposed when host is disposed, and clean up code by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8999](https://redirect.github.com/dotnet/orleans/pull/8999)
- Unsubscribe `ConsistentRingProvider` & `VirtualBucketsRingProvider` from `ISiloStatusOracle` on shutdown by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8997](https://redirect.github.com/dotnet/orleans/pull/8997)
- Avoid unnecessary `Interlocked.Or` in `SingleWaiterAutoResetEvent` by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/9003](https://redirect.github.com/dotnet/orleans/pull/9003)
- test(codegen): add derived from list by [@claylaut](https://redirect.github.com/claylaut) in [https://github.com/dotnet/orleans/pull/8858](https://redirect.github.com/dotnet/orleans/pull/8858)
- Add serialization support for types derived from `List` and `HashSet` by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/9005](https://redirect.github.com/dotnet/orleans/pull/9005)
- Use `PeriodicTimer` instead of `GrainTimer` in `LeaseBasedQueueBalancer` by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/9002](https://redirect.github.com/dotnet/orleans/pull/9002)
- Updatable grain timers by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8954](https://redirect.github.com/dotnet/orleans/pull/8954)
- Fix streaming config validator registration by [@benjaminpetit](https://redirect.github.com/benjaminpetit) in [https://github.com/dotnet/orleans/pull/8876](https://redirect.github.com/dotnet/orleans/pull/8876)
- Update samples README.md to point to samples repo & explorer by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/9010](https://redirect.github.com/dotnet/orleans/pull/9010)
- \[CodeGen] Always specify grain extension interface for grain extension calls by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/9009](https://redirect.github.com/dotnet/orleans/pull/9009)
- Fix silo shutdown logging when silo is already shutting down. by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/9013](https://redirect.github.com/dotnet/orleans/pull/9013)
- Fix perf of PooledBufferTests by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/9015](https://redirect.github.com/dotnet/orleans/pull/9015)
- Fix termination condition in ActivationMigrationManager.AcceptMigratingGrains by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/9017](https://redirect.github.com/dotnet/orleans/pull/9017)
- Improve `ActivationData` shutdown process by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/9018](https://redirect.github.com/dotnet/orleans/pull/9018)
- Exclude explicitly implemented interface methods from proxy by [@alrz](https://redirect.github.com/alrz) in [https://github.com/dotnet/orleans/pull/8992](https://redirect.github.com/dotnet/orleans/pull/8992)
- Consider interface method accessibility when generating the invoker by [@alrz](https://redirect.github.com/alrz) in [https://github.com/dotnet/orleans/pull/9019](https://redirect.github.com/dotnet/orleans/pull/9019)
- ADO.NET Streaming Provider by [@JorgeCandeias](https://redirect.github.com/JorgeCandeias) in [https://github.com/dotnet/orleans/pull/8974](https://redirect.github.com/dotnet/orleans/pull/8974)
- Brings back support for `StringData` in ATS provider by [@ledjon-behluli](https://redirect.github.com/ledjon-behluli) in [https://github.com/dotnet/orleans/pull/8965](https://redirect.github.com/dotnet/orleans/pull/8965)
- Avoid changing soon-to-be-deprecated RegisterTimer method return type by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/9020](https://redirect.github.com/dotnet/orleans/pull/9020)
- Mark Orleans.Streaming.AdoNet as alpha by [@benjaminpetit](https://redirect.github.com/benjaminpetit) in [https://github.com/dotnet/orleans/pull/9022](https://redirect.github.com/dotnet/orleans/pull/9022)
- Use Entra ID auth in Azure tests when possible by [@benjaminpetit](https://redirect.github.com/benjaminpetit) in [https://github.com/dotnet/orleans/pull/9027](https://redirect.github.com/dotnet/orleans/pull/9027)
- Update Microsoft.Build dependency by [@benjaminpetit](https://redirect.github.com/benjaminpetit) in [https://github.com/dotnet/orleans/pull/9029](https://redirect.github.com/dotnet/orleans/pull/9029)
- Added #pragma warning disable CS1591 to supress warnings in the source generated code by [@m3nax](https://redirect.github.com/m3nax) in [https://github.com/dotnet/orleans/pull/8940](https://redirect.github.com/dotnet/orleans/pull/8940)
- ResourceOptimizedPlacement: normalize `MaxAvailableMemory`, add `ActivationCount` factor by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/9028](https://redirect.github.com/dotnet/orleans/pull/9028)
- Add support to JSON codecs to serialize their generic JSON types by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/9033](https://redirect.github.com/dotnet/orleans/pull/9033)
- Remove Orleans.Streaming.GCP by [@benjaminpetit](https://redirect.github.com/benjaminpetit) in [https://github.com/dotnet/orleans/pull/9031](https://redirect.github.com/dotnet/orleans/pull/9031)
- Allow custom back-off providers for `PersistentStreamPullingAgent` by [@ledjon-behluli](https://redirect.github.com/ledjon-behluli) in [https://github.com/dotnet/orleans/pull/9035](https://redirect.github.com/dotnet/orleans/pull/9035)
- Fix nightly package publishing NuGet path by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/9040](https://redirect.github.com/dotnet/orleans/pull/9040)
- Adds support to use `MayInterleave` with `StatelessWorker` grains by [@ledjon-behluli](https://redirect.github.com/ledjon-behluli) in [https://github.com/dotnet/orleans/pull/9050](https://redirect.github.com/dotnet/orleans/pull/9050)
- Avoid logging error monitoring k8s pods on restart by [@gp-jorge](https://redirect.github.com/gp-jorge) in [https://github.com/dotnet/orleans/pull/9048](https://redirect.github.com/dotnet/orleans/pull/9048)
- Non-reentrant grain timers by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8955](https://redirect.github.com/dotnet/orleans/pull/8955)
- Activation Repartitioning by [@ledjon-behluli](https://redirect.github.com/ledjon-behluli) in [https://github.com/dotnet/orleans/pull/8877](https://redirect.github.com/dotnet/orleans/pull/8877)
- Fix leaking timed-out callbacks in InsideRuntimeClient by [@krasin-ga](https://redirect.github.com/krasin-ga) in [https://github.com/dotnet/orleans/pull/9041](https://redirect.github.com/dotnet/orleans/pull/9041)
- Fix table storage Reminders and GrainDirectory providers registration by [@Costo](https://redirect.github.com/Costo) in [https://github.com/dotnet/orleans/pull/9045](https://redirect.github.com/dotnet/orleans/pull/9045)
- Adding codec to serialize F# Unit by [@gfix](https://redirect.github.com/gfix) in [https://github.com/dotnet/orleans/pull/9039](https://redirect.github.com/dotnet/orleans/pull/9039)
- Cassandra Clustering implementation by [@rkargMsft](https://redirect.github.com/rkargMsft) in [https://github.com/dotnet/orleans/pull/8925](https://redirect.github.com/dotnet/orleans/pull/8925)
- Fix for Recorded flag not propagated between activities by [@Costo](https://redirect.github.com/Costo) in [https://github.com/dotnet/orleans/pull/9016](https://redirect.github.com/dotnet/orleans/pull/9016)
- Support implementing multiple IConverter<,> in single converter class by [@ccorsano](https://redirect.github.com/ccorsano) in [https://github.com/dotnet/orleans/pull/8881](https://redirect.github.com/dotnet/orleans/pull/8881)
- \[Orleans.EventSourcing] Fix double-increment in `RemoveStaleConditionalUpdates` by [@zbarrier](https://redirect.github.com/zbarrier) in [https://github.com/dotnet/orleans/pull/8623](https://redirect.github.com/dotnet/orleans/pull/8623)
- Fix flaky Activation Repartitioning test by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/9058](https://redirect.github.com/dotnet/orleans/pull/9058)
- Implement incoming grain call filters for observers by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/9054](https://redirect.github.com/dotnet/orleans/pull/9054)
- Activation repartitioner: use `null` for no-op message observer to avoid interface call by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/9056](https://redirect.github.com/dotnet/orleans/pull/9056)
- MessagePack codec by [@n-sidorov](https://redirect.github.com/n-sidorov) in [https://github.com/dotnet/orleans/pull/8546](https://redirect.github.com/dotnet/orleans/pull/8546)
- Replace custom `GetHashCode` implementations with `HashCode.Combine` by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/9059](https://redirect.github.com/dotnet/orleans/pull/9059)
- Coordinate shutdown of AdaptiveDirectoryCacheMaintainer with LocalGrainDirectory by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/9061](https://redirect.github.com/dotnet/orleans/pull/9061)
- Promptly terminate AdaptiveDirectoryCacheMaintainer by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/9062](https://redirect.github.com/dotnet/orleans/pull/9062)
- ActivationData: get IGrainActivator from shared components consistently by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/9063](https://redirect.github.com/dotnet/orleans/pull/9063)
- StatelessWorker: pump work item queue consistently by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/9064](https://redirect.github.com/dotnet/orleans/pull/9064)
- Allow GrainTimers to dispose themselves from their own callback by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/9065](https://redirect.github.com/dotnet/orleans/pull/9065)
##### New Contributors
- [@scottaddie](https://redirect.github.com/scottaddie) made their first contribution in [https://github.com/dotnet/orleans/pull/8959](https://redirect.github.com/dotnet/orleans/pull/8959)
- [@alrz](https://redirect.github.com/alrz) made their first contribution in [https://github.com/dotnet/orleans/pull/8992](https://redirect.github.com/dotnet/orleans/pull/8992)
- [@gp-jorge](https://redirect.github.com/gp-jorge) made their first contribution in [https://github.com/dotnet/orleans/pull/9048](https://redirect.github.com/dotnet/orleans/pull/9048)
- [@krasin-ga](https://redirect.github.com/krasin-ga) made their first contribution in [https://github.com/dotnet/orleans/pull/9041](https://redirect.github.com/dotnet/orleans/pull/9041)
- [@rkargMsft](https://redirect.github.com/rkargMsft) made their first contribution in [https://github.com/dotnet/orleans/pull/8925](https://redirect.github.com/dotnet/orleans/pull/8925)
- [@ccorsano](https://redirect.github.com/ccorsano) made their first contribution in [https://github.com/dotnet/orleans/pull/8881](https://redirect.github.com/dotnet/orleans/pull/8881)
- [@zbarrier](https://redirect.github.com/zbarrier) made their first contribution in [https://github.com/dotnet/orleans/pull/8623](https://redirect.github.com/dotnet/orleans/pull/8623)
- [@n-sidorov](https://redirect.github.com/n-sidorov) made their first contribution in [https://github.com/dotnet/orleans/pull/8546](https://redirect.github.com/dotnet/orleans/pull/8546)
**Full Changelog**: https://github.com/dotnet/orleans/compare/v8.1.0...v8.2.0
### [`v8.1.0`](https://redirect.github.com/dotnet/orleans/releases/tag/v8.1.0)
##### New features
##### Integration with Aspire
This release includes initial integration with [.NET Aspire](https://learn.microsoft.com/en-us/dotnet/aspire/get-started/aspire-overview), allowing you to configure an Orleans cluster in your Aspire app host, specifying the resources the cluster uses. For example, you can specify that an Azure Table will be used for cluster membership, an Azure Redis resource will be used for the grain directory, and an Azure Blob Storage resource will be used to store grain state. The integration currently supports Redis and Azure Table & Blob storage resources. Support for other resources will be added later.
In the app host project, an Orleans cluster can be declared using the `AddOrleans` method, and then configured with clustering, grain storage, grain directory, and other providers using methods on the returned builder:
```csharp
var storage = builder.AddAzureStorage("storage");
var clusteringTable = storage.AddTables("clustering");
var defaultStorage = storage.AddBlobs("grainstate");
var cartStorage = builder.AddRedis("redis-cart");
var orleans = builder.AddOrleans("my-app")
.WithClustering(clusteringTable)
.WithGrainStorage("Default", grainStorage)
.WithGrainStorage("cart", cartStorage);
// Add a server project (also called "silo")
builder.AddProject("silo")
.WithReference(orleans);
// Add a project with a reference to the Orleans client
builder.AddProject("frontend")
.WithReference(orleans);
```
In the client and server projects, add Orleans to the host builder as usual.
```csharp
// For an Orleans server:
builder.UseOrleans();
// Or, for an Orleans client:
builder.UseOrleansClient();
```
Orleans will read configuration created by your Aspire app host project and configure the providers specified therein. To allow Orleans to access the configured resources, add them as keyed services using the corresponding Aspire component:
```csharp
builder.AddKeyedAzureTableService("clustering");
builder.AddKeyedAzureBlobService("grainstate");
builder.AddKeyedRedis("redis-cart");
```
##### Resource-optimized placement
Resource-optimized placement, enabled via the `[ResourceOptimizedPlacement]` attribute on a grain class, balances grains across hosts based on available memory and CPU usage. For more details, see the PR: [https://github.com/dotnet/orleans/pull/8815](https://redirect.github.com/dotnet/orleans/pull/8815).
##### What's Changed
##### Since 8.1.0-preview3
- Migrate to build template by [@benjaminpetit](https://redirect.github.com/benjaminpetit) in [https://github.com/dotnet/orleans/pull/8905](https://redirect.github.com/dotnet/orleans/pull/8905)
- Remove mention of build.sh from README.md by [@ardrabczyk](https://redirect.github.com/ardrabczyk) in [https://github.com/dotnet/orleans/pull/8901](https://redirect.github.com/dotnet/orleans/pull/8901)
- Fix build template for nightly by [@benjaminpetit](https://redirect.github.com/benjaminpetit) in [https://github.com/dotnet/orleans/pull/8909](https://redirect.github.com/dotnet/orleans/pull/8909)
- Add mirror pipeline by [@benjaminpetit](https://redirect.github.com/benjaminpetit) in [https://github.com/dotnet/orleans/pull/8918](https://redirect.github.com/dotnet/orleans/pull/8918)
- Fix nightly nuget publishing by [@benjaminpetit](https://redirect.github.com/benjaminpetit) in [https://github.com/dotnet/orleans/pull/8919](https://redirect.github.com/dotnet/orleans/pull/8919)
- Fix mirror pipeline by [@benjaminpetit](https://redirect.github.com/benjaminpetit) in [https://github.com/dotnet/orleans/pull/8923](https://redirect.github.com/dotnet/orleans/pull/8923)
- Do not trigger mirror for PR by [@benjaminpetit](https://redirect.github.com/benjaminpetit) in [https://github.com/dotnet/orleans/pull/8924](https://redirect.github.com/dotnet/orleans/pull/8924)
- Enable TCP keep-alive on all sockets by default by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8927](https://redirect.github.com/dotnet/orleans/pull/8927)
- Fix typos in SQSStorage.cs by [@Malpp](https://redirect.github.com/Malpp) in [https://github.com/dotnet/orleans/pull/8933](https://redirect.github.com/dotnet/orleans/pull/8933)
- Add more tests for \[Alias("x")] attribute by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8926](https://redirect.github.com/dotnet/orleans/pull/8926)
- Update Azure.Identity by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8942](https://redirect.github.com/dotnet/orleans/pull/8942)
- Serialization doc fixes, add missing tests, fix PooledBufferCodec by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8943](https://redirect.github.com/dotnet/orleans/pull/8943)
- Fix some reference documentation warnings by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8941](https://redirect.github.com/dotnet/orleans/pull/8941)
- Always read grain state during activation if it has not been rehydrated by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8944](https://redirect.github.com/dotnet/orleans/pull/8944)
##### Additional changes since 8.0.0
- Clean up WorkItemGroup and ActivationTaskScheduler logic by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8865](https://redirect.github.com/dotnet/orleans/pull/8865)
- Orleans is now officially supported by Microsoft by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8882](https://redirect.github.com/dotnet/orleans/pull/8882)
- Avoid over-counting stateless worker activations by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8886](https://redirect.github.com/dotnet/orleans/pull/8886)
- Move `ResourceOptimizedPlacementOptions` to `Orleans.Configuration` by [@ledjon-behluli](https://redirect.github.com/ledjon-behluli) in [https://github.com/dotnet/orleans/pull/8892](https://redirect.github.com/dotnet/orleans/pull/8892)
- Guard against null grain context in test code by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8897](https://redirect.github.com/dotnet/orleans/pull/8897)
- Use GrainDirectoryCacheFactory to construct a IGrainDirectoryCache by [@Mostafa-Goher](https://redirect.github.com/Mostafa-Goher) in [https://github.com/dotnet/orleans/pull/8844](https://redirect.github.com/dotnet/orleans/pull/8844)
- Ensure `StatelessWorkerAttribute.MaxLocal` property is accounted for by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8885](https://redirect.github.com/dotnet/orleans/pull/8885)
- Make EventHub tests more reliable by [@benjaminpetit](https://redirect.github.com/benjaminpetit) in [https://github.com/dotnet/orleans/pull/8889](https://redirect.github.com/dotnet/orleans/pull/8889)
- Fix `PooledBuffer` serialization by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8852](https://redirect.github.com/dotnet/orleans/pull/8852)
- Prepare the FabricBot config for migration to Policy Service by [@jeffhandley](https://redirect.github.com/jeffhandley) in [https://github.com/dotnet/orleans/pull/8855](https://redirect.github.com/dotnet/orleans/pull/8855)
- Address IDE0038. Use pattern matching. by [@IEvangelist](https://redirect.github.com/IEvangelist) in [https://github.com/dotnet/orleans/pull/8619](https://redirect.github.com/dotnet/orleans/pull/8619)
- Always reset `RuntimeContext` to previous value after use by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8864](https://redirect.github.com/dotnet/orleans/pull/8864)
- Distributed Tracing: Use recommended conventions by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8856](https://redirect.github.com/dotnet/orleans/pull/8856)
- FabricBot: Onboarding to GitOps.ResourceManagement because of FabricBot decommissioning by [@dotnet-policy-service](https://redirect.github.com/dotnet-policy-service) in [https://github.com/dotnet/orleans/pull/8869](https://redirect.github.com/dotnet/orleans/pull/8869)
- Clarify \[AlwaysInterleave] interleaves with anything, including itself by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8804](https://redirect.github.com/dotnet/orleans/pull/8804)
- Adds `LinearBackoffClientConnectionRetryFilter` in the default client services by [@ledjon-behluli](https://redirect.github.com/ledjon-behluli) in [https://github.com/dotnet/orleans/pull/8793](https://redirect.github.com/dotnet/orleans/pull/8793)
- Microsoft.Extensions.Configuration support by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8764](https://redirect.github.com/dotnet/orleans/pull/8764)
- Avoid constant try/catch on a non-existing gateway for external cluster client by [@ledjon-behluli](https://redirect.github.com/ledjon-behluli) in [https://github.com/dotnet/orleans/pull/8792](https://redirect.github.com/dotnet/orleans/pull/8792)
- Add Analyzer and CodeFix for duplicate method aliases (ORLEANS0011) by [@ledjon-behluli](https://redirect.github.com/ledjon-behluli) in [https://github.com/dotnet/orleans/pull/8662](https://redirect.github.com/dotnet/orleans/pull/8662)
- Adds code fixer for: Report error on duplicate \[Id(x)] (ORLEANS0012) by [@ledjon-behluli](https://redirect.github.com/ledjon-behluli) in [https://github.com/dotnet/orleans/pull/8808](https://redirect.github.com/dotnet/orleans/pull/8808)
- Make repeatable the execution of SQLServer Ado scripts without errors by [@m3nax](https://redirect.github.com/m3nax) in [https://github.com/dotnet/orleans/pull/8799](https://redirect.github.com/dotnet/orleans/pull/8799)
- `GenerateAliasAttribtuesAnalyzer` needs to account for file-scoped namespaces by [@ledjon-behluli](https://redirect.github.com/ledjon-behluli) in [https://github.com/dotnet/orleans/pull/8809](https://redirect.github.com/dotnet/orleans/pull/8809)
- Add nightly feed publishing by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8810](https://redirect.github.com/dotnet/orleans/pull/8810)
- Update README.md to include new nightly build feed details by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8814](https://redirect.github.com/dotnet/orleans/pull/8814)
- Resource optimized placement strategy by [@ledjon-behluli](https://redirect.github.com/ledjon-behluli) in [https://github.com/dotnet/orleans/pull/8815](https://redirect.github.com/dotnet/orleans/pull/8815)
- Upgrade `System.Data.SqlClient` by [@ledjon-behluli](https://redirect.github.com/ledjon-behluli) in [https://github.com/dotnet/orleans/pull/8821](https://redirect.github.com/dotnet/orleans/pull/8821)
- Provide cross-platform environment statistics collection + Modify `OverloadDetector` to account for memory too by [@ledjon-behluli](https://redirect.github.com/ledjon-behluli) in [https://github.com/dotnet/orleans/pull/8820](https://redirect.github.com/dotnet/orleans/pull/8820)
- Centralize environment statistics filtering by [@ledjon-behluli](https://redirect.github.com/ledjon-behluli) in [https://github.com/dotnet/orleans/pull/8827](https://redirect.github.com/dotnet/orleans/pull/8827)
- Add support for enabling distributed tracing via configuration switch by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8829](https://redirect.github.com/dotnet/orleans/pull/8829)
- Add default Redis options when Redis is configured via keyed service by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8847](https://redirect.github.com/dotnet/orleans/pull/8847)
- Fix insert condition check in `RedisMembershipTable` by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8848](https://redirect.github.com/dotnet/orleans/pull/8848)
- Downgrade Microsoft.CodeAnalyis to v4.5.0 by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8849](https://redirect.github.com/dotnet/orleans/pull/8849)
##### New Contributors
- [@ardrabczyk](https://redirect.github.com/ardrabczyk) made their first contribution in [https://github.com/dotnet/orleans/pull/8901](https://redirect.github.com/dotnet/orleans/pull/8901)
- [@Malpp](https://redirect.github.com/Malpp) made their first contribution in [https://github.com/dotnet/orleans/pull/8933](https://redirect.github.com/dotnet/orleans/pull/8933)
- [@Mostafa-Goher](https://redirect.github.com/Mostafa-Goher) made their first contribution in [https://github.com/dotnet/orleans/pull/8844](https://redirect.github.com/dotnet/orleans/pull/8844)
- [@dotnet-policy-service](https://redirect.github.com/dotnet-policy-service) made their first contribution in [https://github.com/dotnet/orleans/pull/8869](https://redirect.github.com/dotnet/orleans/pull/8869)
- [@m3nax](https://redirect.github.com/m3nax) made their first contribution in [https://github.com/dotnet/orleans/pull/8799](https://redirect.github.com/dotnet/orleans/pull/8799)
**Full Changelog**: https://github.com/dotnet/orleans/compare/v8.0.0...v8.1.0
### [`v8.0.0`](https://redirect.github.com/dotnet/orleans/releases/tag/v8.0.0)
##### What's Changed Since v7.0.0
- Fix version suffix in build.yaml by [@benjaminpetit](https://redirect.github.com/benjaminpetit) in [https://github.com/dotnet/orleans/pull/8113](https://redirect.github.com/dotnet/orleans/pull/8113)
- Exclude samples folder from PR trigger by [@benjaminpetit](https://redirect.github.com/benjaminpetit) in [https://github.com/dotnet/orleans/pull/8118](https://redirect.github.com/dotnet/orleans/pull/8118)
- Upgrading 'Hello World' sample by [@IEvangelist](https://redirect.github.com/IEvangelist) in [https://github.com/dotnet/orleans/pull/8116](https://redirect.github.com/dotnet/orleans/pull/8116)
- Upgrade 'Bank Account' sample by [@IEvangelist](https://redirect.github.com/IEvangelist) in [https://github.com/dotnet/orleans/pull/8119](https://redirect.github.com/dotnet/orleans/pull/8119)
- Enable 3.x scheduled builds by [@benjaminpetit](https://redirect.github.com/benjaminpetit) in [https://github.com/dotnet/orleans/pull/8005](https://redirect.github.com/dotnet/orleans/pull/8005)
- Upgraded 'Adventure' samples by [@IEvangelist](https://redirect.github.com/IEvangelist) in [https://github.com/dotnet/orleans/pull/8120](https://redirect.github.com/dotnet/orleans/pull/8120)
- Upgrade 'Blazor Server' sample by [@IEvangelist](https://redirect.github.com/IEvangelist) in [https://github.com/dotnet/orleans/pull/8121](https://redirect.github.com/dotnet/orleans/pull/8121)
- Upgrade 'Blazor Wasm' sample by [@IEvangelist](https://redirect.github.com/IEvangelist) in [https://github.com/dotnet/orleans/pull/8122](https://redirect.github.com/dotnet/orleans/pull/8122)
- Upgrade 'F# Hello World' sample by [@IEvangelist](https://redirect.github.com/IEvangelist) in [https://github.com/dotnet/orleans/pull/8129](https://redirect.github.com/dotnet/orleans/pull/8129)
- Upgrade 'VB Hello World' sample by [@IEvangelist](https://redirect.github.com/IEvangelist) in [https://github.com/dotnet/orleans/pull/8137](https://redirect.github.com/dotnet/orleans/pull/8137)
- Upgrade 'Tic Tac Toe' sample by [@IEvangelist](https://redirect.github.com/IEvangelist) in [https://github.com/dotnet/orleans/pull/8135](https://redirect.github.com/dotnet/orleans/pull/8135)
- Upgrade 'TLS' sample by [@IEvangelist](https://redirect.github.com/IEvangelist) in [https://github.com/dotnet/orleans/pull/8136](https://redirect.github.com/dotnet/orleans/pull/8136)
- Fix a typo by [@m-sadegh-sh](https://redirect.github.com/m-sadegh-sh) in [https://github.com/dotnet/orleans/pull/8143](https://redirect.github.com/dotnet/orleans/pull/8143)
- Add MembershipVersion to GrainDirectoryEntity by [@benjaminpetit](https://redirect.github.com/benjaminpetit) in [https://github.com/dotnet/orleans/pull/8151](https://redirect.github.com/dotnet/orleans/pull/8151)
- Fix configuration of BroadcastChannel by [@benjaminpetit](https://redirect.github.com/benjaminpetit) in [https://github.com/dotnet/orleans/pull/8150](https://redirect.github.com/dotnet/orleans/pull/8150)
- Fix a typo by [@m-sadegh-sh](https://redirect.github.com/m-sadegh-sh) in [https://github.com/dotnet/orleans/pull/8144](https://redirect.github.com/dotnet/orleans/pull/8144)
- Guard and check for GenerateCodeForDeclaringAssembly when type has no declaring assembly by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8156](https://redirect.github.com/dotnet/orleans/pull/8156)
- Fix packaging of CodeGenerator to accept project properties by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8155](https://redirect.github.com/dotnet/orleans/pull/8155)
- Upgrade 'Streaming' samples by [@IEvangelist](https://redirect.github.com/IEvangelist) in [https://github.com/dotnet/orleans/pull/8134](https://redirect.github.com/dotnet/orleans/pull/8134)
- Upgrade 'Chat Room' sample by [@IEvangelist](https://redirect.github.com/IEvangelist) in [https://github.com/dotnet/orleans/pull/8126](https://redirect.github.com/dotnet/orleans/pull/8126)
- Upgrade 'Stocks' sample by [@IEvangelist](https://redirect.github.com/IEvangelist) in [https://github.com/dotnet/orleans/pull/8133](https://redirect.github.com/dotnet/orleans/pull/8133)
- Upgrade 'Shopping Cart' sample by [@IEvangelist](https://redirect.github.com/IEvangelist) in [https://github.com/dotnet/orleans/pull/8132](https://redirect.github.com/dotnet/orleans/pull/8132)
- Upgrade 'GPS Tracker' sample by [@IEvangelist](https://redirect.github.com/IEvangelist) in [https://github.com/dotnet/orleans/pull/8130](https://redirect.github.com/dotnet/orleans/pull/8130)
- Use code generated or compiled regular expressions where possible by [@SukharevAndrey](https://redirect.github.com/SukharevAndrey) in [https://github.com/dotnet/orleans/pull/8141](https://redirect.github.com/dotnet/orleans/pull/8141)
- Upgrade 'Chirper' sample by [@IEvangelist](https://redirect.github.com/IEvangelist) in [https://github.com/dotnet/orleans/pull/8128](https://redirect.github.com/dotnet/orleans/pull/8128)
- Upgrade 'Presence' sample by [@IEvangelist](https://redirect.github.com/IEvangelist) in [https://github.com/dotnet/orleans/pull/8131](https://redirect.github.com/dotnet/orleans/pull/8131)
- \[main] Add CodeQL3000 tasks by [@dougbu](https://redirect.github.com/dougbu) in [https://github.com/dotnet/orleans/pull/8160](https://redirect.github.com/dotnet/orleans/pull/8160)
- Fix the bug in the Chirper sample code by [@IEvangelist](https://redirect.github.com/IEvangelist) in [https://github.com/dotnet/orleans/pull/8194](https://redirect.github.com/dotnet/orleans/pull/8194)
- Delete empty statements as they are treated as errors by some analyzers by [@SukharevAndrey](https://redirect.github.com/SukharevAndrey) in [https://github.com/dotnet/orleans/pull/8192](https://redirect.github.com/dotnet/orleans/pull/8192)
- Upgrade 'Voting' sample by [@IEvangelist](https://redirect.github.com/IEvangelist) in [https://github.com/dotnet/orleans/pull/8138](https://redirect.github.com/dotnet/orleans/pull/8138)
- Delete samples and update README.md by [@IEvangelist](https://redirect.github.com/IEvangelist) in [https://github.com/dotnet/orleans/pull/8154](https://redirect.github.com/dotnet/orleans/pull/8154)
- Use NuGet Central Package Management to handle dependencies' versions by [@SukharevAndrey](https://redirect.github.com/SukharevAndrey) in [https://github.com/dotnet/orleans/pull/8191](https://redirect.github.com/dotnet/orleans/pull/8191)
- Optimize message serialization by [@pentp](https://redirect.github.com/pentp) in [https://github.com/dotnet/orleans/pull/8185](https://redirect.github.com/dotnet/orleans/pull/8185)
- Add TransactionFaultInjectionTests to Functional runs by [@ReubenBond](https://redirect.github.com/ReubenBond) in [https://github.com/dotnet/orleans/pull/8168](https://redirect.github.com/dotnet/orleans/pull/8168)
- Fix images, use raw URLs from dependent repo by [@IEvangelist](https://redirect.github.com/IEvangelist) in [https://github.com/dotnet/orleans/pull/8202](https://redirect.github.com/dotnet/orleans/pull/8202)
- Fix mariadb tests by [@benjaminpetit](https://redirect.github.com/benjaminpetit) in [https://github.com/dotnet/orleans/pull/8198](https://redirect.github.com/dotnet/orleans/pull/8198)
- Bumped KubernetesClient to v9.0.38 by [@EPinci](https://redirect.github.com/EPinci) in [https://github.com/dotnet/orleans/pull/8199](https://redirect.github.com/dotnet/orleans/pull/8199)
- Optimize static codec serialization by [@pentp](https://redirect.github.com/pentp) in [https://github.com/dotnet/orleans/pull/8206](https://redirect.gi
Configuration
📅 Schedule: Branch creation - "before 4am on monday" (UTC), Automerge - At any time (no schedule defined).
🚦 Automerge: Enabled.
♻ Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about these updates again.
[ ] If you want to rebase/retry this PR, check this box
This PR contains the following updates:
7.2.7
->8.2.0
7.2.7
->8.2.0
7.2.7
->8.2.0
7.2.7
->8.2.0
Release Notes
dotnet/orleans (Microsoft.Orleans.Client)
### [`v8.2.0`](https://redirect.github.com/dotnet/orleans/releases/tag/v8.2.0) ##### New features ##### Activation repartitioning [!Activation Repartitioning in action](https://redirect.github.com/user-attachments/assets/d12764e9-ec04-433d-bff1-cdb33b3c1b1f) > Above: a demonstration showing Activation Repartitioning in action. The red lines represent cross-silo communication. As the red lines are eliminated by the partitioning algorithm, throughput improves to over 2x the initial throughput. [Ledjon Behluli](https://redirect.github.com/ledjon-behluli) and [@ReubenBond](https://redirect.github.com/ReubenBond) implemented **activation repartitioning** in [#8877](https://redirect.github.com/dotnet/orleans/pull/8877). When enabled, **activation repartitioning** collocates grains based on observed communication patterns to improve performance while keeping load balanced across your cluster. In initial benchmarks, we observe throughput improvements in the range of 30% to 110%. The following paragraphs provide more background and implementation details for those who are interested. The feature is currently *experimental* and to enable it you need to opt-in on every silo in your cluster using the `ISiloBuilder.AddActivationRepartitioner()` extension method, suppressing the experimental feature warning: ```csharp #pragma warning disable ORLEANSEXP001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. siloBuilder.AddActivationRepartitioner(); #pragma warning restore ORLEANSEXP001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. ``` The fastest and cheapest grains calls are ones which don't cross process boundaries. These grain calls do not need to be serialized and do not need to incur network transmission costs. For that reason, collocating related grains within the same host can significantly improve the performance of your application. On the other hand, if all grains were placed in a single host, that host may become overloaded and crash, and you would not be able to scale your application across multiple hosts. How can we maximize collocation of related grains while keeping load across your hosts balanced? Before describing our solution, we need to provide some background. [Grain placement in Orleans](https://learn.microsoft.com/dotnet/orleans/grains/grain-placement) is flexible: Orleans executes a user-defined function when deciding where in a cluster to place each grain, providing your function with a list of the compatible silos in your cluster, that is, the silos which support the grain type and interface version which triggered placement. Grains calls are *location-transparent*, so callers do not need to know where a grain is located, allowing grains to be placed anywhere across your cluster of hosts. Each grain's current location is stored in a [distributed directory](https://learn.microsoft.com/dotnet/orleans/host/grain-directory) and lookups to the directory are cached for performance. [**Resource-optimized placement**](https://learn.microsoft.com/dotnet/orleans/grains/grain-placement#resource-optimized-placement) was implemented by [@ledjon-behluli](https://redirect.github.com/ledjon-behluli) in [#8815](https://redirect.github.com/dotnet/orleans/pull/8815). Resource-optimized placement uses runtime statistics such as total and available memory, CPU usage, and grain count, collected from all hosts in the cluster, smooths them, and combines them to calculate a load score. It selects the least-loaded silo from a subset of hosts to balance load evenly across the cluster\[^4]. If the load score of the local silo is within some configured range of the best candidate's load score, the local silo is chosen preferentially. This improves grain locality by leveraging the knowledge that the local silo initiated a call to the grain and therefore has some relation to that grain. Ledjon wrote more about Resource-optimized placement in [this blog post](https://www.ledjonbehluli.com/posts/orleans_resource_placement_kalman/). Originally, there was no straightforward way to move an active grain from one host to another without needing to fully deactivate the grain, unregister it from the grain directory, contend with concurrent callers on where to place the new activation, and reload its state from the database when the new activation is created. [**Live grain migration** was introduced in #8452](https://redirect.github.com/dotnet/orleans/pull/8452), allowing grains to transparently migrate from one silo to another on-demand without needing to reload state from the database, and without affecting pending requests. **Live grain migration** introduced two new lifecycle stages: *dehydration* and *rehydration*. The grain's in-memory state (application state, enqueued messages, metadata) is dehydrated into a migration packet which is sent to the destination silo where it's rehydrated. Live grain migration provided the mechanism for grains to migrate across hosts, but did not provide any out-of-the-box policies to automate migration. Users trigger grain migration by calling `this.MigrateOnIdle()` from within a grain, optionally providing a placement hint which the grain's configured placement director can use to select a destination host for the grain activation. Finally, we have the pieces in place for **activation repartitioning**: grain activations are load-balanced across the cluster, and they are able to migrate from host to host quickly. While **live grain migration** gives developers a mechanism to migrate grain activations from one host to another, it does not provide any automated *policy* to do so. Remember, we want grains to be balanced across the cluster and collocated with related grains to reduce networking and serialization cost. This is a difficult challenge since: - An application can have millions of in-memory grains spread across tens or hundreds of silos. - Each grain can message any other grain. - The set of grains which each grain communicates with can change from minute to minute. For example, in an online game, player grains may join one match and communicate with each other for some time and then join a different match with an entirely different set of players afterwards. - Computing the [minimum edge-cut](https://en.wikipedia.org/wiki/Minimum_cut) for an arbitrary graph is [NP-hard](https://en.wikipedia.org/wiki/NP-hardness). - No single host has full knowledge of which grains are hosted on which other host and which grains they communicate with: the graph is distributed across the cluster and changes dynamically. - Storing the entire communication graph in memory could be prohibitively expensive. Folks at Microsoft Research studied this problem and proposed a solution in a paper titled [Optimizing Distributed Actor Systems for Dynamic Interactive Services](https://www.microsoft.com/research/publication/optimizing-distributed-actor-systems-for-dynamic-interactive-services/). The paper, dubbed *ActOp*, proposes a decentralized approximate solution which achieves good results in their benchmarks. Their implementation was never merged into Orleans and we were unable to find the original implementation on Microsoft's internal network. So, after first implementing **resource-optimized placement**, community contributor [@ledjon-behluli](https://redirect.github.com/ledjon-behluli) set out to implement **activation repartitioning** from scratch based on the ActOp paper. The following paragraphs describe the algorithm and the enhancements we made along the way. The **activation repartitioning** algorithm involves pair-wise exchange of grains between two hosts at a time. Silos compute a candidate set of grains to send to a peer, then the peer does similarly, and uses a greedy algorithm to determine a final exchange set which minimizes cost while keeping silos balanced. To compute the candidate sets, silos track which grains communicate with which other grains and how frequently. The whole graph would be unwieldy, so we only maintain the top-K communication edges using a variant of the *Space-Saving*\[^1] algorithm. Messages are sampled via a [multi-producer, single consumer ring buffer](https://redirect.github.com/dotnet/orleans/blob/92e0bf37048cd8e6c728fba008fd4cfbbd647435/src/Orleans.Runtime/Utilities/StripedMpscBuffer.cs) which drops messages if the partition is full. They are then processed by a single thread, which yields frequently to give other threads CPU time. When the distribution has low skew and the K parameter is fairly small, *Space-Saving* can require a lot of costly shuffling at the bottom of its max-heap (we use the heap variant to reduce memory). To address this, we use *Filtered Space-Saving*\[^2] instead of *Space-Saving*. *Filtered Space-Saving* involves putting a 'sketch' data structure at the bottom of the max heap for the lower end of the distribution, which can greatly reduce churn at the bottom and improve performance by up to ~2x in our tests. If the top-K communication edges are all internal (eg, because the algorithm has already optimized partitioning somewhat), silos won't find many good transfer candidates. We need to track internal edges to work out which grains should/shouldn't be transferred (cost vs benefit). To address this, we introduced a bloom filter to track grains where the cost of movement is greater than the benefit, removing them from the top-K data structure. From our experiments, this works very well with even a 10x smaller *K*. This performance improvement will come with a reduced ability to handle dynamic graphs, so in the future we may need to implement a decay strategy to address this as the bloom filter becomes saturated. To improve lookup performance, [@ledjon-behluli](https://redirect.github.com/ledjon-behluli) implemented a [blocked bloom filter](https://redirect.github.com/dotnet/orleans/blob/92e0bf37048cd8e6c728fba008fd4cfbbd647435/src/Orleans.Runtime/Placement/Repartitioning/BlockedBloomFilter.cs)\[^3], which is used instead of a classic bloom filter. \[^1]: [*Efficient Computation of Frequent and Top-k Elements in Data Streams* by Metwally, Agrawal, and Abbadi](https://www.cs.emory.edu/~cheung/Courses/585/Syllabus/papers/Frequency-count/2005-Metwally-Top-k-elements.pdf) \[^2]: [*Finding top-k elements in data streams* by Nuno Homem & Joao Paulo Carvalho](https://www.hlt.inesc-id.pt/~fmmb/references/misnis.ref0a.pdf) \[^3]: [*Cache-, Hash- and Space-Efficient Bloom Filters* by Felix Putze, Peter Sanders and Johannes Single](https://www.cs.amherst.edu/~ccmcgeoch/cs34/papers/cacheefficientbloomfilters-jea.pdf) \[^4]: [The Power of Two Choices in Randomized Load Balancing by Michael David Mitzenmacher](https://www.eecs.harvard.edu/~michaelm/postscripts/mythesis.pdf) ##### Enhancements to grain timers Orleans v8.2.0 introduces a new API, `RegisterGrainTimer`, for managing [grain timers](https://learn.microsoft.com/dotnet/orleans/grains/timers-and-reminders#timers). For compatibility, the existing `RegisterTimer` API is still available, but it is marked `[Obsolete]` and developers should migrate to the new grain timer API, `RegisterGrainTimer`. Grain timers have been a common source of confusion for new and experienced developers because grain timer callbacks can execute concurrently with other grain calls, rather than being executed one-by-one like grain calls are. That is, timer callbacks are *interleaving*. With v8.2.0, this issue can be avoided by using the new `RegisterGrainTimer` API. The new API has the following advantages: - Grain timers can be updated using the `Change(TimeSpan, TimeSpan)` method on the returned `IGrainTimer` instance. - Callbacks do not interleave by default. Interleaving can be enabled by setting `Interleave` to `true` on `GrainTimerCreationOptions`. - Callbacks can keep the grain active, preventing it from being collected if the timer period is relatively short. This can be enabled by setting `KeepAlive` to `true` on `GrainTimerCreationOptions`. - Callbacks can receive a `CancellationToken` which is canceled when the timer is disposed or the grain starts to deactivate. - Callbacks can dispose the grain timer which fired them. - Callbacks are now subject to grain call filters. - Callbacks are visible in distributed tracing, when distributed tracing is enabled. - POCO grains (grain classes which do not inherit from `Grain`) can register grain timers using the `RegisterGrainTimer` extension method. The core API is as-follows: ```csharp public static IGrainTimer RegisterGrainTimer/// Represents a timer belonging to a grain. ///
public interface IGrainTimer : IDisposable { ///Changes the start time and the interval between method invocations for a timer, using values to measure time intervals.
/// /// AConfiguration
📅 Schedule: Branch creation - "before 4am on monday" (UTC), Automerge - At any time (no schedule defined).
🚦 Automerge: Enabled.
♻ Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about these updates again.
This PR was generated by Mend Renovate. View the repository job log.