public async Task <SimulationApiModel> PatchAsync(
            string id,
            [FromBody] SimulationPatchApiModel patch)
        {
            if (patch == null)
            {
                this.log.Warn("NULL patch provided", () => new { id });
                throw new BadRequestException("No data or invalid data provided");
            }

            SimulationPatch patchServiceModel = patch.ToServiceModel(id);

            if (patchServiceModel.Enabled == false)
            {
                patchServiceModel.Statistics = new SimulationStatistics
                {
                    AverageMessagesPerSecond = this.rateReporter.GetThroughputForMessages(),
                    TotalMessagesSent        = this.simulationRunner.TotalMessagesCount
                };
            }

            var simulation = await this.simulationsService.MergeAsync(patchServiceModel);

            return(SimulationApiModel.FromServiceModel(
                       simulation, this.servicesConfig, this.deploymentConfig, this.connectionStringManager, this.simulationRunner, this.rateReporter));
        }
        public async Task <SimulationApiModel> PatchAsync(string id, [FromBody]
                                                          SimulationPatchApiModel patch)
        {
            if (patch == null)
            {
                this.log.Warn("NULL patch provided", () => new { id });
                throw new BadRequestException("No data or invalid data provided");
            }

            SimulationPatch patchServiceModel = patch.ToServiceModel(id);
            var             simulation        = await this.simulationsService.MergeAsync(patchServiceModel);

            return(SimulationApiModel.FromServiceModel(simulation));
        }
Пример #3
0
        public async Task <Models.Simulation> MergeAsync(SimulationPatch patch)
        {
            if (patch.Id != SIMULATION_ID)
            {
                this.log.Warn("Invalid simulation ID.", () => new { patch.Id });
                throw new InvalidInputException("Invalid simulation ID. Use ID '" + SIMULATION_ID + "'.");
            }

            var item = await this.storage.GetAsync(STORAGE_COLLECTION, patch.Id);

            var simulation = JsonConvert.DeserializeObject <Models.Simulation>(item.Data);

            simulation.Etag = item.ETag;

            // Even when there's nothing to do, verify the etag mismatch
            if (patch.Etag != simulation.Etag)
            {
                this.log.Warn("Etag mismatch",
                              () => new { Current = simulation.Etag, Provided = patch.Etag });
                throw new ConflictingResourceException(
                          $"The ETag provided doesn't match the current resource ETag ({simulation.Etag}).");
            }

            if (!patch.Enabled.HasValue || patch.Enabled.Value == simulation.Enabled)
            {
                // Nothing to do
                return(simulation);
            }

            simulation.Enabled  = patch.Enabled.Value;
            simulation.Modified = DateTimeOffset.UtcNow;
            simulation.Version += 1;

            item = await this.storage.UpdateAsync(
                STORAGE_COLLECTION,
                SIMULATION_ID,
                JsonConvert.SerializeObject(simulation),
                patch.Etag);

            simulation.Etag = item.ETag;

            return(simulation);
        }
        /// <summary>
        /// Modify a simulation.
        /// </summary>
        public async Task <Models.Simulation> MergeAsync(SimulationPatch patch)
        {
            if (string.IsNullOrEmpty(patch.Id))
            {
                this.log.Warn("Invalid simulation ID.", () => new { patch.Id });
                throw new InvalidInputException("Invalid simulation ID.");
            }

            var item = await this.simulationsStorage.GetAsync(patch.Id);

            var simulation = JsonConvert.DeserializeObject <Models.Simulation>(item.Data);

            simulation.ETag = item.ETag;
            simulation.Id   = item.Id;

            // Even when there's nothing to do, verify the ETag mismatch
            if (patch.ETag != simulation.ETag)
            {
                this.log.Warn("ETag mismatch",
                              () => new { Current = simulation.ETag, Provided = patch.ETag });
                throw new ConflictingResourceException(
                          $"The ETag provided doesn't match the current resource ETag ({simulation.ETag}).");
            }

            if (!patch.Enabled.HasValue || patch.Enabled.Value == simulation.Enabled)
            {
                // Nothing to do
                return(simulation);
            }

            simulation.Enabled = patch.Enabled.Value;

            if (patch.Enabled == false)
            {
                simulation.StoppedTime = simulation.Modified;
                simulation.Statistics  = new Models.Simulation.StatisticsRef
                {
                    AverageMessagesPerSecond = patch.Statistics.AverageMessagesPerSecond,
                    TotalMessagesSent        = patch.Statistics.TotalMessagesSent
                };

                // When a simulation is disabled, its partitions are deleted - this triggers the deletion
                if (!simulation.Enabled)
                {
                    simulation.PartitioningComplete = false;
                }
            }

            item = await this.simulationsStorage.UpsertAsync(
                new StorageRecord
            {
                Id   = simulation.Id,
                Data = JsonConvert.SerializeObject(simulation)
            },
                patch.ETag
                );

            simulation.ETag = item.ETag;

            return(simulation);
        }
        /// <summary>
        /// Modify some simulation details
        /// </summary>
        public async Task <Models.Simulation> MergeAsync(SimulationPatch patch)
        {
            if (string.IsNullOrEmpty(patch.Id))
            {
                this.log.Warn("Invalid simulation ID.", () => new { patch.Id });
                throw new InvalidInputException("Invalid simulation ID.");
            }

            var item = await this.simulationsStorage.GetAsync(patch.Id);

            var simulation = JsonConvert.DeserializeObject <Models.Simulation>(item.Data);

            simulation.ETag = item.ETag;
            simulation.Id   = item.Id;

            // Even when there's nothing to do, verify the ETag mismatch
            if (patch.ETag != simulation.ETag)
            {
                this.log.Warn("ETag mismatch",
                              () => new { Current = simulation.ETag, Provided = patch.ETag });
                throw new ConflictingResourceException(
                          $"The ETag provided doesn't match the current resource ETag ({simulation.ETag}).");
            }

            // Define the user intent looking at the simulation status and the patch content
            var simulationIsRestarting = !simulation.Enabled && patch.Enabled.HasValue && patch.Enabled.Value;
            var simulationIsStopping   = simulation.Enabled && patch.Enabled.HasValue && !patch.Enabled.Value;

            // Note: this code is also in UpsertAsync
            // (consider refactoring it out unless the code becomes harder to follow)
            if (simulationIsRestarting)
            {
                simulation = await this.ResetSimulationStatisticsAsync(simulation);
            }
            else if (simulationIsStopping)
            {
                simulation.StoppedTime = DateTimeOffset.UtcNow;

                // When a simulation is disabled, its partitions are deleted.
                // This boolean triggers the deletion of partitions from the storage
                // in the partitioning agent.
                simulation.PartitioningComplete = false;
            }

            // The Enabled field is optional, e.g. in case PATCH is extended to
            // modify other fields, so we need to check for null
            if (patch.Enabled != null)
            {
                simulation.Enabled = patch.Enabled.Value;
            }

            // TODO: can we use this.SaveAsync() here too and avoid the duplication?
            item = await this.simulationsStorage.UpsertAsync(
                new StorageRecord
            {
                Id   = simulation.Id,
                Data = JsonConvert.SerializeObject(simulation)
            },
                patch.ETag
                );

            simulation.ETag = item.ETag;

            return(simulation);
        }