Skip to content
Merged
5 changes: 5 additions & 0 deletions .openpublishing.redirection.orleans.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@
{
"source_path_from_root": "/docs/orleans/host/configuration-guide/activation-garbage-collection.md",
"redirect_url": "/dotnet/orleans/host/configuration-guide/activation-collection"
},
{
"source_path_from_root": "/docs/orleans/implementation/cluster-configuration.md",
"redirect_url": "/dotnet/orleans/implementation/cluster-management"
}

]
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.0" />
<PackageReference Include="Microsoft.SemanticKernel" Version="1.32.0" />
<PackageReference Include="Microsoft.SemanticKernel" Version="1.33.0" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.AzureAISearch" Version="1.9.0-alpha" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.Redis" Version="1.9.0-alpha" />
<PackageReference Include="Microsoft.SemanticKernel.Plugins.Memory" Version="1.9.0-alpha" />
Expand Down
2 changes: 1 addition & 1 deletion docs/ai/tutorials/snippets/llm-eval/llm-eval.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.0" />
<PackageReference Include="Microsoft.SemanticKernel" Version="1.32.0" />
<PackageReference Include="Microsoft.SemanticKernel" Version="1.33.0" />
</ItemGroup>

</Project>
2 changes: 1 addition & 1 deletion docs/architecture/maui/navigation.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ This interface specifies that an implementing class must provide the following m
The `MauiNavigationService` class, which implements the `INavigationService` interface, is registered as a singleton with the dependency injection container in the `MauiProgram.CreateMauiApp()` method, as demonstrated in the following code example:

```csharp
mauiAppBuilder.Services.AddSingleton<INavigationService, MauiNavigationService>();;
mauiAppBuilder.Services.AddSingleton<INavigationService, MauiNavigationService>();
```

The `INavigationService` interface can then be resolved by adding it to the constructor of our views and view-models, as demonstrated in the following code example:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ ms.date: 11/01/2020
Checking `<Isa>.X64.IsSupported`, where `<Isa>` refers to the classes in the <xref:System.Runtime.Intrinsics.X86?displayProperty=nameWithType> namespace, may now produce a different result to previous versions of .NET.

> [!TIP]
> *ISA* stands for industry standard architecture.
> *ISA* stands for Instruction Set Architecture.

## Version introduced

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Previously, `NaN` inputs to the listed <xref:System.Runtime.Intrinsics.X86.Sse>

Starting in .NET 5, these methods correctly handle `NaN` inputs and return the same results as the corresponding methods in the <xref:System.Runtime.Intrinsics.X86.Avx> class.

The Streaming SIMD Extensions (SSE) and Streaming SIMD Extensions 2 (SSE2) industry standard architectures (ISAs) don't provide direct hardware support for these comparison methods, so they're implemented in software. Previously, the methods were improperly implemented, and they incorrectly handled `NaN` inputs. For code ported from native, the incorrect behavior may introduce bugs. For a 256-bit code path, the methods can also produce different results to the equivalent methods in the <xref:System.Runtime.Intrinsics.X86.Avx> class.
The Streaming SIMD Extensions (SSE) and Streaming SIMD Extensions 2 (SSE2) Instruction Set Architectures (ISAs) don't provide direct hardware support for these comparison methods, so they're implemented in software. Previously, the methods were improperly implemented, and they incorrectly handled `NaN` inputs. For code ported from native, the incorrect behavior may introduce bugs. For a 256-bit code path, the methods can also produce different results to the equivalent methods in the <xref:System.Runtime.Intrinsics.X86.Avx> class.

As an example of how the methods were previously incorrect, you can implement `CompareNotGreaterThan(x,y)` as `CompareLessThanOrEqual(x,y)` for regular integers. However, for `NaN` inputs, that logic computes the wrong result. Instead, using `CompareNotLessThan(y,x)` compares the numbers correctly *and* takes `NaN` inputs into consideration.

