public async Task WorkItem_Throws_Exception_When_Logger_Is_Null_Should_Swallow_Exception() { //Arrange var settings = new BatchSettings { NumberOfParallelJobs = 1, PollingFrequency = 50, HeartBeatFrequency = 5000, }; var job = CreateJobWithException(); _store.AcquireJobAsync().Returns(Task.FromResult(job), Task.FromResult((JobDescription)null)); //Act using (var engine = new BatchEngine(_store, _dependencyResolver, null, settings)) { engine.Start(); await Task.Delay(10); } //Assert AssertNoErrorsLogged(); }
public async Task Heart_Neat_Failed_Should_Log_Error() { //Arrange var settings = new BatchSettings { NumberOfParallelJobs = 1, PollingFrequency = 500, HeartBeatFrequency = 50, }; _store.HeartBeatAsync(Environment.MachineName, 1, 500, 50) .Throws(x => new Exception("Some error")); //Act using (var engine = new BatchEngine(_store, _dependencyResolver, _logger, settings)) { engine.Start(); await Task.Delay(150); } //Assert await _store.Received().HeartBeatAsync(Environment.MachineName, 1, 500, 50); _logger.Received().Log( LogLevel.Error, Arg.Any <EventId>(), Arg.Is <object>(o => o.ToString().StartsWith("Error while sending heartbeat, System.Exception: Some error")), null, Arg.Any <Func <object, Exception, string> >()); }
public async Task Heart_Beat_Failed_When_Logger_Is_Null_Should_Swallow_Error() { //Arrange var settings = new BatchSettings { NumberOfParallelJobs = 1, PollingFrequency = 500, HeartBeatFrequency = 50, }; _store.HeartBeatAsync(Environment.MachineName, 1, 500, 50) .Throws(x => new Exception("Some error")); //Act using (var engine = new BatchEngine(_store, _dependencyResolver, null, settings)) { engine.Start(); await Task.Delay(150); } //Assert await _store.Received().HeartBeatAsync(Environment.MachineName, 1, 500, 50); AssertNoErrorsLogged(); }
public async Task Semaphore_Released_After_Done_Executing() { //Arrange var settings = new BatchSettings { NumberOfParallelJobs = 1, PollingFrequency = 50, HeartBeatFrequency = 5000, }; var job1 = Task.FromResult(CreateJob(1)); var job2 = Task.FromResult(CreateJob(2)); _store.AcquireJobAsync().Returns(job1, job2, Task.FromResult((JobDescription)null)); var service = Substitute.For <ITestService>(); _dependencyResolver.Resolve(typeof(ITestService), out _).Returns(x => { x[1] = service; return(true); }); //Act using (var engine = new BatchEngine(_store, _dependencyResolver, _logger, settings)) { engine.Start(); await Task.Delay(150); } //Assert Received.InOrder(() => { service.DoSomethingAsync(1); service.DoSomethingAsync(2); }); await _store.Received().AcquireJobAsync(); await service.Received(2).DoSomethingAsync(Arg.Any <int>()); AssertNoErrorsLogged(); }
public async Task Successful_Job_Should_Release_With_Given_Result() { //Arrange var settings = new BatchSettings { NumberOfParallelJobs = 1, PollingFrequency = 50, HeartBeatFrequency = 5000, }; var data = new TestJobWithReturnData.TestData { State = ExecutionState.Halted, StatusInfo = "info", DueTime = new DateTime(2018, 1, 2, 3, 4, 5) }; var job = CreateJobWithReturnData(data); job.Id = Guid.NewGuid(); _store.AcquireJobAsync().Returns(Task.FromResult(job), Task.FromResult((JobDescription)null)); JobResult result = null; await _store.ReleaseJobAsync(job.Id, Arg.Do <JobResult>(x => result = x)); //Act using (var engine = new BatchEngine(_store, _dependencyResolver, _logger, settings)) { engine.Start(); await Task.Delay(10); } //Assert Assert.Equal(data.State, result.State); Assert.Equal(data.StatusInfo, result.StatusInfo); Assert.Equal(data.DueTime, result.DueTime); await _store.Received(1).ReleaseJobAsync(job.Id, result); AssertNoErrorsLogged(); }
static void Main(string[] args) { //Setup var dateService = new UtcDateService(); var store = new InMemoryStorage(dateService); var resolver = new SimpleResolver(dateService); ILogger logger = null; var settings = new BatchSettings { HeartBeatFrequency = 2000, NumberOfParallelJobs = 2, PollingFrequency = 500 }; var scheduler = new JobScheduler(store, dateService); //Add a sequence of jobs var sequence = new Sequence(); sequence.Add <SimpleJob>(); sequence.Add <JobWithInput, JobWithInput.Input>(new JobWithInput.Input { Text = "this is awesome!" }); //Queue the sequence scheduler.QueueAsync(sequence).Wait(); //Add a single job scheduler.QueueAsync <RecurringJob>(); //Start the engine using (var engine = new BatchEngine(store, resolver, logger, settings)) { Console.WriteLine("Starting ..."); engine.Start(); Console.ReadKey(); } }
static void Main(string[] args) { //Setup var resolver = new SimpleResolver(); MinionConfiguration.Configuration.UseDependencyResolver(resolver); MinionConfiguration.Configuration.UseInMemoryStorage(); //MinionConfiguration.Configuration.UseSqlStorage("<ConnectionString>"); MinionConfiguration.Configuration.HeartBeatFrequency = 2000; MinionConfiguration.Configuration.NumberOfParallelJobs = 2; MinionConfiguration.Configuration.PollingFrequency = 500; var scheduler = new JobScheduler(); //Add a sequence of jobs var sequence = new Sequence(); sequence.Add <SimpleJob>(); sequence.Add <JobWithInput, JobWithInput.Input>(new JobWithInput.Input { Text = "this is awesome!" }); //Queue the sequence scheduler.QueueAsync(sequence).Wait(); //Add a single job scheduler.QueueAsync <RecurringJob>(); //Start the engine using (var engine = new BatchEngine()) { Console.WriteLine("Starting ..."); engine.Start(); Console.ReadKey(); } }
public void Start_Without_Store() { //Arrange var settings = new BatchSettings { NumberOfParallelJobs = 1, PollingFrequency = 1000, HeartBeatFrequency = 50, }; InvalidOperationException ex; //Act using (var engine = new BatchEngine(null, null, null, settings)) { ex = Assert.Throws <InvalidOperationException>(() => engine.Start()); } //Assert Assert.Equal("Cannot start without storage.", ex.Message); }
public async Task Job_Throws_Exception_Should_Release_With_Error_State() { //Arrange var settings = new BatchSettings { NumberOfParallelJobs = 1, PollingFrequency = 50, HeartBeatFrequency = 5000, }; var job = CreateJobWithException(); _store.AcquireJobAsync().Returns(Task.FromResult(job), Task.FromResult((JobDescription)null)); JobResult result = null; await _store.ReleaseJobAsync(job.Id, Arg.Do <JobResult>(x => result = x)); //Act using (var engine = new BatchEngine(_store, _dependencyResolver, _logger, settings)) { engine.Start(); await Task.Delay(10); } //Assert Assert.Equal(ExecutionState.Error, result.State); Assert.StartsWith("System.NotImplementedException: Method not implemented.", result.StatusInfo); Assert.Equal(job.DueTime, result.DueTime); await _store.Received(1).ReleaseJobAsync(job.Id, result); _logger.Received(1).Log( LogLevel.Error, Arg.Any <EventId>(), Arg.Is <object>(x => x.ToString().StartsWith("Error while processing work item, ")), null, Arg.Any <Func <object, Exception, string> >()); }
public async Task Batch_Engine_Should_Send_Heart_Beat() { //Arrange var settings = new BatchSettings { NumberOfParallelJobs = 1, PollingFrequency = 1000, HeartBeatFrequency = 50, }; //Act using (var engine = new BatchEngine(_store, _dependencyResolver, _logger, settings)) { engine.Start(); await Task.Delay(150); } //Assert await _store.Received().HeartBeatAsync(Environment.MachineName, 1, 1000, 50); AssertNoErrorsLogged(); }
public async Task Polling_Frequency_Zero_Should_Release_Semaphore() { //Arrange var settings = new BatchSettings { NumberOfParallelJobs = 1, PollingFrequency = 0, HeartBeatFrequency = 5000, }; var data = new TestJobWithReturnData.TestData { State = ExecutionState.Waiting, StatusInfo = "info", DueTime = new DateTime(2018, 1, 2, 3, 4, 5) }; var job = CreateJobWithReturnData(data); job.Id = Guid.NewGuid(); _store.AcquireJobAsync().Returns(Task.FromResult(job), Task.FromResult((JobDescription)null), Task.FromResult(job), Task.FromResult((JobDescription)null)); //Act using (var engine = new BatchEngine(_store, _dependencyResolver, _logger, settings)) { engine.Start(); await Task.Delay(200); } //Assert await _store.Received(2).ReleaseJobAsync(job.Id, Arg.Any <JobResult>()); AssertNoErrorsLogged(); }
public async Task Should_Wait_For_Executing_Job_To_Finish_Before_Shut_Down() { //Arrange var settings = new BatchSettings { NumberOfParallelJobs = 1, PollingFrequency = 50, HeartBeatFrequency = 5000, }; var job = Task.FromResult(CreateDelayedJob(300)); _store.AcquireJobAsync().Returns(job, Task.FromResult((JobDescription)null)); var service = Substitute.For <ITestService>(); _dependencyResolver.Resolve(typeof(ITestService), out _).Returns(x => { x[1] = service; return(true); }); //Act using (var engine = new BatchEngine(_store, _dependencyResolver, _logger, settings)) { engine.Start(); await Task.Delay(10); } //Assert await service.Received(1).DoSomethingAsync(300); AssertNoErrorsLogged(); }
public async Task Invoke(HttpContext httpContext) { var path = httpContext.Request.Path.Value; if (!methodLookup.TryGetValue(path, out var methodInfo)) { await next(httpContext); return; } // create args string[] args = null; try { if (httpContext.Request.HasFormContentType) { args = new string[(httpContext.Request.Form.Count * 2) + 1]; { var i = 0; args[i++] = methodInfo.DeclaringType.Name + "." + methodInfo.Name; foreach (var item in httpContext.Request.Form) { args[i++] = "-" + item.Key; args[i++] = (item.Value.Count == 0) ? null : (item.Value.Count == 1) ? item.Value[0] : "[" + string.Join(", ", item.Value) + "]"; } } } else { args = new[] { methodInfo.DeclaringType.Name + "." + methodInfo.Name }; } } catch (Exception ex) { httpContext.Response.ContentType = "text/plain"; httpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError; await httpContext.Response.WriteAsync(ex.ToString()); return; } // run with collect statuses var hostingInterceptor = new WebHostingInterceptor(interceptor); var collectLogger = new LogCollector(logger); var engine = new BatchEngine(collectLogger, provider, hostingInterceptor, httpContext.RequestAborted); await engine.RunAsync(methodInfo.DeclaringType, methodInfo, args); // out result if (hostingInterceptor.CompleteSuccessfully) { httpContext.Response.ContentType = "text/plain"; httpContext.Response.StatusCode = (int)HttpStatusCode.OK; await httpContext.Response.WriteAsync(collectLogger.ToString()); } else { var errorMsg = ((hostingInterceptor.ErrorMessage != null) ? hostingInterceptor.ErrorMessage + Environment.NewLine : "") + ((hostingInterceptor.Exception != null) ? hostingInterceptor.Exception.ToString() : ""); httpContext.Response.ContentType = "text/plain"; httpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError; await httpContext.Response.WriteAsync(errorMsg); } }