/// <summary> /// The action that is taken for each worker report /// </summary> /// <param name="report"></param> protected virtual void EvaluateWorkerReport(Message <WorkerReport> report) { try { var reportData = ValidateWorkerReport(report); // TODO: May want to replace the switch with strategy. Need to see which is better as we add more behavior switch (reportData.Status) { case WorkerReportStatus.TaskComplete: // Good work, let's track the success and the elapsed time so we can make better decisions going forward _statisticsProvider.RecordQueueMessageCompletionTime(reportData.SourceQueue, reportData.ElapsedTime); break; case WorkerReportStatus.NoWork: // Uh oh, this worker doesn't have anything to do. Better turn it off _actorManager.Deactivate(reportData); if (_dynamicallyKeyedWorkerConfigurations.ContainsKey(reportData.SourceQueue)) { _dynamicallyKeyedWorkerConfigurations.Remove(reportData.SourceQueue); _actorManager.DeactiveListener(reportData.SourceQueue); } break; case WorkerReportStatus.FatalError: // For now, just turn the dead worker off _actorManager.Deactivate(reportData); break; case WorkerReportStatus.ExileMessage: // A message has been causing our workers to die regularly! They've already removed it from their work queue, // But we need to be sure to put it somewhere where we can review it and identify the issue. PlaceMessageIntoHoldingQueue(reportData.SourceQueue, reportData.Exception, reportData.Message); break; default: throw new ArgumentOutOfRangeException( $"{reportData.Status} does not map to enum {typeof(WorkerReportStatus).FullName}, or its case is not handled by this switch statement"); } } catch (Exception ex) { OnErrorAction(ex); } }