Expand Down
6 changes: 6 additions & 0 deletions docs/core/testing/selective-unit-tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ For `FullyQualifiedName` values that include a comma for generic type parameters
dotnet test --filter "FullyQualifiedName=MyNamespace.MyTestsClass<ParameterType1%2CParameterType2>.MyTestMethod"
```

For `Name` or `DisplayName`, use the URL encoding for the special characters. For example, to run a test with the name `MyTestMethod` and a string value `"text"`, use the following filter:

```dotnetcli
dotnet test --filter "Name=MyTestMethod \(%22text%22\)"
```

:::zone pivot="mstest"

## MSTest examples
Expand Down
8 changes: 1 addition & 7 deletions docs/core/testing/unit-testing-platform-vs-vstest.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,7 @@ VSTest also uses a JSON based communication protocol, but it's not JSON-RPC base

### Disabling the new protocol

To disable the use of the new protocol in Test Explorer, you can edit the csproj and remove the `TestingPlatformServer` capability.

```xml
<ItemGroup>
<ProjectCapability Remove="TestingPlatformServer" />
</ItemGroup>
```
To disable the use of the new protocol in Test Explorer, you can edit your project to add the following property: `<DisableTestingPlatformServerCapability>true</DisableTestingPlatformServerCapability>`.

## Executables

Expand Down
14 changes: 5 additions & 9 deletions docs/core/tools/dotnet-install-script.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: dotnet-install scripts
description: Learn about the dotnet-install scripts to install the .NET SDK and the shared runtime.
ms.date: 12/26/2024
ms.date: 01/15/2024
---
# dotnet-install scripts reference

Expand All @@ -20,7 +20,7 @@ Windows:
dotnet-install.ps1 [-Architecture <ARCHITECTURE>] [-AzureFeed]
[-Channel <CHANNEL>] [-DryRun] [-FeedCredential]
[-InstallDir <DIRECTORY>] [-JSonFile <JSONFILE>]
[-NoCdn] [-NoPath] [-ProxyAddress] [-ProxyBypassList <LIST_OF_URLS>]
[-NoPath] [-ProxyAddress] [-ProxyBypassList <LIST_OF_URLS>]
[-ProxyUseDefaultCredentials] [-Quality <QUALITY>] [-Runtime <RUNTIME>]
[-SkipNonVersionedFiles] [-UncachedFeed] [-KeepZip] [-ZipPath <PATH>] [-Verbose]
[-Version <VERSION>]
Expand All @@ -34,7 +34,7 @@ Linux/macOS:
dotnet-install.sh [--architecture <ARCHITECTURE>] [--azure-feed]
[--channel <CHANNEL>] [--dry-run] [--feed-credential]
[--install-dir <DIRECTORY>] [--jsonfile <JSONFILE>]
[--no-cdn] [--no-path] [--quality <QUALITY>]
[--no-path] [--quality <QUALITY>]
[--runtime <RUNTIME>] [--runtime-id <RID>]
[--skip-non-versioned-files] [--uncached-feed] [--keep-zip] [--zip-path <PATH>] [--verbose]
[--version <VERSION>]
Expand Down Expand Up @@ -102,7 +102,7 @@ The install scripts do not update the registry on Windows. They just download th

- **`-AzureFeed|--azure-feed`**

For internal use only. Allows using a different storage to download SDK archives from. This parameter is only used if --no-cdn is false. The default is `https://builds.dotnet.microsoft.com/dotnet`.
For internal use only. Allows using a different storage to download SDK archives from. The default is `https://builds.dotnet.microsoft.com/dotnet`.

- **`-Channel|--channel <CHANNEL>`**

Expand Down Expand Up @@ -137,10 +137,6 @@ The install scripts do not update the registry on Windows. They just download th

Specifies a path to a [global.json](global-json.md) file that will be used to determine the SDK version. The *global.json* file must have a value for `sdk:version`.

