Пример #1
0
        public void Wait_SecondEntryWithTheSameID_Is_BlockedUntilTheFirstResolvesTest()
        {
            // Arrange
            List <Task> tasks        = new List <Task>();
            string      id           = "test";
            bool        firstRunning = false;

            DateTime completionTimeOfFirstTask  = DateTime.MinValue;
            DateTime completionTimeOfSecondTask = DateTime.MinValue;

            void FirstLock()
            {
                firstRunning = true;
                _semaphoreOnEntity.Wait(id);
                Thread.Sleep(LongSleepInterval);
                _semaphoreOnEntity.Release(id);
                completionTimeOfFirstTask = DateTime.UtcNow;
            }

            void SecondLock()
            {
                do
                {
                    // Wait for first to start
                    Thread.Sleep(ShortSleepInterval);
                }while (!firstRunning);

                _semaphoreOnEntity.Wait(id);
                _semaphoreOnEntity.Release(id);
                completionTimeOfSecondTask = DateTime.UtcNow;
            }

            // Act
            Task firstTask  = Task.Run(FirstLock);
            Task secondTask = Task.Run(SecondLock);

            Task.WaitAll(new Task[] { firstTask, secondTask });

            // Assert
            completionTimeOfFirstTask.Should().BeBefore(completionTimeOfSecondTask);
        }
        /// <inheritdoc/>
        public async Task CreateAsync(CreateContractRequest request)
        {
            await _semaphoreOnEntity.WaitAsync(request.ContractNumber).ConfigureAwait(false);

            try
            {
                _logger.LogInformation($"[{nameof(CreateAsync)}] Creating new contract [{request.ContractNumber}] version [{request.ContractVersion}] for [{request.UKPRN}].");

                var existing = await _repository.GetByContractNumberAsync(request.ContractNumber);

                _contractValidator.ValidateForNewContract(request, existing);

                var newContract = _mapper.Map <Repository.DataModels.Contract>(request);
                newContract.LastUpdatedAt = newContract.CreatedAt = DateTime.UtcNow;

                // For amendment type notification the default status has to be approved
                // For None and Variation, it should be published to provider
                if (request.AmendmentType == ContractAmendmentType.Notfication)
                {
                    newContract.Status              = (int)ContractStatus.Approved;
                    newContract.SignedOn            = request.SignedOn.Value.Date;
                    newContract.SignedBy            = "Feed";
                    newContract.SignedByDisplayName = "Feed";
                }
                else if (request.AmendmentType == ContractAmendmentType.None || request.AmendmentType == ContractAmendmentType.Variation)
                {
                    newContract.Status = (int)ContractStatus.PublishedToProvider;
                }

                await _contractDocumentService.UpsertOriginalContractXmlAsync(newContract, new ContractRequest()
                {
                    FileName = request.ContractData, ContractNumber = request.ContractNumber, ContractVersion = request.ContractVersion
                });

                await _repository.CreateAsync(newContract);

                var updatedContractStatusResponse = new UpdatedContractStatusResponse
                {
                    Id              = newContract.Id,
                    ContractNumber  = newContract.ContractNumber,
                    ContractVersion = newContract.ContractVersion,
                    Ukprn           = newContract.Ukprn,
                    NewStatus       = (ContractStatus)newContract.Status,
                    Action          = ActionType.ContractCreated,
                    AmendmentType   = request.AmendmentType
                };

                _logger.LogInformation($"[{nameof(CreateAsync)}] Contract [{newContract.ContractNumber}] version [{newContract.ContractVersion}] has been created for [{newContract.Ukprn}].");

                // Update operations to existing records can be done outside the semaphore
                if (request.AmendmentType == ContractAmendmentType.Variation || request.AmendmentType == ContractAmendmentType.None)
                {
                    var statuses = new int[]
                    {
                        (int)ContractStatus.PublishedToProvider
                    };

                    await ReplaceContractsWithGivenStatuses(existing, statuses);
                }
                else if (request.AmendmentType == ContractAmendmentType.Notfication)
                {
                    var statuses = new int[]
                    {
                        (int)ContractStatus.Approved,
                        (int)ContractStatus.ApprovedWaitingConfirmation,
                        (int)ContractStatus.PublishedToProvider
                    };

                    await ReplaceContractsWithGivenStatuses(existing, statuses);
                }

                await _mediator.Publish(updatedContractStatusResponse);
            }
            finally
            {
                _semaphoreOnEntity.Release(request.ContractNumber);
            }
        }