private static void SendIngestCommand(IContainer container) { var messageSenderFactory = container.Resolve <IMessageSenderFactory>(); var channelIdentifierRepository = container.Resolve <IComponentChannelIdentifierRepository>(); var capmMessageChannelIdentifier = channelIdentifierRepository.GetChannelIdentifierFor(CaPMSystem.CaPMComponentIdentifier); var capmMessageChannel = messageSenderFactory.GetChannel <StartIngestCommand>(capmMessageChannelIdentifier); var command = new StartIngestCommand() { SubmissionAgreementId = "SubmissionAgreement1", IngestParameters = "http://localhost:17729/images/unnamed.png" }; capmMessageChannel.Send(command); }
private static void Start(IConfiguration configuration) { StartMode mode; try { mode = (StartMode)Enum.Parse(typeof(StartMode), configuration?["mode"] ?? "CapmOnly", ignoreCase: true); } catch (ArgumentException e) { Console.WriteLine("Failed parsing execution mode. " + e.Message + " Valid values for --mode are: " + string.Join(", ", Enum.GetNames(typeof(StartMode)))); return; } Console.WriteLine("Starting console runner with mode: " + mode); IContainer container; switch (mode) { case StartMode.CapmOnly: container = BootstrapIoCContainer(configuration); StartComponent <CaPMSystem>(container); break; case StartMode.InMemoryWithAllComponents: container = BoostrapIoCContainerForInMemoryExecution().Build(); StartComponent <CollectorComponent>(container); StartComponent <RandomErrorComponent>(container); StartComponent <ArchiverComponent>(container); StartComponent <CaPMSystem>(container); Task.Factory.StartNew(async() => { await Task.Delay(2000); SendIngestCommand(container); }); break; case StartMode.OnlySendLotsOfMessages: container = BootstrapIoCContainer(configuration); var command = new StartIngestCommand() { SubmissionAgreementId = "1% Failing and 1% Failing on Compensation", IngestParameters = "http://localhost:17729/images/unnamed.png" }; Task.Factory.StartNew(() => SendStartIngestCommands(container, 1302, _ => command, "Send messages")); break; case StartMode.Simulation: var decimalFormattingCulture = CultureInfo.GetCultureInfo("en-US"); var isFailureRateProvided = decimal.TryParse(configuration["failure-rate"], NumberStyles.Any, decimalFormattingCulture, out var failureRate); var isCompensationFailureRateProvided = decimal.TryParse(configuration["compensation-failure-rate"], NumberStyles.Any, decimalFormattingCulture, out var compensationFailureRate); var isIngestCountProvided = int.TryParse(configuration["ingest-count"], out var ingestCount); var isComponentCountProvided = int.TryParse(configuration["number-of-components-per-ingest"], out var componentCount); var isStoragePathProvided = !string.IsNullOrEmpty(configuration["storage-path"]); if (isFailureRateProvided && isCompensationFailureRateProvided && isIngestCountProvided && isStoragePathProvided && isComponentCountProvided && componentCount > 0 && ingestCount > 0) { var filePath = configuration["storage-path"]; if (File.Exists(filePath)) { throw new IOException($"Aborting execution since it will not be possible to write results, file '{filePath}' already exists"); } var containerBuilder = BoostrapIoCContainerForInMemoryExecution(); MessageSourceExtensions.DisableMessageProcessingConsoleOutput = true; InMemoryComponentStagingStore.SkipDelay = true; //containerBuilder.RegisterInstance(new FileSystemStagingStoreContainer(configuration["storage-path"])).As<IStagingStoreContainer>().SingleInstance(); container = containerBuilder.Build(); var submissionAgreementStore = container.Resolve <FakeSubmissionAgreementStore>(); var simulationAgreementId = "simulationagreement"; submissionAgreementStore.Add(simulationAgreementId, new SubmissionAgreement() { SubmissionAgreementId = simulationAgreementId, ProcessComponents = Enumerable.Range(0, componentCount).Select(_ => new SubmissionAgreement.ComponentExecutionPlan { ComponentCode = "Component.RandomError", ComponentSettings = $"{{\"FailureRisk\": {failureRate.ToString(decimalFormattingCulture)}, \"CompensationFailureRisk\": {compensationFailureRate.ToString(decimalFormattingCulture)}, \"SkipDelay\": true }}", Order = 1 } ).ToArray() }); StartComponent <CollectorComponent>(container); StartComponent <RandomErrorComponent>(container); StartComponent <ArchiverComponent>(container); StartComponent <CaPMSystem>(container); var ingestCommand = new StartIngestCommand() { SubmissionAgreementId = simulationAgreementId, IngestParameters = "" }; var channelProvider = container.Resolve <IChannelProvider>(); var componentChannelIdentifierRepository = container.Resolve <IComponentChannelIdentifierRepository>(); var eventsByIngestId = new Dictionary <Guid, List <IIngestEvent> >(); Func <List <IIngestEvent>, bool> hasFailedCompensation = (events) => events.Any(e => e is IngestComponentCompensationFailed); Func <List <IIngestEvent>, bool> hasFailedIngest = (events) => events.Any(e => e is IngestComponentWorkFailed); var numberOfSuccessfulIngests = 0; var numberOfCompensatedIngests = 0; var numberOfFailedCompensations = 0; var numberOfComponentExecutionsWhichNeedCompensation = 0; var numberOfSuccessfulComponentExecutions = 0; var numberOfFailedComponentExecutions = 0; var numberOfSuccessfulComponentCompensations = 0; var numberOfFailedComponentCompensations = 0; var numberOfComponentExecutionsWhichWouldHaveNeededManualWorkWithoutCompensationResilience = 0; channelProvider.GetMessageSource <SerializedEvent>(componentChannelIdentifierRepository.GetChannelIdentifierFor(IngestEventConstants.ChannelIdentifierCode)).GetChannel().Subscribe(evt => { var evtObject = evt.GetEventObject(); var events = eventsByIngestId.ContainsKey(evtObject.IngestId) ? eventsByIngestId[evtObject.IngestId] : eventsByIngestId[evtObject.IngestId] = new List <IIngestEvent>(); events.Add(evtObject); switch (evtObject) { case IngestCompleted ingComp: if (hasFailedIngest(events)) { if (hasFailedCompensation(events)) { numberOfFailedCompensations++; var countOfEventsWhichNeedCompensation = events.Count(e => e is IngestComponentWorkCompleted || e is IngestComponentWorkFailed); var countOfEventsWhichWereCompensatedBeforeFirstCompensationFailure = events .Where(e => e is IngestComponentCompensationCompleted || e is IngestComponentCompensationFailed) .TakeWhile(e => !(e is IngestComponentCompensationFailed)) .Count(); numberOfComponentExecutionsWhichWouldHaveNeededManualWorkWithoutCompensationResilience += countOfEventsWhichNeedCompensation - countOfEventsWhichWereCompensatedBeforeFirstCompensationFailure; } else { numberOfCompensatedIngests++; } } else { numberOfSuccessfulIngests++; } eventsByIngestId.Remove(evtObject.IngestId); break; case IngestComponentWorkCompleted ingComp: numberOfSuccessfulComponentExecutions++; break; case IngestComponentWorkFailed ingComp: numberOfFailedComponentExecutions++; numberOfComponentExecutionsWhichNeedCompensation += events.Count(e => e is IngestComponentWorkCompleted); break; case IngestComponentCompensationCompleted ingComp: numberOfSuccessfulComponentCompensations++; break; case IngestComponentCompensationFailed ingComp: numberOfFailedComponentCompensations++; break; case IngestPlanSet _: case IngestStarted _: case IngestComponentWorkStartRequested _: case IngestComponentCompensationStartRequested _: //We ignore these events, because we don't want to count them break; default: throw new Exception("Unknown event type " + evtObject.GetType().FullName); } }); SendStartIngestCommands(container, ingestCount, _ => ingestCommand, $"F: {failureRate}, CF: {compensationFailureRate}"); if (File.Exists(filePath)) { throw new IOException($"Could not save results, file '{filePath}' already exists"); } File.WriteAllText(configuration["storage-path"], JsonSerializer.Serialize(new { numberOfIngests = ingestCount, numberOfSuccessfulIngests, numberOfFailedIngests = ingestCount - numberOfSuccessfulIngests, numberOfCompensatedIngests, numberOfFailedCompensations, failureRate, compensationFailureRate, numberOfSuccessfulComponentExecutions, numberOfSuccessfulComponentCompensations, numberOfFailedComponentExecutions, numberOfFailedComponentCompensations, numberOfComponentExecutionsWhichNeedCompensation, numberOfComponentExecutionsWhichWouldHaveNeededManualWorkWithoutCompensationResilience }, new JsonSerializerOptions { WriteIndented = true, PropertyNamingPolicy = JsonNamingPolicy.CamelCase })); return; } else { Console.WriteLine("Mandatory parameters missing. Need to configure the failure rate, compensation failure rate, ingest count and storage path, or pass them as parameters to the cli, e.g. --mode simulation --failure-rate 0.01 --compensation-failure-rate 0.01 --ingest-count 100000 --number-of-components-per-ingest 5 --storage-path C:\\temp\\simulation-results.txt"); Console.WriteLine("The following values were missing, invalid or not possible to parse:"); if (!isFailureRateProvided) { Console.WriteLine(" --failure-rate: " + configuration["failure-rate"]); } if (!isCompensationFailureRateProvided) { Console.WriteLine(" --compensation-failure-rate: " + configuration["compensation-failure-rate"]); } if (!isIngestCountProvided) { Console.WriteLine(" --ingest-count: " + configuration["ingest-count"]); } if (!isComponentCountProvided) { Console.WriteLine(" --number-of-components-per-ingest " + configuration["number-of-components-per-ingest"]); } if (!isStoragePathProvided) { Console.WriteLine(" --storage-path: " + configuration["storage-path"]); } return; } default: throw new NotSupportedException(); } Console.WriteLine("System running, press [ENTER] to quit."); Console.ReadLine(); Console.WriteLine("System shut down."); }