/// <summary> /// Main Execution Method for the worker /// </summary> public override void Run() { try { var diagnosticsConnectionString = CloudConfigurationManager.GetSetting(GlobalConstants.DIAGNOSTICS_STORAGE_CONNECTIONSTRING_CONFIGNAME); var level = CloudConfigurationManager.GetSetting(GlobalConstants.GERES_CONFIG_DIAGNOSTICS_LEVEL); Geres.Diagnostics.GeresEventSource.StartDiagnostics( RoleEnvironment.CurrentRoleInstance.Id, diagnosticsConnectionString, level ); } catch (Exception ex) { Trace.TraceError("FATAL ERROR - unable to initialize GERES Diagnostics Component at Run()-method: {0}. Recycling role...", ex.Message); RoleEnvironment.RequestRecycle(); } try { GeresEventSource.Log.JobProcessorWorkerStarted(RoleEnvironment.CurrentRoleInstance.Id, RoleEnvironment.DeploymentId); // Initialize basic properties with information about the role _currentDeploymentId = RoleEnvironment.DeploymentId; _currentRoleInstanceId = RoleEnvironment.CurrentRoleInstance.Id; // Read general configuration settings _waitTimeInSecondsBetweenJobQueriesShort = int.Parse(CloudConfigurationManager.GetSetting(GlobalConstants.GERES_CONFIG_JOBPROCESSOR_PAUSE_BETWEEN_WORKCHECK_SHORT)); _waitTimeInSecondsBetweenJobQueriesLong = int.Parse(CloudConfigurationManager.GetSetting(GlobalConstants.GERES_CONFIG_JOBPROCESSOR_PAUSE_BETWEEN_WORKCHECK_LONG)); _idlePingIntervalToAutoScalerInSeconds = int.Parse(CloudConfigurationManager.GetSetting(GlobalConstants.GERES_CONFIG_JOBPROCESSOR_IDLE_PING_INTERVAL)); _autoScalerCommandCheckIntervalInSeconds = int.Parse(CloudConfigurationManager.GetSetting(GlobalConstants.GERES_CONFIG_JOBPROCESSOR_AUTOSCALER_COMMANDCHECKINTERVAL)); _autoScalerEnabled = bool.Parse(CloudConfigurationManager.GetSetting(GlobalConstants.GERES_CONFIG_AUTOSCALER_ENABLED)); _maxNumberOfRetriesBeforeIdle = int.Parse(CloudConfigurationManager.GetSetting(GlobalConstants.OTHER_WORKER_RETRYCOUNT_CONFIGNAME)); _internalServiceBusConnectionString = CloudConfigurationManager.GetSetting(GlobalConstants.SERVICEBUS_INTERNAL_CONNECTIONSTRING_CONFIGNAME); // Create the tenant manager based on the local resource path var localResourceForJobs = RoleEnvironment.GetLocalResource(GlobalConstants.LOCAL_RESOURCE_FOR_JOBS); var localResourceForJobPackageDownloads = RoleEnvironment.GetLocalResource(GlobalConstants.LOCAL_RESOURCE_FOR_TEMPJOBFILES); var tenantManager = EngineFactory.CreateTenantManager(localResourceForJobs.RootPath, localResourceForJobPackageDownloads.RootPath); // initialize the JobHandler which is actually processing the jobs with // the composition factory that is loading the jobs through MEF GeresEventSource.Log.JobProcessorWorkerInitializeJobHandler(_currentRoleInstanceId, _currentDeploymentId); var jobHandler = EngineFactory.CreateJobHandler(tenantManager); GeresEventSource.Log.JobProcessorWorkerInitializationJobHandlerCompleted(_currentRoleInstanceId, _currentDeploymentId); // Initialize the service bus to communicate with the AutoScaler var jobHostAutoScalerIntegrator = new JobHostAutoScalerIntegrator(_autoScalerEnabled, _internalServiceBusConnectionString); jobHostAutoScalerIntegrator.Initialize ( _currentRoleInstanceId, _currentDeploymentId, _autoScalerCommandCheckIntervalInSeconds, _maxNumberOfRetriesBeforeIdle, _idlePingIntervalToAutoScalerInSeconds ); // When the instance is stopping, remove the subscription RoleEnvironment.Stopping += ((sender, e) => { try { jobHostAutoScalerIntegrator.StopAutoScaleInteraction(); tenantManager.DeleteTenants(); } catch (Exception ex) { GeresEventSource.Log.JobProcessorWorkerRemovingAutoScalerCommandSubscriptionFailed(_currentDeploymentId, _currentDeploymentId, _subscriptionName, ex.Message, ex.StackTrace); } }); // // Start running the worker while loop and processing jobs // var retries = _maxNumberOfRetriesBeforeIdle; var lastTimeIdleSent = DateTime.UtcNow; var currentWaitTime = _waitTimeInSecondsBetweenJobQueriesShort; while (true) { // wait x seconds before checking the queue again Thread.Sleep(currentWaitTime); // If the AutoScaler says the worker should be running, the run, otherwise stay IDLE and query the queue less often if (jobHostAutoScalerIntegrator.VerifyIfWorkerShouldBeIdle()) { // Increase the time between checking the status currentWaitTime = _waitTimeInSecondsBetweenJobQueriesLong; } else { // The worker is not idle, process the queue // Check whether there is a job to process, if a job is processed then true is returned GeresEventSource.Log.JobProcessorWorkerStartProcessJobStart(_currentRoleInstanceId, _currentDeploymentId, jobHostAutoScalerIntegrator.AssignedDedicatedBatchId); var result = jobHandler.Process(jobHostAutoScalerIntegrator.AssignedDedicatedBatchId); GeresEventSource.Log.JobProcessorWorkerProcessJobResultReceived(_currentRoleInstanceId, _currentDeploymentId, jobHostAutoScalerIntegrator.AssignedDedicatedBatchId, result); // If there was NO job on the queue, register it as an empty retry if (!result) { // Register an empty processing cycle jobHostAutoScalerIntegrator.RegisterRetryProcessing(); // Leverage the empty processing cycle for clean-up tasks tenantManager.DeleteTenants(); // No job processed, set the current wait-time to long currentWaitTime = _waitTimeInSecondsBetweenJobQueriesLong; } else { // Job processed, set the wait-time to short currentWaitTime = _waitTimeInSecondsBetweenJobQueriesShort; } } } } catch (Exception ex) { GeresEventSource.Log.JobProcessorWorkerUnhandledExceptionOccured(_currentRoleInstanceId, _currentDeploymentId, ex.Message, ex.StackTrace); } GeresEventSource.Log.JobProcessorWorkerStopping(_currentRoleInstanceId, _currentDeploymentId); }