public void TestSdkMarkerIsWrittenWhenInAzureWebSites() { // Arrange string tempDir = Path.GetTempPath(); const string filename = "WebJobsSdk.marker"; var path = Path.Combine(tempDir, filename); File.Delete(path); IServiceProvider configuration = CreateConfiguration(); using (JobHost host = new JobHost(configuration)) { try { Environment.SetEnvironmentVariable(WebSitesKnownKeyNames.JobDataPath, tempDir); // Act host.Start(); // Assert Assert.True(File.Exists(path), "SDK marker file should have been written"); } finally { Environment.SetEnvironmentVariable(WebSitesKnownKeyNames.JobDataPath, null); File.Delete(path); } } }
public void BlobGetsProcessedOnlyOnce_SingleHost() { TextWriter hold = Console.Out; StringWriter consoleOutput = new StringWriter(); Console.SetOut(consoleOutput); CloudBlockBlob blob = _testContainer.GetBlockBlobReference(BlobName); blob.UploadText("0"); int timeToProcess; // Process the blob first using (_blobProcessedEvent = new ManualResetEvent(initialState: false)) using (JobHost host = new JobHost(_hostConfiguration)) { DateTime startTime = DateTime.Now; host.Start(); Assert.True(_blobProcessedEvent.WaitOne(TimeSpan.FromSeconds(60))); timeToProcess = (int)(DateTime.Now - startTime).TotalMilliseconds; host.Stop(); Console.SetOut(hold); string[] consoleOutputLines = consoleOutput.ToString().Trim().Split(new string[] { Environment.NewLine }, StringSplitOptions.None); string[] expectedOutputLines = new string[] { "Found the following functions:", "Microsoft.Azure.WebJobs.Host.EndToEndTests.BlobTriggerTests.SingleBlobTrigger", "Job host started", string.Format("Executing: 'BlobTriggerTests.SingleBlobTrigger' - Reason: 'New blob detected: {0}/{1}'", blob.Container.Name, blob.Name), "Executed: 'BlobTriggerTests.SingleBlobTrigger' (Succeeded)", "Job host stopped", }; Assert.True(consoleOutputLines.SequenceEqual(expectedOutputLines)); } // Then start again and make sure the blob doesn't get reprocessed // wait twice the amount of time required to process first before // deciding that it doesn't get reprocessed using (_blobProcessedEvent = new ManualResetEvent(initialState: false)) using (JobHost host = new JobHost(_hostConfiguration)) { host.Start(); bool blobReprocessed = _blobProcessedEvent.WaitOne(2 * timeToProcess); host.Stop(); Assert.False(blobReprocessed); } }
public void StartAsync_WhenStarted_Throws() { // Arrange using (JobHost host = new JobHost(CreateConfiguration())) { host.Start(); // Act & Assert ExceptionAssert.ThrowsInvalidOperation(() => host.StartAsync(), "Start has already been called."); } }
public void BlobChainTest() { // write the initial trigger blob to start the chain var blobClient = _storageAccount.CreateCloudBlobClient(); var container = blobClient.GetContainerReference(_nameResolver.ResolveInString(BlobChainContainerName)); container.CreateIfNotExists(); CloudBlockBlob blob = container.GetBlockBlobReference(BlobChainTriggerBlobName); blob.UploadText("0"); using (_completedEvent = new ManualResetEvent(initialState: false)) using (JobHost host = new JobHost(_hostConfiguration)) { host.Start(); Assert.True(_completedEvent.WaitOne(TimeSpan.FromSeconds(60))); } }
protected void RunTestHost(JobHostConfiguration config) { using (JobHost host = new JobHost(config)) using (DoneNotificationFunction._doneEvent = new ManualResetEvent(initialState: false)) { host.Start(); DoneNotificationFunction._doneEvent.WaitOne(); try { host.Stop(); } catch { // We don't care about errors here } } }
private void EndToEndTestInternal(bool uploadBlobBeforeHostStart) { // Reinitialize the name resolver to avoid conflicts _resolver = new RandomNameResolver(); JobHostConfiguration hostConfig = new JobHostConfiguration() { NameResolver = _resolver, TypeLocator = new FakeTypeLocator( this.GetType(), typeof(BlobToCustomObjectBinder)) }; _storageAccount = CloudStorageAccount.Parse(hostConfig.StorageConnectionString); if (uploadBlobBeforeHostStart) { // The function will be triggered fast because the blob is already there UploadTestObject(); } // The jobs host is started JobHost host = new JobHost(hostConfig); _functionChainWaitHandle = new ManualResetEvent(initialState: false); host.Start(); if (!uploadBlobBeforeHostStart) { WaitForTestFunctionsToStart(); UploadTestObject(); } bool signaled = _functionChainWaitHandle.WaitOne(15 * 60 * 1000); // Stop the host and wait for it to finish host.Stop(); Assert.True(signaled); // Verify VerifyTableResults(); }
private async Task EndToEndTest(bool uploadBlobBeforeHostStart) { // Reinitialize the name resolver to avoid conflicts _resolver = new RandomNameResolver(); JobHostConfiguration hostConfig = new JobHostConfiguration() { NameResolver = _resolver, TypeLocator = new FakeTypeLocator( this.GetType(), typeof(BlobToCustomObjectBinder)) }; hostConfig.AddService <IWebJobsExceptionHandler>(new TestExceptionHandler()); if (uploadBlobBeforeHostStart) { // The function will be triggered fast because the blob is already there await UploadTestObject(); } // The jobs host is started JobHost host = new JobHost(hostConfig); _functionChainWaitHandle = new ManualResetEvent(initialState: false); host.Start(); if (!uploadBlobBeforeHostStart) { await WaitForTestFunctionsToStart(); await UploadTestObject(); } bool signaled = _functionChainWaitHandle.WaitOne(15 * 1000); // Stop the host and wait for it to finish host.Stop(); Assert.True(signaled); // Verify await VerifyTableResultsAsync(); }
private void RunTest(Type testType, string testName, INotificationHubClientServiceFactory factory, TraceWriter testTrace, object argument = null, string configConnectionString = ConfigConnStr, string configHubName = ConfigHubName, bool includeDefaultConnectionString = true, bool includeDefaultHubName = true) { ExplicitTypeLocator locator = new ExplicitTypeLocator(testType); JobHostConfiguration config = new JobHostConfiguration { TypeLocator = locator, }; config.Tracing.Tracers.Add(testTrace); var arguments = new Dictionary <string, object>(); arguments.Add("triggerData", argument); var notificationHubConfig = new NotificationHubsConfiguration() { ConnectionString = configConnectionString, HubName = configHubName, NotificationHubClientServiceFactory = factory }; var resolver = new TestNameResolver(); resolver.Values.Add("HubName", "ResolvedHubName"); resolver.Values.Add("MyConnectionString", AttributeConnStr); if (includeDefaultConnectionString) { resolver.Values.Add(NotificationHubsConfiguration.NotificationHubConnectionStringName, DefaultConnStr); } if (includeDefaultHubName) { resolver.Values.Add(NotificationHubsConfiguration.NotificationHubSettingName, DefaultHubName); } config.NameResolver = resolver; config.UseNotificationHubs(notificationHubConfig); JobHost host = new JobHost(config); host.Start(); host.Call(testType.GetMethod(testName), arguments); host.Stop(); }
static void Main() { CreateDemoData(); JobHost host = new JobHost(); host.Start(); // Stop the host if Ctrl + C/Ctrl + Break is pressed Console.CancelKeyPress += (sender, args) => { host.Stop(); }; while (true) { Thread.Sleep(500); } }
public async Task SingletonTriggerFunction_MultipleConcurrentInvocations_InvocationsAreSerialized() { JobHost host = CreateTestJobHost(1); host.Start(); // trigger a bunch of parallel invocations int numMessages = 20; List <Task> invokeTasks = new List <Task>(); JsonSerializer serializer = new JsonSerializer(); for (int i = 0; i < numMessages; i++) { int zone = _rand.Next(3) + 1; JObject workItem = new JObject { { "ID", i + 1 }, { "Region", "Central" }, { "Zone", zone }, { "Category", 3 }, { "Description", "Test Work Item " + i } }; await host.CallAsync(typeof(TestJobs).GetMethod("EnqueueQueue2TestMessage"), new { message = workItem.ToString() }); } // wait for all the messages to be processed by the job await TestHelpers.Await(() => { return((TestJobs.Queue2MessageCount == numMessages && TestJobs.JobInvocations.Select(p => p.Value).Sum() == numMessages) || TestJobs.FailureDetected); }, pollingInterval : 500); Assert.False(TestJobs.FailureDetected); Assert.Equal(numMessages, TestJobs.JobInvocations[1]); await VerifyLeaseState(typeof(TestJobs).GetMethod("SingletonTriggerJob"), SingletonScope.Function, "Central/1", LeaseState.Available, LeaseStatus.Unlocked); await VerifyLeaseState(typeof(TestJobs).GetMethod("SingletonTriggerJob"), SingletonScope.Function, "Central/2", LeaseState.Available, LeaseStatus.Unlocked); await VerifyLeaseState(typeof(TestJobs).GetMethod("SingletonTriggerJob"), SingletonScope.Function, "Central/3", LeaseState.Available, LeaseStatus.Unlocked); host.Stop(); host.Dispose(); }
public void GlobalErrorHandler_ManualSubscriberFails_NoInfiniteLoop() { JobHostConfiguration config = new JobHostConfiguration() { TypeLocator = new ExplicitTypeLocator(typeof(ErrorProgram)) }; config.UseCore(); int notificationCount = 0; var traceMonitor = new TraceMonitor() .Filter(p => { return(true); }) .Subscribe(p => { notificationCount++; throw new Exception("Kaboom"); }); config.Tracing.Tracers.Add(traceMonitor); JobHost host = new JobHost(config); host.Start(); TestTraceWriter traceWriter = new TestTraceWriter(); config.Tracing.Tracers.Add(traceWriter); MethodInfo method = typeof(ErrorProgram).GetMethod("Throw"); CallSafe(host, method); Assert.Equal(1, notificationCount); var events = traceWriter.Events; Assert.Equal(4, events.Count); Assert.True(events[0].Message.StartsWith("Executing: 'ErrorProgram.Throw'")); Assert.True(events[1].Message.StartsWith("Exception while executing function: ErrorProgram.Throw")); Assert.True(events[2].Message.StartsWith("Executed: 'ErrorProgram.Throw' (Failed)")); Assert.True(events[3].Message.StartsWith(" Function had errors. See Azure WebJobs SDK dashboard for details.")); }
public void GlobalErrorHandler_HandlerFails_NoInfiniteLoop() { ErrorTriggerProgram_GlobalCatchAllHandler instance = new ErrorTriggerProgram_GlobalCatchAllHandler(fail: true); JobHostConfiguration config = new JobHostConfiguration() { TypeLocator = new ExplicitTypeLocator(instance.GetType()), JobActivator = new ExplicitJobActivator(instance) }; config.UseCore(); JobHost host = new JobHost(config); host.Start(); TestTraceWriter traceWriter = new TestTraceWriter(); config.Tracing.Tracers.Add(traceWriter); MethodInfo method = instance.GetType().GetMethod("Throw"); CallSafe(host, method); Assert.Equal(1, instance.Errors.Count); TraceEvent error = instance.Errors.Single(); Assert.Equal("Exception while executing function: ErrorTriggerProgram_GlobalCatchAllHandler.Throw", error.Message); // make sure the error handler failure is still logged var events = traceWriter.Events; Assert.Equal(8, events.Count); Assert.True(events[0].Message.StartsWith("Executing: 'ErrorTriggerProgram_GlobalCatchAllHandler.Throw'")); Assert.True(events[1].Message.StartsWith("Executing: 'ErrorTriggerProgram_GlobalCatchAllHandler.ErrorHandler'")); Assert.True(events[2].Message.StartsWith("Exception while executing function: ErrorTriggerProgram_GlobalCatchAllHandler.ErrorHandler")); Assert.Equal("Kaboom!", events[3].Exception.InnerException.Message); Assert.True(events[3].Message.StartsWith("Executed: 'ErrorTriggerProgram_GlobalCatchAllHandler.ErrorHandler' (Failed)")); Assert.True(events[4].Message.StartsWith(" Function had errors. See Azure WebJobs SDK dashboard for details.")); Assert.True(events[5].Message.StartsWith("Exception while executing function: ErrorTriggerProgram_GlobalCatchAllHandler.Throw")); Assert.True(events[6].Message.StartsWith("Executed: 'ErrorTriggerProgram_GlobalCatchAllHandler.Throw' (Failed)")); Assert.True(events[7].Message.StartsWith(" Function had errors. See Azure WebJobs SDK dashboard for details.")); }
public void IndexingExceptions_CanBeHandledByTraceWriter() { JobHostConfiguration config = new JobHostConfiguration(); TestTraceWriter traceWriter = new TestTraceWriter(TraceLevel.Verbose); config.Tracing.Tracers.Add(traceWriter); config.TypeLocator = new FakeTypeLocator(typeof(BindingErrorsProgram)); FunctionErrorTraceWriter errorTraceWriter = new FunctionErrorTraceWriter(TraceLevel.Error); config.Tracing.Tracers.Add(errorTraceWriter); JobHost host = new JobHost(config); host.Start(); // verify the handled binding error FunctionIndexingException fex = errorTraceWriter.Errors.SingleOrDefault() as FunctionIndexingException; Assert.True(fex.Handled); Assert.Equal("BindingErrorsProgram.Invalid", fex.MethodName); // verify that the binding error was logged Assert.Equal(3, traceWriter.Traces.Count); TraceEvent traceEvent = traceWriter.Traces[0]; Assert.Equal("Error indexing method 'BindingErrorsProgram.Invalid'", traceEvent.Message); Assert.Same(fex, traceEvent.Exception); Assert.Equal("Invalid container name: invalid$=+1", traceEvent.Exception.InnerException.Message); // verify that the valid function was still indexed traceEvent = traceWriter.Traces[1]; Assert.True(traceEvent.Message.Contains("Found the following functions")); Assert.True(traceEvent.Message.Contains("BindingErrorsProgram.Valid")); // verify that the job host was started successfully traceEvent = traceWriter.Traces[2]; Assert.Equal("Job host started", traceEvent.Message); host.Stop(); host.Dispose(); }
public void MaxDegreeOfParallelism_Queues(int batchSize, int maxExpectedParallelism) { _receivedMessages = 0; _currentSimultaneouslyRunningFunctions = 0; _maxSimultaneouslyRunningFunctions = 0; _numberOfQueueMessages = batchSize * 3; RandomNameResolver nameResolver = new RandomNameResolver(); JobHostConfiguration hostConfiguration = new JobHostConfiguration() { NameResolver = nameResolver, TypeLocator = new FakeTypeLocator(typeof(ParallelExecutionTests)), }; hostConfiguration.Queues.BatchSize = batchSize; //hostConfiguration.Queues.NewBatchThreshold = Math.Max(1, batchSize / 2); CloudStorageAccount storageAccount = CloudStorageAccount.Parse(hostConfiguration.StorageConnectionString); _queueClient = storageAccount.CreateCloudQueueClient(); CloudQueue queue = _queueClient.GetQueueReference(nameResolver.ResolveInString(TestQueueName)); queue.CreateIfNotExists(); for (int i = 0; i < _numberOfQueueMessages; i++) { int sleepTimeInSeconds = i % 2 == 0 ? 5 : 1; queue.AddMessage(new CloudQueueMessage(sleepTimeInSeconds.ToString())); } using (_allMessagesProcessed = new ManualResetEvent(initialState: false)) using (JobHost host = new JobHost(hostConfiguration)) { host.Start(); _allMessagesProcessed.WaitOne(TimeSpan.FromSeconds(90)); host.Stop(); } Assert.Equal(_numberOfQueueMessages, _receivedMessages); Assert.Equal(0, _currentSimultaneouslyRunningFunctions); Assert.Equal(maxExpectedParallelism, _maxSimultaneouslyRunningFunctions); }
private async Task RunTimerJobTest(Type jobClassType, Func <bool> condition) { ExplicitTypeLocator locator = new ExplicitTypeLocator(jobClassType); JobHostConfiguration config = new JobHostConfiguration { TypeLocator = locator }; config.UseTimers(); JobHost host = new JobHost(config); host.Start(); await TestHelpers.Await(() => { return(condition()); }); host.Stop(); }
public async Task BlobChainTest() { // write the initial trigger blob to start the chain var blobClient = _storageAccount.CreateCloudBlobClient(); var container = blobClient.GetContainerReference(_nameResolver.ResolveInString(BlobChainContainerName)); await container.CreateIfNotExistsAsync(); CloudBlockBlob blob = container.GetBlockBlobReference(BlobChainTriggerBlobName); await blob.UploadTextAsync("0"); var prog = new BlobChainTest_Program(); var config = NewConfig(prog); using (prog._completedEvent = new ManualResetEvent(initialState: false)) using (JobHost host = new JobHost(config)) { host.Start(); Assert.True(prog._completedEvent.WaitOne(TimeSpan.FromSeconds(60))); } }
public TestFixture() { int testPort = 43000; BaseUrl = string.Format("http://localhost:{0}/", testPort); Client = new HttpClient(); Client.BaseAddress = new Uri(BaseUrl); JobHostConfiguration config = new JobHostConfiguration { TypeLocator = new ExplicitTypeLocator(typeof(WebHookTestFunctions)) }; WebHooksConfiguration webHooksConfig = new WebHooksConfiguration(testPort); webHooksConfig.UseReceiver <GitHubWebHookReceiver>(); config.UseWebHooks(webHooksConfig); Host = new JobHost(config); Host.Start(); }
public void BlobGetsProcessedOnlyOnce_MultipleHosts() { _testContainer .GetBlockBlobReference(BlobName) .UploadText("10"); using (_blobProcessedEvent = new ManualResetEvent(initialState: false)) using (JobHost host1 = new JobHost(_hostConfiguration)) using (JobHost host2 = new JobHost(_hostConfiguration)) { host1.Start(); host2.Start(); Assert.True(_blobProcessedEvent.WaitOne(TimeSpan.FromSeconds(60))); host1.Stop(); host2.Stop(); } Assert.Equal(1, _timesProcessed); }
static void Main(string[] args) { using (var listener = new ObservableEventListener()) { listener.LogToConsole(new ConsoleFormatter()); listener.EnableEvents(EngineEventSource.Log, EventLevel.Verbose, Keywords.All); listener.EnableEvents(TableStorageEventSource.Log, EventLevel.Verbose, Keywords.All); var eventContext = new TableStorageJobEventContext( CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageAccount"))); var host = new JobHost(eventContext); host.Add(new LogCleanupJob()); host.Add(new SendNewsletterJob()); host.Add(new LongRunningJob()); host.Start(); Console.WriteLine("Waiting..."); Console.ReadLine(); } }
static void Main() { //CreateDemoData(); GetNextMessage(); EnCryptDecrypt.CryptorEngine.Decrypt(); JobHost host = new JobHost(); host.Start(); // Stop the host if Ctrl + C/Ctrl + Break is pressed Console.CancelKeyPress += (sender, args) => { host.Stop(); }; while (true) { Thread.Sleep(500); } }
private void RunTest(Type testType, string testName, IDocumentDBServiceFactory factory, TraceWriter testTrace, object argument = null, DocumentDBConfiguration documentDBConfig = null) { ExplicitTypeLocator locator = new ExplicitTypeLocator(testType); JobHostConfiguration config = new JobHostConfiguration { TypeLocator = locator, }; config.Tracing.Tracers.Add(testTrace); var arguments = new Dictionary <string, object>(); arguments.Add("triggerData", argument); if (documentDBConfig == null) { documentDBConfig = new DocumentDBConfiguration() { ConnectionString = "AccountEndpoint=https://someuri;AccountKey=some_key", DocumentDBServiceFactory = factory }; } var resolver = new TestNameResolver(); resolver.Values.Add("Database", "ResolvedDatabase"); resolver.Values.Add("Collection", "ResolvedCollection"); config.NameResolver = resolver; config.UseDocumentDB(documentDBConfig); JobHost host = new JobHost(config); host.Start(); host.Call(testType.GetMethod(testName), arguments); host.Stop(); }
static void Main(string[] vargStrings) { var configuration = new JobHostConfiguration(); configuration.Queues.MaxPollingInterval = TimeSpan.FromSeconds(30); configuration.Queues.MaxDequeueCount = 10; configuration.Queues.BatchSize = 1; var host = new JobHost(configuration); host.Start(); // Stop the host if Ctrl + C/Ctrl + Break is pressed Console.CancelKeyPress += (sender, args) => { host.Stop(); }; while (true) { Thread.Sleep(500); } }
public async Task BlobGetsProcessedOnlyOnce_MultipleHosts() { await _testContainer .GetBlockBlobReference(TestBlobName) .UploadTextAsync("10"); var prog = new BlobGetsProcessedOnlyOnce_SingleHost_Program(); var config = NewConfig(prog); using (prog._completedEvent = new ManualResetEvent(initialState: false)) using (JobHost host1 = new JobHost(config)) using (JobHost host2 = new JobHost(config)) { host1.Start(); host2.Start(); Assert.True(prog._completedEvent.WaitOne(TimeSpan.FromSeconds(60))); } Assert.Equal(1, prog._timesProcessed); }
public void Queue_IfNameIsInvalid_ThrowsDuringIndexing() { IStorageAccount account = CreateFakeStorageAccount(); TaskCompletionSource<object> backgroundTaskSource = new TaskCompletionSource<object>(); IServiceProvider serviceProvider = FunctionalTest.CreateServiceProviderForCallFailure(account, typeof(InvalidQueueNameProgram), backgroundTaskSource); using (JobHost host = new JobHost(serviceProvider)) { // Act & Assert FunctionIndexingException exception = Assert.Throws<FunctionIndexingException>(() => host.Start()); Assert.Equal("Error indexing method 'InvalidQueueNameProgram.Invalid'", exception.Message); Exception innerException = exception.InnerException; Assert.IsType<ArgumentException>(innerException); ArgumentException argumentException = (ArgumentException)innerException; Assert.Equal("name", argumentException.ParamName); string expectedMessage = String.Format(CultureInfo.InvariantCulture, "The dash (-) character may not be the first or last letter - \"-illegalname-\"{0}Parameter " + "name: name", Environment.NewLine); Assert.Equal(expectedMessage, innerException.Message); Assert.Equal(TaskStatus.WaitingForActivation, backgroundTaskSource.Task.Status); } }
public void GlobalErrorHandler_CatchAll_InvokedAsExpected() { ErrorTriggerProgram_GlobalCatchAllHandler instance = new ErrorTriggerProgram_GlobalCatchAllHandler(); JobHostConfiguration config = new JobHostConfiguration() { TypeLocator = new ExplicitTypeLocator(instance.GetType()), JobActivator = new ExplicitJobActivator(instance) }; config.UseCore(); JobHost host = new JobHost(config); host.Start(); MethodInfo method = instance.GetType().GetMethod("Throw"); CallSafe(host, method); Assert.NotNull(instance.TraceFilter); Assert.Equal("One or more WebJob errors have occurred.", instance.TraceFilter.Message); Assert.Equal(1, instance.TraceFilter.Events.Count); }
public void BlobGetsProcessedOnlyOnce_SingleHost() { _testContainer .GetBlockBlobReference(BlobName) .UploadText("0"); int timeToProcess; // Process the blob first using (_blobProcessedEvent = new ManualResetEvent(initialState: false)) using (JobHost host = new JobHost(_hostConfiguration)) { DateTime startTime = DateTime.Now; host.Start(); Assert.True(_blobProcessedEvent.WaitOne(TimeSpan.FromSeconds(60))); timeToProcess = (int)(DateTime.Now - startTime).TotalMilliseconds; host.Stop(); } // Then start again and make sure the blob doesn't get reprocessed // wait twice the amount of time required to process first before // deciding that it doesn't get reprocessed using (_blobProcessedEvent = new ManualResetEvent(initialState: false)) using (JobHost host = new JobHost(_hostConfiguration)) { host.Start(); bool blobReprocessed = _blobProcessedEvent.WaitOne(2 * timeToProcess); host.Stop(); Assert.False(blobReprocessed); } }
private async Task RunTimerJobTest(Type jobClassType, Func<bool> condition) { TestTraceWriter testTrace = new TestTraceWriter(TraceLevel.Error); ExplicitTypeLocator locator = new ExplicitTypeLocator(jobClassType); JobHostConfiguration config = new JobHostConfiguration { TypeLocator = locator }; config.UseTimers(); config.Tracing.Tracers.Add(testTrace); JobHost host = new JobHost(config); host.Start(); await TestHelpers.Await(() => { return condition(); }); host.Stop(); // ensure there were no errors Assert.Equal(0, testTrace.Events.Count); }
public async Task SingletonNonTriggeredFunction_MultipleConcurrentInvocations_InvocationsAreSerialized() { JobHost host = CreateTestJobHost(1); host.Start(); // make a bunch of parallel invocations int numInvocations = 20; List <Task> invokeTasks = new List <Task>(); MethodInfo method = typeof(TestJobs).GetMethod(nameof(TestJobs.SingletonJob)); for (int i = 0; i < numInvocations; i++) { int zone = _rand.Next(3) + 1; WorkItem workItem = new WorkItem { ID = i + 1, Region = "Central", Zone = zone, Category = 3, Description = "Test Work Item " + i }; invokeTasks.Add(host.CallAsync(method, new { workItem = workItem })); } await Task.WhenAll(invokeTasks); Assert.False(TestJobs.FailureDetected); Assert.Equal(numInvocations, TestJobs.JobInvocations[1]); await VerifyLeaseState(method, SingletonScope.Function, "TestValue", LeaseState.Available, LeaseStatus.Unlocked); host.Stop(); host.Dispose(); }
public void Stop_WhenUsingHostCall_DoesNotTriggerCancellationToken() { // Run test in multithreaded environment var oldContext = SynchronizationContext.Current; try { SynchronizationContext.SetSynchronizationContext(null); using (JobHost host = new JobHost(_hostConfiguration)) { host.Start(); Task callTask = InvokeNoAutomaticTriggerFunction(host); host.Stop(); EvaluateNoAutomaticTriggerCancellation(callTask, expectedCancellation: false); } } finally { SynchronizationContext.SetSynchronizationContext(oldContext); } }
public void Stop_WhenUsingHostCall_DoesNotTriggerCancellationToken() { using (JobHost host = new JobHost(_hostConfiguration)) { host.Start(); Task callTask = InvokeNoAutomaticTriggerFunction(host); host.Stop(); EvaluateNoAutomaticTriggerCancellation(callTask, expectedCancellation: false); } }
private void PrepareHostForTrigger(JobHost host, bool startHost) { host.Call(typeof(AsyncCancellationEndToEndTests).GetMethod("WriteQueueMessage")); if (startHost) { host.Start(); Assert.True(_functionStarted.WaitOne(DefaultTimeout)); } }
public void IndexingExceptions_CanBeHandledByTraceWriter() { JobHostConfiguration config = new JobHostConfiguration(); TestTraceWriter traceWriter = new TestTraceWriter(TraceLevel.Verbose); config.Tracing.Tracers.Add(traceWriter); config.TypeLocator = new FakeTypeLocator(typeof(BindingErrorsProgram)); FunctionErrorTraceWriter errorTraceWriter = new FunctionErrorTraceWriter(TraceLevel.Error); config.Tracing.Tracers.Add(errorTraceWriter); JobHost host = new JobHost(config); host.Start(); // verify the handled binding error FunctionIndexingException fex = errorTraceWriter.Errors.SingleOrDefault() as FunctionIndexingException; Assert.True(fex.Handled); Assert.Equal("BindingErrorsProgram.Invalid", fex.MethodName); // verify that the binding error was logged Assert.Equal(5, traceWriter.Traces.Count); TraceEvent traceEvent = traceWriter.Traces[0]; Assert.Equal("Error indexing method 'BindingErrorsProgram.Invalid'", traceEvent.Message); Assert.Same(fex, traceEvent.Exception); Assert.Equal("Invalid container name: invalid$=+1", traceEvent.Exception.InnerException.Message); // verify that the valid function was still indexed traceEvent = traceWriter.Traces[1]; Assert.True(traceEvent.Message.Contains("Found the following functions")); Assert.True(traceEvent.Message.Contains("BindingErrorsProgram.Valid")); // verify that the job host was started successfully traceEvent = traceWriter.Traces[4]; Assert.Equal("Job host started", traceEvent.Message); host.Stop(); host.Dispose(); }
public TestFixture() { RandomNameResolver nameResolver = new RandomNameResolver(); JobHostConfiguration hostConfiguration = new JobHostConfiguration() { NameResolver = nameResolver, TypeLocator = new FakeTypeLocator(typeof(BlobBindingEndToEndTests)), }; Config = hostConfiguration; StorageAccount = CloudStorageAccount.Parse(hostConfiguration.StorageConnectionString); CloudBlobClient blobClient = StorageAccount.CreateCloudBlobClient(); BlobContainer = blobClient.GetContainerReference(nameResolver.ResolveInString(ContainerName)); Assert.False(BlobContainer.Exists()); BlobContainer.Create(); OutputBlobContainer = blobClient.GetContainerReference(nameResolver.ResolveInString(OutputContainerName)); CloudBlobContainer pageBlobContainer = blobClient.GetContainerReference(nameResolver.ResolveInString(PageBlobContainerName)); Assert.False(pageBlobContainer.Exists()); pageBlobContainer.Create(); CloudBlobContainer hierarchicalBlobContainer = blobClient.GetContainerReference(nameResolver.ResolveInString(HierarchicalBlobContainerName)); Assert.False(hierarchicalBlobContainer.Exists()); hierarchicalBlobContainer.Create(); Host = new JobHost(hostConfiguration); Host.Start(); // upload some test blobs CloudBlockBlob blob = BlobContainer.GetBlockBlobReference("blob1"); blob.UploadText(TestData); blob = BlobContainer.GetBlockBlobReference("blob2"); blob.UploadText(TestData); blob = BlobContainer.GetBlockBlobReference("blob3"); blob.UploadText(TestData); blob = BlobContainer.GetBlockBlobReference("file1"); blob.UploadText(TestData); blob = BlobContainer.GetBlockBlobReference("file2"); blob.UploadText(TestData); // add a couple hierarchical blob paths blob = hierarchicalBlobContainer.GetBlockBlobReference("sub/blob1"); blob.UploadText(TestData); blob = hierarchicalBlobContainer.GetBlockBlobReference("sub/blob2"); blob.UploadText(TestData); blob = hierarchicalBlobContainer.GetBlockBlobReference("sub/sub/blob3"); blob.UploadText(TestData); blob = hierarchicalBlobContainer.GetBlockBlobReference("blob4"); blob.UploadText(TestData); byte[] bytes = new byte[512]; byte[] testBytes = Encoding.UTF8.GetBytes(TestData); for (int i = 0; i < testBytes.Length; i++) { bytes[i] = testBytes[i]; } CloudPageBlob pageBlob = pageBlobContainer.GetPageBlobReference("blob1"); pageBlob.UploadFromByteArray(bytes, 0, bytes.Length); pageBlob = pageBlobContainer.GetPageBlobReference("blob2"); pageBlob.UploadFromByteArray(bytes, 0, bytes.Length); }
static void Main() { Log.Trace(); // Set the maximum number of concurrent connections HttpUtilities.SetServicePointDefaultConnectionLimit(); var shipHubConfig = new ShipHubCloudConfiguration(); var azureWebJobsDashboard = shipHubConfig.AzureWebJobsDashboard; var azureWebJobsStorage = shipHubConfig.AzureWebJobsStorage; // Raygun Client var raygunApiKey = shipHubConfig.RaygunApiKey; RaygunClient raygunClient = null; if (!raygunApiKey.IsNullOrWhiteSpace()) { raygunClient = new RaygunClient(raygunApiKey); raygunClient.AddWrapperExceptions(typeof(AggregateException)); } // App Insights Client var applicationInsightsKey = shipHubConfig.ApplicationInsightsKey; TelemetryClient telemetryClient = null; if (!applicationInsightsKey.IsNullOrWhiteSpace()) { TelemetryConfiguration.Active.InstrumentationKey = applicationInsightsKey; telemetryClient = new TelemetryClient(); } var detailedLogger = new DetailedExceptionLogger(telemetryClient, raygunClient); var container = CreateContainer(detailedLogger); // Hack to address https://github.com/realartists/shiphub-server/issues/277 // I suspect that when DI occurs, the AzureBlobTraceListener is registered as a TraceListener // but not initialized. To get around this, force Orleans to initialize now, before any // TraceListeners get added. var timer = new Stopwatch(); timer.Restart(); Log.Info("[Orleans Client]: Initializing"); container.GetInstance <IAsyncGrainFactory>(); timer.Stop(); Log.Info($"[Orleans Client]: Initialized in {timer.Elapsed}"); // Job Host Configuration var config = new JobHostConfiguration() { DashboardConnectionString = azureWebJobsDashboard, StorageConnectionString = azureWebJobsStorage, JobActivator = new SimpleInjectorJobActivator(container), }; config.Queues.MaxDequeueCount = 2; // Only try twice // Gross manual DI ConfigureGlobalLogging(config, telemetryClient, raygunClient); var azureWebJobsServiceBus = shipHubConfig.AzureWebJobsServiceBus; var sbConfig = new ServiceBusConfiguration() { ConnectionString = azureWebJobsServiceBus, }; sbConfig.MessageOptions.MaxConcurrentCalls = 128; #if DEBUG config.UseDevelopmentSettings(); config.DashboardConnectionString = null; sbConfig.MessageOptions.AutoRenewTimeout = TimeSpan.FromSeconds(10); // Abandon locks quickly sbConfig.MessageOptions.MaxConcurrentCalls = 1; config.Queues.MaxDequeueCount = 1; #endif // https://azure.microsoft.com/en-us/documentation/articles/service-bus-performance-improvements/ recommends // 20x the processing rate/sec var ratePerSecond = 1; sbConfig.PrefetchCount = sbConfig.MessageOptions.MaxConcurrentCalls * 20 * ratePerSecond; Log.Info($"[Service Bus]: Initializing"); timer.Restart(); var sbFactory = container.GetInstance <IServiceBusFactory>(); timer.Stop(); Log.Info($"[Service Bus]: Initialized in {timer.Elapsed}"); // Override default messaging provider to use pairing. sbConfig.MessagingProvider = new PairedMessagingProvider(sbConfig, sbFactory); config.UseServiceBus(sbConfig); config.UseTimers(); config.UseCore(); // For ExecutionContext Log.Info("[Job Host]: Starting"); using (var host = new JobHost(config)) { #if DEBUG host.Start(); Console.WriteLine("Press Any Key to Exit."); Console.ReadLine(); Console.WriteLine("Stopping job host..."); host.Stop(); #else host.RunAndBlock(); #endif Log.Info("[Job Host]: Stopped"); } }
public TestFixture() { RandomNameResolver nameResolver = new RandomNameResolver(); JobHostConfiguration hostConfiguration = new JobHostConfiguration() { NameResolver = nameResolver, TypeLocator = new FakeTypeLocator(typeof(MultipleStorageAccountsEndToEndTests)), }; Config = hostConfiguration; Account1 = CloudStorageAccount.Parse(hostConfiguration.StorageConnectionString); string secondaryConnectionString = AmbientConnectionStringProvider.Instance.GetConnectionString(Secondary); Account2 = CloudStorageAccount.Parse(secondaryConnectionString); CleanContainers(); CloudBlobClient blobClient1 = Account1.CreateCloudBlobClient(); string inputName = nameResolver.ResolveInString(Input); CloudBlobContainer inputContainer1 = blobClient1.GetContainerReference(inputName); inputContainer1.Create(); string outputName = nameResolver.ResolveWholeString(Output); OutputContainer1 = blobClient1.GetContainerReference(outputName); OutputContainer1.CreateIfNotExists(); CloudBlobClient blobClient2 = Account2.CreateCloudBlobClient(); CloudBlobContainer inputContainer2 = blobClient2.GetContainerReference(inputName); inputContainer2.Create(); OutputContainer2 = blobClient2.GetContainerReference(outputName); OutputContainer2.CreateIfNotExists(); CloudQueueClient queueClient1 = Account1.CreateCloudQueueClient(); CloudQueue inputQueue1 = queueClient1.GetQueueReference(inputName); inputQueue1.CreateIfNotExists(); OutputQueue1 = queueClient1.GetQueueReference(outputName); OutputQueue1.CreateIfNotExists(); CloudQueueClient queueClient2 = Account2.CreateCloudQueueClient(); CloudQueue inputQueue2 = queueClient2.GetQueueReference(inputName); inputQueue2.CreateIfNotExists(); OutputQueue2 = queueClient2.GetQueueReference(outputName); OutputQueue2.CreateIfNotExists(); CloudTableClient tableClient1 = Account1.CreateCloudTableClient(); string outputTableName = nameResolver.ResolveWholeString(OutputTableName); OutputTable1 = tableClient1.GetTableReference(outputTableName); OutputTable2 = Account2.CreateCloudTableClient().GetTableReference(outputTableName); // upload some test blobs to the input containers of both storage accounts CloudBlockBlob blob = inputContainer1.GetBlockBlobReference("blob1"); blob.UploadText(TestData); blob = inputContainer2.GetBlockBlobReference("blob2"); blob.UploadText(TestData); // upload some test queue messages to the input queues of both storage accounts inputQueue1.AddMessage(new CloudQueueMessage(TestData)); inputQueue2.AddMessage(new CloudQueueMessage(TestData)); Host = new JobHost(hostConfiguration); Host.Start(); }
/// <summary> /// <see cref="IJobHost.Start"/> /// </summary> public void Start() { _jobHost.Start(); }
public void JobHost_NoStorage_Succeeds() { string prevStorage = Environment.GetEnvironmentVariable("AzureWebJobsStorage"); string prevDashboard = Environment.GetEnvironmentVariable("AzureWebJobsDashboard"); try { Environment.SetEnvironmentVariable("AzureWebJobsStorage", null); Environment.SetEnvironmentVariable("AzureWebJobsDashboard", null); JobHostConfiguration config = new JobHostConfiguration() { TypeLocator = new FakeTypeLocator(typeof(BasicTest)) }; // Explicitly disalbe storage. config.HostId = Guid.NewGuid().ToString("n"); config.DashboardConnectionString = null; config.StorageConnectionString = null; var randomValue = Guid.NewGuid().ToString(); StringBuilder sbLoggingCallbacks = new StringBuilder(); var fastLogger = new FastLogger(); config.AddService <IAsyncCollector <FunctionInstanceLogEntry> >(fastLogger); JobHost host = new JobHost(config); // Manually invoked. var method = typeof(BasicTest).GetMethod("Method", BindingFlags.Public | BindingFlags.Static); host.Call(method, new { value = randomValue }); Assert.True(BasicTest.Called); Assert.Equal(2, fastLogger.List.Count); // We should be batching, so flush not called yet. host.Start(); // required to call stop() host.Stop(); // will ensure flush is called. // Verify fast logs Assert.Equal(3, fastLogger.List.Count); var startMsg = fastLogger.List[0]; Assert.Equal("BasicTest.Method", startMsg.FunctionName); Assert.Equal(null, startMsg.EndTime); Assert.NotNull(startMsg.StartTime); var endMsg = fastLogger.List[1]; Assert.Equal(startMsg.FunctionName, endMsg.FunctionName); Assert.Equal(startMsg.StartTime, endMsg.StartTime); Assert.Equal(startMsg.FunctionInstanceId, endMsg.FunctionInstanceId); Assert.NotNull(endMsg.EndTime); // signal completed Assert.True(endMsg.StartTime <= endMsg.EndTime); Assert.Null(endMsg.ErrorDetails); Assert.Null(endMsg.ParentId); Assert.Equal(2, endMsg.Arguments.Count); Assert.True(endMsg.Arguments.ContainsKey("log")); Assert.Equal(randomValue, endMsg.Arguments["value"]); Assert.Equal("val=" + randomValue, endMsg.LogOutput.Trim()); Assert.Same(FastLogger.FlushEntry, fastLogger.List[2]); } finally { Environment.SetEnvironmentVariable("AzureWebJobsStorage", prevStorage); Environment.SetEnvironmentVariable("AzureWebJobsDashboard", prevDashboard); } }
private void ServiceBusEndToEndInternal(Type jobContainerType, bool verifyLogs = true) { StringWriter consoleOutput = null; if (verifyLogs) { consoleOutput = new StringWriter(); Console.SetOut(consoleOutput); } JobHostConfiguration config = new JobHostConfiguration() { NameResolver = _nameResolver, TypeLocator = new FakeTypeLocator(jobContainerType) }; config.UseServiceBus(_serviceBusConfig); string startQueueName = ResolveName(StartQueueName); string secondQueueName = startQueueName.Replace("start", "1"); string queuePrefix = startQueueName.Replace("-queue-start", ""); string firstTopicName = string.Format("{0}-topic/Subscriptions/{0}-queue-topic-1", queuePrefix); string secondTopicName = string.Format("{0}-topic/Subscriptions/{0}-queue-topic-2", queuePrefix); CreateStartMessage(_serviceBusConfig.ConnectionString, startQueueName); _host = new JobHost(config); _topicSubscriptionCalled1 = new ManualResetEvent(initialState: false); _topicSubscriptionCalled2 = new ManualResetEvent(initialState: false); _host.Start(); int timeout = 1 * 60 * 1000; _topicSubscriptionCalled1.WaitOne(timeout); _topicSubscriptionCalled2.WaitOne(timeout); // Wait for the host to terminate _host.Stop(); Assert.Equal("E2E-SBQueue2SBQueue-SBQueue2SBTopic-topic-1", _resultMessage1); Assert.Equal("E2E-SBQueue2SBQueue-SBQueue2SBTopic-topic-2", _resultMessage2); if (verifyLogs) { string[] consoleOutputLines = consoleOutput.ToString().Trim().Split(new string[] { Environment.NewLine }, StringSplitOptions.None); string[] expectedOutputLines = new string[] { "Found the following functions:", string.Format("{0}.SBQueue2SBQueue", jobContainerType.FullName), string.Format("{0}.SBQueue2SBTopic", jobContainerType.FullName), string.Format("{0}.SBTopicListener1", jobContainerType.FullName), string.Format("{0}.SBTopicListener2", jobContainerType.FullName), "Job host started", string.Format("Executing: '{0}.SBQueue2SBQueue' - Reason: 'New ServiceBus message detected on '{1}'.'", jobContainerType.Name, startQueueName), string.Format("Executing: '{0}.SBQueue2SBTopic' - Reason: 'New ServiceBus message detected on '{1}'.'", jobContainerType.Name, secondQueueName), string.Format("Executing: '{0}.SBTopicListener1' - Reason: 'New ServiceBus message detected on '{1}'.'", jobContainerType.Name, firstTopicName), string.Format("Executing: '{0}.SBTopicListener2' - Reason: 'New ServiceBus message detected on '{1}'.'", jobContainerType.Name, secondTopicName), "Job host stopped" }; Assert.True(expectedOutputLines.OrderBy(p => p).SequenceEqual(consoleOutputLines.OrderBy(p => p))); } }
private static TimeBlock RunWebJobsSDKTestInternal(bool disableLogging) { JobHostConfiguration hostConfig = new JobHostConfiguration(_connectionString); hostConfig.Queues.BatchSize = BatchSize; hostConfig.NameResolver = _nameResolver; hostConfig.TypeLocator = new FakeTypeLocator(typeof(QueueOverheadPerfTest)); if (disableLogging) { hostConfig.DashboardConnectionString = null; } _receivedMessages = 0; using (_firstMessagesReceivedEvent = new ManualResetEvent(initialState: false)) using (_allMessagesReceivedEvent = new ManualResetEvent(initialState: false)) using (JobHost host = new JobHost(hostConfig)) { host.Start(); _firstMessagesReceivedEvent.WaitOne(); TimeBlock block = new TimeBlock(); _allMessagesReceivedEvent.WaitOne(); block.End(); return block; } }
public void StopAsync_WhenAlreadyStopping_ReturnsSameTask() { // Arrange using (JobHost host = new JobHost(CreateConfiguration())) { host.Start(); // Replace (and cleanup) the existing listener to hook StopAsync. IListener oldRunner = host.Listener; oldRunner.StopAsync(CancellationToken.None).GetAwaiter().GetResult(); TaskCompletionSource<object> stopTaskSource = new TaskCompletionSource<object>(); Mock<IListener> listenerMock = new Mock<IListener>(MockBehavior.Strict); listenerMock.Setup(r => r.StopAsync(It.IsAny<CancellationToken>())).Returns(stopTaskSource.Task); listenerMock.Setup(r => r.Dispose()); host.Listener = listenerMock.Object; Task alreadyStopping = host.StopAsync(); // Act Task stoppingAgain = host.StopAsync(); // Assert Assert.Same(alreadyStopping, stoppingAgain); // Cleanup stopTaskSource.SetResult(null); alreadyStopping.GetAwaiter().GetResult(); stoppingAgain.GetAwaiter().GetResult(); } }
public void StopAsync_WhenStopped_DoesNotThrow() { // Arrange using (JobHost host = new JobHost(CreateConfiguration())) { host.Start(); host.Stop(); // Act & Assert host.StopAsync().GetAwaiter().GetResult(); } }
public void StartAsync_WhenStopping_Throws() { // Arrange using (JobHost host = new JobHost(CreateConfiguration())) { host.Start(); // Replace (and cleanup) the exsiting runner to hook StopAsync. IListener oldListener = host.Listener; oldListener.StopAsync(CancellationToken.None).GetAwaiter().GetResult(); TaskCompletionSource<object> stopTaskSource = new TaskCompletionSource<object>(); Mock<IListener> listenerMock = new Mock<IListener>(MockBehavior.Strict); listenerMock.Setup(r => r.StopAsync(It.IsAny<CancellationToken>())).Returns(stopTaskSource.Task); listenerMock.Setup(r => r.Dispose()); host.Listener = listenerMock.Object; Task stopping = host.StopAsync(); // Act & Assert ExceptionAssert.ThrowsInvalidOperation(() => host.StartAsync(), "Start has already been called."); // Cleanup stopTaskSource.SetResult(null); stopping.GetAwaiter().GetResult(); } }
public void MaxDegreeOfParallelism_Queues(int batchSize, int maxExpectedParallelism) { _receivedMessages = 0; _currentSimultaneouslyRunningFunctions = 0; _maxSimultaneouslyRunningFunctions = 0; _numberOfQueueMessages = batchSize * 3; RandomNameResolver nameResolver = new RandomNameResolver(); JobHostConfiguration hostConfiguration = new JobHostConfiguration() { NameResolver = nameResolver, TypeLocator = new FakeTypeLocator(typeof(ParallelExecutionTests)), }; hostConfiguration.Queues.BatchSize = batchSize; CloudStorageAccount storageAccount = CloudStorageAccount.Parse(hostConfiguration.StorageConnectionString); _queueClient = storageAccount.CreateCloudQueueClient(); CloudQueue queue = _queueClient.GetQueueReference(nameResolver.ResolveInString(TestQueueName)); queue.CreateIfNotExists(); for (int i = 0; i < _numberOfQueueMessages; i++) { int sleepTimeInSeconds = i % 2 == 0 ? 5 : 1; queue.AddMessage(new CloudQueueMessage(sleepTimeInSeconds.ToString())); } using (_allMessagesProcessed = new ManualResetEvent(initialState: false)) using (JobHost host = new JobHost(hostConfiguration)) { host.Start(); _allMessagesProcessed.WaitOne(TimeSpan.FromSeconds(90)); host.Stop(); } Assert.Equal(_numberOfQueueMessages, _receivedMessages); Assert.Equal(0, _currentSimultaneouslyRunningFunctions); // the actual value will vary sometimes based on the speed of the machine // running the test. int delta = _maxSimultaneouslyRunningFunctions - maxExpectedParallelism; Assert.True(delta == 0 || delta == 1); }
protected override void OnStart(string[] args) { jobHost.Start(); }