What to do if I need to run IHostedService
s per tenant?
#14507
-
I have several GRPC subscriptions that must run per tenant with their own settings. I have researched #8409 #7253 #14380 but there is no solution for my case |
Beta Was this translation helpful? Give feedback.
Answered by
xperiandri
Oct 19, 2023
Replies: 1 comment
-
So the simplest way is to inherit The other way is to create a derived interface like namespace Microsoft.Extensions.Hosting
type ITenantHostedService = inherit IHostedService and then namespace Microsoft.Extensions.DependencyInjection
open OrchardCore.Modules
[<AutoOpen>]
module ServiceCollectionExtensions =
open System
open System.Collections.Immutable
open System.Linq
open System.Threading
open System.Threading.Tasks
open FSharp.Collections.Immutable
open Microsoft.Extensions.DependencyInjection
open Microsoft.Extensions.Hosting
open IcedTasks
open OrchardCore.Environment.Shell
open OrchardCore.Environment.Shell.Events
open Lula.RiskAssessment.Hosting
// From https://github.com/dotnet/runtime/blob/1878c5515e78fbc527c721f38dca94e9fceb55d8/src/libraries/Microsoft.Extensions.Hosting/src/Internal/Host.cs#L327
let internal foreachService
(token: CancellationToken)
(services: 'T FlatList)
(concurrent: bool, abortOnFirstException: bool)
(operation: CancellationToken -> 'T -> Task)
=
task {
let exceptions = ResizeArray<Exception>()
if concurrent then
let tasks = ResizeArray<Task>(services.Length)
for service in services do
try
let task = operation token service
if task.IsCompleted && task.Exception <> null then
exceptions.AddRange(task.Exception.InnerExceptions)
else
tasks.Add(Task.Run(fun () -> task, token))
with ex ->
exceptions.Add(ex)
let groupedTasks = Task.WhenAll tasks
try
do! groupedTasks.ConfigureAwait false
with ex ->
match groupedTasks.Exception with
| null -> exceptions.AddRange groupedTasks.Exception.InnerExceptions
| _ -> exceptions.Add ex
else
let mutable index = 0
let mutable ``continue`` = services.Length > 0
while ``continue`` do
try
index <- index + 1
``continue`` <- index < services.Length
let service = services.[index]
do! (operation token service).ConfigureAwait false
with ex ->
exceptions.Add(ex)
if abortOnFirstException then
``continue`` <- false
return exceptions |> FlatList.ofSeq
}
type HostedServiceModularEvents(shellSettings: ShellSettings, hostedServices: ITenantHostedService seq) =
inherit ModularTenantEvents()
let hostedServices = hostedServices |> Seq.toFlatList
override _.ActivatingAsync() = task {
if shellSettings.IsInitialized() then
let! exceptions =
foreachService CancellationToken.None hostedServices (true, false) (fun token service -> service.StartAsync(token))
match exceptions.Length with
| 0 -> ()
| 1 -> raise (exceptions.First())
| _ -> raise (AggregateException($"Environmet '{shellSettings.TenantId}' initialization failed", exceptions))
}
override _.TerminatingAsync() = task {
let! exceptions =
foreachService CancellationToken.None hostedServices (true, false) (fun token service -> service.StopAsync(token))
match exceptions.Length with
| 0 -> ()
| 1 -> raise (exceptions.First())
| _ -> raise (AggregateException($"Environmet '{shellSettings.TenantId}' releasing failed", exceptions))
}
open Microsoft.Extensions.DependencyInjection.Extensions
type IServiceCollection with
// From https://github.com/dotnet/runtime/blob/release/7.0/src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/ServiceCollectionHostedServiceExtensions.cs
/// Add an ITenantHostedService registration for the given type.
member services.AddTenantHostedService<'HostedService
when 'HostedService: not struct and 'HostedService :> IEnvironmentDependentHostedService>()
=
services.TryAddEnumerable(ServiceDescriptor.Singleton<ITenantHostedService, 'HostedService>())
services
/// Add an ITenantHostedService registration for the given type.
member services.AddEnvironmentDependentHostedService<'HostedService
when 'HostedService: not struct and 'HostedService :> ITenantHostedService>
(implementationFactory: Func<IServiceProvider, ITenantHostedService>)
=
services.TryAddEnumerable(ServiceDescriptor.Singleton<ITenantHostedService>(implementationFactory))
services
then call in Orchard Core member services.EnableRunningTenantHostedServices() =
services.AddScoped<IModularTenantEvents, HostedServiceModularEvents>() |
Beta Was this translation helpful? Give feedback.
0 replies
Answer selected by
xperiandri
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
So the simplest way is to inherit
ModularTenantEvents
or implementIModularTenantEvents
.And it will work like a hosted service.
The other way is to create a derived interface like
and then