public void ProcessEntityCacheOperation(Operation operation) { // base initialize var entityName = configurationService.EntityName; var batchSize = configurationService.BatchSize; var serviceUrl = operation == Operation.Create ? configurationService.CreateServiceUrl : configurationService.UpdateServiceUrl; HttpMethod httpMethod = operation == Operation.Create ? HttpMethod.Post : HttpMethod.Patch; IRequestPayloadCreator payloadCreator = operation == Operation.Create ? createRequestPayloadCreator : updateRequestPayloadCreator; logger.LogInformation($"Processing {Enum.GetName(typeof(EntityCacheMessageStatusReason), operation)} EntityCache for entity: {entityName}"); logger.LogInformation($"Integration layer endpoint: {serviceUrl}"); logger.LogInformation($"Retrieving entity cache records to process with maximum batch size: {batchSize}"); // retrieve records var entityCacheCollection = operation == Operation.Create ? outboundSynchronisationDataService.GetCreatedEntityCacheToProcess(entityName, batchSize) : outboundSynchronisationDataService.GetUpdatedEntityCacheToProcess(entityName, batchSize); logger.LogInformation($"Found {entityCacheCollection?.Count} records to be processed"); if (entityCacheCollection == null || entityCacheCollection.Count == 0) { return; } // prepare jwt token var token = jwtService.CreateJwtToken(outboundSynchronisationDataService.GetSecretKey(), CreateTokenPayload()); foreach (EntityCache entityCache in entityCacheCollection) { // don't do call if succeeded max retries (ex if request from integration layer to CRM failed and it was max retried) if (entityCache.StatusReason == EntityCacheStatusReason.InProgress && entityCache.RequestsCount > MaxRetries) { logger.LogInformation($"EntityCache record: {entityCache.Name} reached maximum retries {MaxRetries} of calls to integration layer and will be failed"); outboundSynchronisationDataService.UpdateEntityCacheStatus(entityCache.Id, Status.Inactive, EntityCacheStatusReason.Failed); continue; } // create entity cache message var entityCacheMessage = new EntityCacheMessage { EntityCacheId = entityCache.Id, Name = string.Format(EntityCacheMessageName, entityCache.RecordId, entityCache.Id) }; var entityCacheMessageId = outboundSynchronisationDataService.CreateEntityCacheMessage(entityCacheMessage); logger.LogInformation($"Processing EntityCache/EntityCacheMessage : {entityCache.Name}/{entityCacheMessage.Name}"); // update entity cache outboundSynchronisationDataService.UpdateEntityCacheStatus(entityCache.Id, Status.Active, EntityCacheStatusReason.InProgress); // calculate next retry time in case if failure var eligibleRetryTime = GetEligibleRetryTime(RetrySchedule, entityCache.RequestsCount); string note = null; var statusReason = EntityCacheMessageStatusReason.Failed; var success = false; try { var entityModel = entityModelDeserializer.Deserialize(entityCache.Data); var requestPayload = payloadCreator.GetPayload(entityModel); var url = operation == Operation.Update ? GetUpdateUrl(serviceUrl, entityCache.SourceSystemId) : serviceUrl; var response = jwtService.SendHttpRequest(httpMethod, url, token, requestPayload, entityCacheMessageId.ToString()); success = IsResponseSuccessful(response.StatusCode); statusReason = success ? EntityCacheMessageStatusReason.SuccessfullySentToIL : EntityCacheMessageStatusReason.Failed; note = success ? null : AppendNote(entityCacheMessage.Notes, response.StatusCode, response.Content); logger.LogInformation($"Executed call to integration layer. EntityCacheMessage Status Reason: {Enum.GetName(typeof(EntityCacheMessageStatusReason), statusReason)}"); } catch (Exception e) { note = AppendNote(entityCacheMessage.Notes, HttpStatusCode.InternalServerError, "Internal server error."); logger.LogError(e.ToString()); logger.LogInformation($"Exception thrown while executing call to service layer. EntityCacheMessage Status Reason: {Enum.GetName(typeof(EntityCacheMessageStatusReason), statusReason)}"); } finally { // do crash in case of connectivity problems to CRM outboundSynchronisationDataService.UpdateEntityCacheSendToIntegrationLayerStatus(entityCache.Id, success, success ? (DateTime?)null : eligibleRetryTime); outboundSynchronisationDataService.UpdateEntityCacheMessageStatus(entityCacheMessageId, Status.Inactive, statusReason, success ? null : note); } } }
/// <summary> /// To create entitycachemessage record /// </summary> /// <param name="entityCacheMessageModel"></param> /// <returns></returns> public Guid CreateEntityCacheMessage(EntityCacheMessage entityCacheMessageModel) { return(outboundSynchronisationDataService.CreateEntityCacheMessage(entityCacheMessageModel)); }
public void TestCreateSuccessResponse() { // Given var payload = "payload"; var entityCache = new List <EntityCache>() { new EntityCache() { SourceMarket = "sm1", Data = "{'Fields':[{'Name':'territorycode','Type':8,'Value':{'__type':'OptionSet','Name':null,'Value':1}}]}", Id = Guid.NewGuid(), Name = "name1", Operation = EntityCacheOperation.Create, RecordId = "id1", SourceSystemId = "ssId1", Type = "type1", RequestsCount = 1 } }; var entityCacheMessage = new EntityCacheMessage() { EntityCacheId = entityCache[0].Id, Name = string.Format(entityCacheMessageName, entityCache[0].RecordId, entityCache[0].Id) }; var messageGuid = Guid.NewGuid(); var responseEntity = new Crm.Common.IntegrationLayer.Model.ResponseEntity() { StatusCode = HttpStatusCode.Created, Content = "content", Cookies = new Dictionary <string, string>() }; A.CallTo(() => outboundSynchDataService.GetCreatedEntityCacheToProcess(entityName, batchSize)).Returns(entityCache); A.CallTo(() => outboundSynchDataService.GetSecretKey()).Returns(secretKey); A.CallTo(() => jwtService.GetIssuedAtTime()).Returns(issuedAtTime); A.CallTo(() => outboundSynchDataService.GetExpiry()).Returns(expiry); A.CallTo(() => outboundSynchDataService.GetNotBeforeTime()).Returns(notBeforeTime); A.CallTo(() => jwtService.CreateJwtToken( secretKey, A <OutboundJsonWebTokenPayload> .That.Matches(el => el.Issuer == "msd" && el.Expiry == expiry && el.IssuedAtTime == issuedAtTime.ToString(CultureInfo.InvariantCulture) && el.NotBefore == notBeforeTime))) .Returns(jwtToken); A.CallTo(() => outboundSynchDataService.CreateEntityCacheMessage(A <EntityCacheMessage> .That.Matches(el => el.Name == entityCacheMessage.Name))).Returns(messageGuid); A.CallTo(() => createRequestPayloadCreator.GetPayload(A <Crm.Common.IntegrationLayer.Model.EntityModel> ._)).Returns(payload); A.CallTo(() => jwtService.SendHttpRequest(HttpMethod.Post, createServiceUrl, jwtToken, payload, messageGuid.ToString())).Returns(responseEntity); // When outboundSynchService.ProcessEntityCacheOperation(Operation.Create); // Then A.CallTo(() => logger.LogInformation($"Processing {Enum.GetName(typeof(EntityCacheMessageStatusReason), Operation.Create)} EntityCache for entity: {entityName}")).MustHaveHappened(); A.CallTo(() => logger.LogInformation($"Integration layer endpoint: {createServiceUrl}")).MustHaveHappened(); A.CallTo(() => logger.LogInformation($"Retrieving entity cache records to process with maximum batch size: {batchSize}")).MustHaveHappened(); A.CallTo(() => logger.LogInformation("Found 1 records to be processed")).MustHaveHappened(); A.CallTo(() => logger.LogInformation($"Executed call to integration layer. EntityCacheMessage Status Reason: {Enum.GetName(typeof(EntityCacheMessageStatusReason), EntityCacheMessageStatusReason.SuccessfullySentToIL)}")).MustHaveHappened(); A.CallTo(() => outboundSynchDataService.UpdateEntityCacheStatus(entityCache[0].Id, Status.Active, EntityCacheStatusReason.InProgress)).MustHaveHappened(); A.CallTo(() => outboundSynchDataService.UpdateEntityCacheMessageStatus(messageGuid, Status.Inactive, EntityCacheMessageStatusReason.SuccessfullySentToIL, A <string> ._)).MustHaveHappened(); A.CallTo(() => outboundSynchDataService.UpdateEntityCacheSendToIntegrationLayerStatus(entityCache[0].Id, true, null)).MustHaveHappened(); }