/// <summary> /// Sets the provided <paramref name="orchestrationService"/> to the <paramref name="builder" />. /// </summary> /// <param name="builder">The task hub builder.</param> /// <param name="orchestrationService">The orchestration service to use.</param> /// <returns>The original builder, with orchestration service set.</returns> public static ITaskHubWorkerBuilder WithOrchestrationService( this ITaskHubWorkerBuilder builder, IOrchestrationService orchestrationService) { Check.NotNull(builder, nameof(builder)); builder.Services.TryAddSingleton(orchestrationService); return(builder); }
public async Task CanCreateIfNotExists(bool isDatabaseMissing) { using TestDatabase testDb = this.CreateTestDb(!isDatabaseMissing); IOrchestrationService service = this.CreateServiceWithTestDb(testDb); await service.CreateIfNotExistsAsync(); LogAssert.NoWarningsOrErrors(this.logProvider); LogAssert .For(this.logProvider) .Expect( LogAssert.CheckedDatabase()) .ExpectIf( isDatabaseMissing, LogAssert.CommandCompleted($"CREATE DATABASE [{testDb.Name}]"), LogAssert.CreatedDatabase(testDb.Name)) .Expect( LogAssert.AcquiredAppLock(), LogAssert.SprocCompleted("dt._GetVersions"), LogAssert.ExecutedSqlScript("schema-0.2.0.sql"), LogAssert.ExecutedSqlScript("logic.sql"), LogAssert.ExecutedSqlScript("permissions.sql"), LogAssert.SprocCompleted("dt._UpdateVersion")) .EndOfLog(); ValidateDatabaseSchema(testDb); }
/// <summary> /// Sets the provided <paramref name="orchestrationService"/> to the <paramref name="builder" />. /// </summary> /// <param name="builder">The task hub builder.</param> /// <param name="orchestrationService">The orchestration service to use.</param> /// <returns>The original builder, with orchestration service set.</returns> public static ITaskHubWorkerBuilder WithOrchestrationService( this ITaskHubWorkerBuilder builder, IOrchestrationService orchestrationService) { Check.NotNull(builder, nameof(builder)); builder.OrchestrationService = orchestrationService; return(builder); }
public void SchemaCreationIsSerializedAndIdempotent() { using TestDatabase testDb = this.CreateTestDb(); IOrchestrationService service = this.CreateServiceWithTestDb(testDb); // Simulate 4 workers starting up concurrently and trying to initialize // the same database schema. It should just work with predictable output. Parallel.For(0, 4, i => { service.CreateIfNotExistsAsync().GetAwaiter().GetResult(); }); ValidateDatabaseSchema(testDb); // Operations are expected to be serialized, making the log output deterministic. LogAssert.Sequence( this.logProvider, // 1st LogAssert.AcquiredAppLock(statusCode: 0), LogAssert.SprocCompleted("dt._GetVersions"), LogAssert.ExecutedSqlScript("schema-0.2.0.sql"), LogAssert.ExecutedSqlScript("logic.sql"), LogAssert.ExecutedSqlScript("permissions.sql"), LogAssert.SprocCompleted("dt._UpdateVersion"), // 2nd LogAssert.AcquiredAppLock(statusCode: 1), LogAssert.SprocCompleted("dt._GetVersions"), // 3rd LogAssert.AcquiredAppLock(statusCode: 1), LogAssert.SprocCompleted("dt._GetVersions"), // 4th LogAssert.AcquiredAppLock(statusCode: 1), LogAssert.SprocCompleted("dt._GetVersions")); }
internal TaskOrchestrationDispatcher( IOrchestrationService orchestrationService, INameVersionObjectManager <TaskOrchestration> objectManager, DispatchMiddlewarePipeline dispatchPipeline) { this.objectManager = objectManager ?? throw new ArgumentNullException(nameof(objectManager)); this.orchestrationService = orchestrationService ?? throw new ArgumentNullException(nameof(orchestrationService)); this.dispatchPipeline = dispatchPipeline ?? throw new ArgumentNullException(nameof(dispatchPipeline)); this.dispatcher = new WorkItemDispatcher <TaskOrchestrationWorkItem>( "TaskOrchestrationDispatcher", item => item == null ? string.Empty : item.InstanceId, OnFetchWorkItemAsync, OnProcessWorkItemSessionAsync) { GetDelayInSecondsAfterOnFetchException = orchestrationService.GetDelayInSecondsAfterOnFetchException, GetDelayInSecondsAfterOnProcessException = orchestrationService.GetDelayInSecondsAfterOnProcessException, SafeReleaseWorkItem = orchestrationService.ReleaseTaskOrchestrationWorkItemAsync, AbortWorkItem = orchestrationService.AbandonTaskOrchestrationWorkItemAsync, DispatcherCount = orchestrationService.TaskOrchestrationDispatcherCount, MaxConcurrentWorkItems = orchestrationService.MaxConcurrentTaskOrchestrationWorkItems }; // To avoid starvation, we only allow half of all concurrently execution orchestrations to // leverage extended sessions. var maxConcurrentSessions = (int)Math.Ceiling(this.dispatcher.MaxConcurrentWorkItems / 2.0); this.concurrentSessionLock = new NonBlockingCountdownLock(maxConcurrentSessions); }
/// <summary> /// Creates the default <see cref="DurabilityProvider"/>. /// </summary> /// <param name="storageProviderName">The name of the storage backend providing the durability.</param> /// <param name="service">The internal <see cref="IOrchestrationService"/> that provides functionality /// for this classes implementions of <see cref="IOrchestrationService"/>.</param> /// <param name="serviceClient">The internal <see cref="IOrchestrationServiceClient"/> that provides functionality /// for this classes implementions of <see cref="IOrchestrationServiceClient"/>.</param> /// <param name="connectionName">The name of the app setting that stores connection details for the storage provider.</param> public DurabilityProvider(string storageProviderName, IOrchestrationService service, IOrchestrationServiceClient serviceClient, string connectionName) { this.name = storageProviderName ?? throw new ArgumentNullException(nameof(storageProviderName)); this.innerService = service ?? throw new ArgumentNullException(nameof(service)); this.innerServiceClient = serviceClient ?? throw new ArgumentNullException(nameof(serviceClient)); this.connectionName = connectionName ?? throw new ArgumentNullException(connectionName); }
public WorkerHostedService( IOrchestrationService orchestrationService, TaskHubWorker taskHubWorker) { _orchestrationService = orchestrationService; _taskHubWorker = taskHubWorker; }
/// <summary> /// The entry point. /// </summary> /// <param name="args">The supplied arguments, if any.</param> /// <returns>A task that completes when this program is finished running.</returns> public static Task Main(string[] args) { IHost host = CreateDefaultBuilder(args) .ConfigureServices(services => { services.AddSingleton <IConsole, ConsoleWrapper>(); services.AddHostedService <TaskEnqueuer>(); }) .ConfigureTaskHubWorker((context, builder) => { // IOrchestrationService orchestrationService = UseServiceBus(context.Configuration); IOrchestrationService orchestrationService = UseLocalEmulator(); builder.WithOrchestrationService(orchestrationService); builder.AddClient(); builder.AddOrchestration <GreetingsOrchestration>(); builder .AddActivity <GetUserTask>() .AddActivity <SendGreetingTask>(); }) .UseConsoleLifetime() .Build(); using (DurableTaskEventListener listener = ActivatorUtilities.CreateInstance <DurableTaskEventListener>(host.Services)) { return(host.RunAsync()); } }
internal TaskActivityDispatcher( IOrchestrationService orchestrationService, INameVersionObjectManager <TaskActivity> objectManager, DispatchMiddlewarePipeline dispatchPipeline, LogHelper logHelper) { this.orchestrationService = orchestrationService ?? throw new ArgumentNullException(nameof(orchestrationService)); this.objectManager = objectManager ?? throw new ArgumentNullException(nameof(objectManager)); this.dispatchPipeline = dispatchPipeline ?? throw new ArgumentNullException(nameof(dispatchPipeline)); this.logHelper = logHelper; this.dispatcher = new WorkItemDispatcher <TaskActivityWorkItem>( "TaskActivityDispatcher", item => item.Id, this.OnFetchWorkItemAsync, this.OnProcessWorkItemAsync) { AbortWorkItem = orchestrationService.AbandonTaskActivityWorkItemAsync, GetDelayInSecondsAfterOnFetchException = orchestrationService.GetDelayInSecondsAfterOnFetchException, GetDelayInSecondsAfterOnProcessException = orchestrationService.GetDelayInSecondsAfterOnProcessException, DispatcherCount = orchestrationService.TaskActivityDispatcherCount, MaxConcurrentWorkItems = orchestrationService.MaxConcurrentTaskActivityWorkItems, LogHelper = logHelper, }; }
/// <summary> /// Create a new TaskHubWorker with given OrchestrationService /// </summary> /// <param name="orchestrationService">Reference the orchestration service implementation</param> public TaskHubWorker(IOrchestrationService orchestrationService) : this( orchestrationService, new NameVersionObjectManager <TaskOrchestration>(), new NameVersionObjectManager <TaskActivity>()) { }
/// <summary> /// Create a new TaskHubWorker with given OrchestrationService /// </summary> /// <param name="orchestrationService">Reference the orchestration service implementation</param> /// <param name="loggerFactory">The <see cref="ILoggerFactory"/> to use for logging</param> public TaskHubWorker(IOrchestrationService orchestrationService, ILoggerFactory loggerFactory = null) : this( orchestrationService, new NameVersionObjectManager <TaskOrchestration>(), new NameVersionObjectManager <TaskActivity>(), loggerFactory) { }
/// <summary> /// Create a new TaskHubWorker with given OrchestrationService and name version managers /// </summary> /// <param name="orchestrationService">Reference the orchestration service implementation</param> /// <param name="orchestrationObjectManager">NameVersionObjectManager for Orchestrations</param> /// <param name="activityObjectManager">NameVersionObjectManager for Activities</param> public TaskHubWorker( IOrchestrationService orchestrationService, INameVersionObjectManager <TaskOrchestration> orchestrationObjectManager, INameVersionObjectManager <TaskActivity> activityObjectManager) { this.orchestrationManager = orchestrationObjectManager ?? throw new ArgumentException("orchestrationObjectManager"); this.activityManager = activityObjectManager ?? throw new ArgumentException("activityObjectManager"); this.orchestrationService = orchestrationService ?? throw new ArgumentException("orchestrationService"); }
public async Task CanCreateAndDropSchema(bool isDatabaseMissing) { using TestDatabase testDb = this.CreateTestDb(!isDatabaseMissing); IOrchestrationService service = this.CreateServiceWithTestDb(testDb); // Create the DB schema for the first time await service.CreateAsync(recreateInstanceStore : true); LogAssert.NoWarningsOrErrors(this.logProvider); LogAssert .For(this.logProvider) .Expect( LogAssert.CheckedDatabase()) .ExpectIf( isDatabaseMissing, LogAssert.CommandCompleted($"CREATE DATABASE [{testDb.Name}]"), LogAssert.CreatedDatabase(testDb.Name)) .Expect( LogAssert.AcquiredAppLock(), LogAssert.ExecutedSqlScript("drop-schema.sql"), LogAssert.ExecutedSqlScript("schema-0.2.0.sql"), LogAssert.ExecutedSqlScript("logic.sql"), LogAssert.ExecutedSqlScript("permissions.sql"), LogAssert.SprocCompleted("dt._UpdateVersion")) .EndOfLog(); ValidateDatabaseSchema(testDb); // Create the DB schema again - should be a no-op since it already exists this.logProvider.Clear(); await service.CreateIfNotExistsAsync(); ValidateDatabaseSchema(testDb); // The subsequent execution should run exactly one sproc and no scripts. // It's important to verify this to ensure the overhead of CreateIfNotExistsAsync is very small. LogAssert.NoWarningsOrErrors(this.logProvider); LogAssert.Sequence( this.logProvider, LogAssert.CheckedDatabase(), LogAssert.AcquiredAppLock(), LogAssert.SprocCompleted("dt._GetVersions")); // Delete the database and validate this.logProvider.Clear(); await service.DeleteAsync(); LogAssert.NoWarningsOrErrors(this.logProvider); LogAssert.Sequence( this.logProvider, LogAssert.AcquiredAppLock(), LogAssert.ExecutedSqlScript("drop-schema.sql")); // The previous schema validation ensures all objects are in the "dt" schema. // We know that all objects were successfully removed if the "dt" no longer exists. Assert.DoesNotContain("dt", testDb.GetSchemas()); }
public async Task StopAsync_IsIdempotent() { int numStops = 3; IOrchestrationService service = TestConstants.GetTestOrchestrationService(this.loggerFactory); for (int i = 0; i < numStops; i++) { await service.StopAsync(); } }
public void SchemaCreationIsSerializedAndIdempotent(bool isDatabaseMissing) { using TestDatabase testDb = this.CreateTestDb(!isDatabaseMissing); IOrchestrationService service = this.CreateServiceWithTestDb(testDb); // Simulate 4 workers starting up concurrently and trying to initialize // the same database schema. It should just work with predictable output. Parallel.For(0, 4, i => { service.CreateIfNotExistsAsync().GetAwaiter().GetResult(); }); ValidateDatabaseSchema(testDb); // Operations are expected to be serialized, making the log output deterministic. LogAssert .For(this.logProvider) .Expect( // At least 1 worker will check the database first LogAssert.CheckedDatabase()) .Contains( // The other 3 workers will check in some non-deterministic order LogAssert.CheckedDatabase(), LogAssert.CheckedDatabase(), LogAssert.CheckedDatabase()) .ContainsIf( // One worker may obtain the lock after another worker created the database. isDatabaseMissing, LogAssert.CommandCompleted($"CREATE DATABASE [{testDb.Name}]"), LogAssert.CreatedDatabase(testDb.Name)) .OptionallyContainsIf( // Anywhere from 0 to 3 of the workers may end up attempting to create the database. isDatabaseMissing, LogAssert.CommandCompleted($"CREATE DATABASE [{testDb.Name}]"), LogAssert.CommandCompleted($"CREATE DATABASE [{testDb.Name}]"), LogAssert.CommandCompleted($"CREATE DATABASE [{testDb.Name}]")) .Expect( // 1st LogAssert.AcquiredAppLock(statusCode: 0), LogAssert.SprocCompleted("dt._GetVersions"), LogAssert.ExecutedSqlScript("schema-0.2.0.sql"), LogAssert.ExecutedSqlScript("logic.sql"), LogAssert.ExecutedSqlScript("permissions.sql"), LogAssert.SprocCompleted("dt._UpdateVersion"), // 2nd LogAssert.AcquiredAppLock(), LogAssert.SprocCompleted("dt._GetVersions"), // 3rd LogAssert.AcquiredAppLock(), LogAssert.SprocCompleted("dt._GetVersions"), // 4th LogAssert.AcquiredAppLock(), LogAssert.SprocCompleted("dt._GetVersions")) .EndOfLog(); }
/// <summary> /// Create a new <see cref="TaskHubWorker"/> with given <see cref="IOrchestrationService"/> and name version managers /// </summary> /// <param name="orchestrationService">The orchestration service implementation</param> /// <param name="orchestrationObjectManager">The <see cref="INameVersionObjectManager{TaskOrchestration}"/> for orchestrations</param> /// <param name="activityObjectManager">The <see cref="INameVersionObjectManager{TaskActivity}"/> for activities</param> /// <param name="loggerFactory">The <see cref="ILoggerFactory"/> to use for logging</param> public TaskHubWorker( IOrchestrationService orchestrationService, INameVersionObjectManager <TaskOrchestration> orchestrationObjectManager, INameVersionObjectManager <TaskActivity> activityObjectManager, ILoggerFactory loggerFactory = null) { this.orchestrationManager = orchestrationObjectManager ?? throw new ArgumentException("orchestrationObjectManager"); this.activityManager = activityObjectManager ?? throw new ArgumentException("activityObjectManager"); this.orchestrationService = orchestrationService ?? throw new ArgumentException("orchestrationService"); this.logHelper = new LogHelper(loggerFactory?.CreateLogger("DurableTask.Core")); }
/// <summary> /// Create a new TaskHubWorker with given OrchestrationService and name version managers /// </summary> /// <param name="orchestrationService">Reference the orchestration service implementation</param> /// <param name="orchestrationObjectManager">NameVersionObjectManager for Orchestrations</param> /// <param name="activityObjectManager">NameVersionObjectManager for Activities</param> public TaskHubWorker( IOrchestrationService orchestrationService, INameVersionObjectManager <TaskOrchestration> orchestrationObjectManager, INameVersionObjectManager <TaskActivity> activityObjectManager) : this( orchestrationService, orchestrationObjectManager, activityObjectManager, loggerFactory : null) { }
public void WithOrchestration_ServiceIsSet() => RunTest( builder => { IOrchestrationService service = Mock.Of <IOrchestrationService>(); ITaskHubWorkerBuilder returned = builder.WithOrchestrationService(service); builder.Should().NotBeNull(); builder.Should().BeSameAs(returned); return(service); }, (mock, service) => { mock.Object.Services.Should().Contain(x => x.ServiceType == typeof(IOrchestrationService)); });
public void WithOrchestration_ServiceIsSet() => RunTest( builder => { IOrchestrationService service = Mock.Of <IOrchestrationService>(); ITaskHubWorkerBuilder returned = builder.WithOrchestrationService(service); builder.Should().NotBeNull(); builder.Should().BeSameAs(returned); return(service); }, (mock, service) => { mock.VerifySet(m => m.OrchestrationService = service, Times.Once); });
public GrpcServerOrchestrationService( IOptions <GrpcServerOrchestrationServiceOptions> options, IOrchestrationService orchestrationService, IOrchestrationServiceClient orchestrationServiceClient, ILogger <GrpcServerOrchestrationService> logger, IExtendedOrchestrationService extendedOrchestrationService = null, IExtendedOrchestrationServiceClient extendedOrchestrationServiceClient = null) { _options = options.Value; _orchestrationService = orchestrationService; _orchestrationServiceClient = orchestrationServiceClient; _logger = logger; _extendedOrchestrationService = extendedOrchestrationService; _extendedOrchestrationServiceClient = extendedOrchestrationServiceClient; }
public WorkerOrchestrationService( IOrchestrationService innerOrchestrationService, IExtendedOrchestrationService innerExtenedOrchestrationService, IServiceScopeFactory serviceScopeFactory, IEnumerable <ObjectCreator <TaskOrchestration> > orchestrations, IEnumerable <ObjectCreator <TaskActivity> > activities, bool hasAllOrchestrations, bool hasAllActivities) { _innerOrchestrationService = innerOrchestrationService; _innerExtenedOrchestrationService = innerExtenedOrchestrationService; _serviceScopeFactory = serviceScopeFactory; _orchestrations = orchestrations.OfType <INameVersionInfo>().ToArray(); _activities = activities.OfType <INameVersionInfo>().ToArray(); _hasAllOrchestrations = hasAllOrchestrations; _hasAllActivities = hasAllActivities; }
/// <summary> /// Creates the instance of the host. /// </summary> /// <param name="orchestrationService"></param> /// <param name="orchestrationClient"></param> /// <param name="instanceStore"></param> /// <param name="resetHub"></param> /// <param name="loggerFactory"></param> /// <param name="scopes">List of scopes, which will be appended to logger scopes, every time</param> public ServiceHost(IOrchestrationService orchestrationService, IOrchestrationServiceClient orchestrationClient, IOrchestrationServiceInstanceStore instanceStore, bool resetHub = false, ILoggerFactory loggerFactory = null) { m_HubClient = new TaskHubClient(orchestrationClient); this.m_TaskHubWorker = new TaskHubWorker(orchestrationService); this.m_InstanceStoreService = instanceStore; if (loggerFactory != null) { m_LoggerFactory = loggerFactory; m_Logger = m_LoggerFactory.CreateLogger <ServiceHost>(); } if (resetHub) { orchestrationService.DeleteAsync().Wait(); } int n = 10; while (--n > 0) { try { orchestrationService.CreateIfNotExistsAsync().Wait(); break; } catch (AggregateException aggEx) { if (n <= 0) { throw; } if (aggEx.InnerException.Message.Contains("409")) { Thread.Sleep(10000); } } } }
public async Task CanCreateIfNotExists() { using TestDatabase testDb = this.CreateTestDb(); IOrchestrationService service = this.CreateServiceWithTestDb(testDb); await service.CreateIfNotExistsAsync(); LogAssert.NoWarningsOrErrors(this.logProvider); LogAssert.Sequence( this.logProvider, LogAssert.AcquiredAppLock(), LogAssert.SprocCompleted("dt._GetVersions"), LogAssert.ExecutedSqlScript("schema-0.2.0.sql"), LogAssert.ExecutedSqlScript("logic.sql"), LogAssert.ExecutedSqlScript("permissions.sql"), LogAssert.SprocCompleted("dt._UpdateVersion")); ValidateDatabaseSchema(testDb); }
/// <summary> /// The entry point. /// </summary> /// <param name="args">The supplied arguments, if any.</param> /// <returns>A task that completes when this program is finished running.</returns> public static Task Main(string[] args) { IHost host = Host.CreateDefaultBuilder(args) .ConfigureServices(services => { services.AddSingleton <IConsole, ConsoleWrapper>(); services.AddHostedService <TaskEnqueuer>(); }) .ConfigureTaskHubWorker((context, builder) => { // IOrchestrationService orchestrationService = UseServiceBus(context.Configuration); IOrchestrationService orchestrationService = UseLocalEmulator(); builder.WithOrchestrationService(orchestrationService); builder.AddClient(); builder.UseOrchestrationMiddleware <OrchestrationInstanceExMiddleware>(); builder.UseOrchestrationMiddleware <SampleMiddleware>(); builder.UseActivityMiddleware <ActivityInstanceExMiddleware>(); builder.UseActivityMiddleware <SampleMiddleware>(); builder .AddOrchestration <GreetingsOrchestration>() .AddOrchestration <GenericOrchestrationRunner>(); //builder // .AddActivity<PrintTask>() // .AddActivity<GetUserTask>() // .AddActivity<SendGreetingTask>() // .AddActivity(typeof(GenericActivity<>)); builder.AddActivitiesFromAssembly <Program>(); }) .UseConsoleLifetime() .Build(); return(host.RunAsync()); }
private static TaskHubClient ClientFactory(ITaskHubWorkerBuilder builder, IServiceProvider serviceProvider) { IOrchestrationServiceClient client = serviceProvider.GetService <IOrchestrationServiceClient>(); if (client is null) { #pragma warning disable CS0618 // Type or member is obsolete IOrchestrationService service = builder.OrchestrationService ?? serviceProvider.GetRequiredService <IOrchestrationService>(); #pragma warning restore CS0618 // Type or member is obsolete client = service as IOrchestrationServiceClient; if (client is null) { throw new InvalidOperationException( Strings.NotOrchestrationServiceClient(service.GetType())); } } ILoggerFactory loggerFactory = serviceProvider.GetRequiredService <ILoggerFactory>(); return(new TaskHubClient(client, loggerFactory: loggerFactory)); }
internal TaskOrchestrationDispatcher( IOrchestrationService orchestrationService, INameVersionObjectManager <TaskOrchestration> objectManager, DispatchMiddlewarePipeline dispatchPipeline) { this.objectManager = objectManager ?? throw new ArgumentNullException(nameof(objectManager)); this.orchestrationService = orchestrationService ?? throw new ArgumentNullException(nameof(orchestrationService)); this.dispatchPipeline = dispatchPipeline ?? throw new ArgumentNullException(nameof(dispatchPipeline)); this.dispatcher = new WorkItemDispatcher <TaskOrchestrationWorkItem>( "TaskOrchestrationDispatcher", item => item == null ? string.Empty : item.InstanceId, this.OnFetchWorkItemAsync, this.OnProcessWorkItemAsync) { GetDelayInSecondsAfterOnFetchException = orchestrationService.GetDelayInSecondsAfterOnFetchException, GetDelayInSecondsAfterOnProcessException = orchestrationService.GetDelayInSecondsAfterOnProcessException, SafeReleaseWorkItem = orchestrationService.ReleaseTaskOrchestrationWorkItemAsync, AbortWorkItem = orchestrationService.AbandonTaskOrchestrationWorkItemAsync, DispatcherCount = orchestrationService.TaskOrchestrationDispatcherCount, MaxConcurrentWorkItems = orchestrationService.MaxConcurrentTaskOrchestrationWorkItems }; }
public ServerHostedService(IOrchestrationService orchestrationService) { _orchestrationService = orchestrationService; }
public IdController(IOrchestrationService service) { _service = service; }
public LocalOrchestrationService(IOrchestrationService orchestrationService) { this.OrchestrationService = orchestrationService; }
public async Task UnstartedService_CanBeSafelyStopped() { IOrchestrationService service = TestConstants.GetTestOrchestrationService(this.loggerFactory); await service.StopAsync(); }