- **`-NoCdn|--no-cdn`**

Disables downloading from the [Azure Content Delivery Network (CDN)](/azure/cdn/cdn-overview) and uses the uncached feed directly.

- **`-NoPath|--no-path`**

If set, the installation folder isn't exported to the path for the current session. By default, the script modifies the PATH, which makes the .NET CLI available immediately after install.
Expand Down Expand Up @@ -205,7 +201,7 @@ The install scripts do not update the registry on Windows. They just download th

- **`-UncachedFeed|--uncached-feed`**

For internal use only. Allows using a different storage to download SDK archives from. This parameter is only used if --no-cdn is true.
For internal use only. Allows using a different storage to download SDK archives from. This parameter overwrites `-AzureFeed|--azure-feed`.

- **`-KeepZip|--keep-zip`**

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ using Microsoft.Extensions.Hosting;
await Host.CreateDefaultBuilder(args)
.UseOrleans(siloBuilder =>
{
siloBuilder.UseLocalhostClustering();;
siloBuilder.UseLocalhostClustering();
})
.RunConsoleAsync();
```
Expand Down
166 changes: 140 additions & 26 deletions docs/orleans/host/configuration-guide/startup-tasks.md
Original file line number Diff line number Diff line change
@@ -1,44 +1,158 @@
---
title: Startup tasks
description: Learn how to configure and manage startup tasks in .NET Orleans.
ms.date: 07/03/2024
title: Background Services and Startup Tasks
description: Learn how to configure and manage background services and startup tasks in .NET Orleans.
ms.date: 11/19/2024
---

# Startup tasks
# Background Services and Startup Tasks

In many cases, some task needs to be performed automatically as soon as a silo becomes available. Startup tasks provide this functionality.
When building Orleans applications, you often need to perform background operations or initialize components when the application starts.

Some use cases include, but are not limited to:
Startup tasks can be used to perform initialization work when a silo starts, before or after it begins accepting requests. Common use cases include:

* Starting background timers to perform periodic housekeeping tasks
* Pre-loading some cache grains with data downloaded from external backing storage
* Initializing grain state or preloading data
* Setting up external service connections
* Performing database migrations
* Validating configuration
* Warming up caches

Any exceptions that are thrown from a startup task during startup will be reported in the silo log and will stop the silo.
## Using BackgroundService (Recommended)

This fail-fast approach is the standard way that Orleans handles silo start-up issues, and is intended to allow any problems with silo configuration and/or bootstrap logic to be easily detected during testing phases rather than being silently ignored and causing unexpected problems later in the silo lifecycle.
The recommended approach is to use .NET [BackgroundService or `IHostedService`](/aspnet/core/fundamentals/host/hosted-services). See the [Background tasks with hosted services in ASP.NET Core](/aspnet/core/fundamentals/host/hosted-services) documentation for more information.

## Configure startup tasks
Here's an example that pings a grain every 5 seconds:

Startup tasks can be configured using the <xref:Orleans.Hosting.ISiloHostBuilder> either by registering a delegate to be invoked during startup or by registering an implementation of <xref:Orleans.Runtime.IStartupTask>.
```csharp
public class GrainPingService : BackgroundService
{
private readonly IGrainFactory _grainFactory;
private readonly ILogger<GrainPingService> _logger;

### Register a delegate
public GrainPingService(
IGrainFactory grainFactory,
ILogger<GrainPingService> logger)
{
_grainFactory = grainFactory;
_logger = logger;
}

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
try
{
while (!stoppingToken.IsCancellationRequested)
{
try
{
_logger.LogInformation("Pinging grain...");
var grain = _grainFactory.GetGrain<IMyGrain>("ping-target");
await grain.Ping();
}
catch (Exception ex) when (ex is not OperationCanceledException)
{
// Log the error but continue running
_logger.LogError(ex, "Failed to ping grain. Will retry in 5 seconds.");
}

await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);
}
}
catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
{
// Ignore cancellation during shutdown.
}
finally
{
_logger.LogInformation("Grain ping service is shutting down.");
}
}
}
```

Registration order is significant, since services added to the host builder are started one-by-one, in the order they are registered. You can register the background service as follows:

```csharp
siloHostBuilder.AddStartupTask(
async (IServiceProvider services, CancellationToken cancellation) =>
{
// Use the service provider to get the grain factory.
var grainFactory = services.GetRequiredService<IGrainFactory>();

// Get a reference to a grain and call a method on it.
var grain = grainFactory.GetGrain<IMyGrain>(0);
await grain.Initialize();
var builder = WebApplication.CreateBuilder(args);

// Configure Orleans first
builder.UseOrleans(siloBuilder =>
{
// Orleans configuration...
});

// Register the background service after calling 'UseOrleans' to make it start once Orleans has started.
builder.Services.AddHostedService<GrainPingService>();

var app = builder.Build();
```

The background service will start automatically when the application starts and will gracefully shut down when the application stops.

## Using IHostedService

For simpler scenarios where you don't need continuous background operation, you can implement `IHostedService` directly:

```csharp
public class GrainInitializerService : IHostedService
{
private readonly IGrainFactory _grainFactory;
private readonly ILogger<GrainInitializerService> _logger;

public GrainInitializerService(
IGrainFactory grainFactory,
ILogger<GrainInitializerService> logger)
{
_grainFactory = grainFactory;
_logger = logger;
}

public async Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Initializing grains...");
var grain = _grainFactory.GetGrain<IMyGrain>("initializer");
await grain.Initialize();
}

public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
```

Register it the same way:

```csharp
builder.Services.AddHostedService<GrainInitializerService>();
```

## Orleans' Startup Tasks

> [!NOTE]
> While startup tasks are still supported, we recommend using `BackgroundService` or `IHostedService` instead as they are the common .NET hosting mechanism for running background tasks.

> [!WARNING]
> Any exceptions thrown from a startup task will be reported in the silo log and will stop the silo. This fail-fast approach helps detect configuration and bootstrap issues during testing rather than having them cause unexpected problems later, but it can also mean that transient failures in a startup task will cause unavailability of the host.

If you need to use the built-in startup task system, you can configure them as follows:

### Register a delegate

A delegate can be registered as a startup task using the appropriate <xref:Orleans.Hosting.SiloBuilderStartupExtensions.AddStartupTask*> extension method on <xref:Orleans.Hosting.ISiloBuilder>.

```csharp
siloBuilder.AddStartupTask(
async (IServiceProvider services, CancellationToken cancellation) =>
{
var grainFactory = services.GetRequiredService<IGrainFactory>();
var grain = grainFactory.GetGrain<IMyGrain>("startup-task-grain");
await grain.Initialize();
});
```

### Register an `IStartupTask` implementation

First, we must define an implementation of `IStartupTask`:
The <xref:Orleans.Runtime.IStartupTask> interface can be implemented and registered as a startup task using the <xref:Orleans.Hosting.SiloBuilderStartupExtensions.AddStartupTask*> extension method on <xref:Orleans.Hosting.ISiloBuilder>.

```csharp
public class CallGrainStartupTask : IStartupTask
Expand All @@ -50,14 +164,14 @@ public class CallGrainStartupTask : IStartupTask

public async Task Execute(CancellationToken cancellationToken)
{
var grain = _grainFactory.GetGrain<IMyGrain>(0);
var grain = _grainFactory.GetGrain<IMyGrain>("startup-task-grain");
await grain.Initialize();
}
}
```

Then that implementation must be registered with the `ISiloHostBuilder`:
Register the startup task as follows:

```csharp
siloHostBuilder.AddStartupTask<CallGrainStartupTask>();
siloBuilder.AddStartupTask<CallGrainStartupTask>();
```
Loading
Loading