private EntityCacheMessage GetEntityCacheMessageModel(Entity entity)
        {
            if (entity == null)
            {
                return(null);
            }

            var entityCacheMessageModel = new EntityCacheMessage(entity.Id);

            if (EntityHelper.HasAttributeNotNull(entity, Attributes.EntityCacheMessage.Name))
            {
                entityCacheMessageModel.Name = entity.Attributes[Attributes.EntityCacheMessage.Name].ToString();
            }

            if (EntityHelper.HasAttributeNotNull(entity, Attributes.EntityCacheMessage.OutcomeId))
            {
                entityCacheMessageModel.OutcomeId = entity.Attributes[Attributes.EntityCacheMessage.OutcomeId].ToString();
            }

            if (EntityHelper.HasAttributeNotNull(entity, Attributes.EntityCacheMessage.EntityCacheId))
            {
                entityCacheMessageModel.EntityCacheId = ((EntityReference)entity.Attributes[Attributes.EntityCacheMessage.EntityCacheId]).Id;
            }

            return(entityCacheMessageModel);
        }
        public Entity PrepareEntityCacheMessage(EntityCacheMessage entityCacheMessageModel)
        {
            if (entityCacheMessageModel == null)
            {
                return(null);
            }

            var entityCacheMessage = new Entity(EntityName.EntityCacheMessage);

            entityCacheMessage.Id = entityCacheMessageModel.Id;

            if (entityCacheMessageModel.Name != null)
            {
                entityCacheMessage.Attributes[Attributes.EntityCacheMessage.Name] = entityCacheMessageModel.Name;
            }

            if (entityCacheMessageModel.EntityCacheId != null)
            {
                entityCacheMessage.Attributes[Attributes.EntityCacheMessage.EntityCacheId] = new EntityReference(EntityName.EntityCache, entityCacheMessageModel.EntityCacheId);
            }

            if (entityCacheMessageModel.OutcomeId != null)
            {
                entityCacheMessage.Attributes[Attributes.EntityCacheMessage.OutcomeId] = entityCacheMessageModel.OutcomeId;
            }

            if (entityCacheMessageModel.Notes != null)
            {
                entityCacheMessage.Attributes[Attributes.EntityCacheMessage.Notes] = entityCacheMessageModel.Notes;
            }

            return(entityCacheMessage);
        }
Пример #3
0
        public void TestUpdateExceptionThrownDoNextRetry()
        {
            // 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.Update,
                    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();

            A.CallTo(() => outboundSynchDataService.GetUpdatedEntityCacheToProcess(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(() => updateRequestPayloadCreator.GetPayload(A <Crm.Common.IntegrationLayer.Model.EntityModel> ._)).Returns(payload);
            A.CallTo(() => jwtService.SendHttpRequest(HttpMethod.Patch, updateServiceUrl + "/" + entityCache[0].SourceSystemId, jwtToken, payload, messageGuid.ToString())).Throws(new Exception("error"));

            // When
            outboundSynchService.ProcessEntityCacheOperation(Operation.Update);

            // Then
            A.CallTo(() => logger.LogInformation($"Processing {Enum.GetName(typeof(EntityCacheMessageStatusReason), Operation.Update)} EntityCache for entity: {entityName}")).MustHaveHappened();
            A.CallTo(() => logger.LogInformation($"Integration layer endpoint: {updateServiceUrl}")).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(() => outboundSynchDataService.UpdateEntityCacheStatus(entityCache[0].Id, Status.Active, EntityCacheStatusReason.InProgress)).MustHaveHappened();
            A.CallTo(() => outboundSynchDataService.UpdateEntityCacheMessageStatus(messageGuid, Status.Inactive, EntityCacheMessageStatusReason.Failed, A <string> ._)).MustHaveHappened();
            A.CallTo(() => outboundSynchDataService.UpdateEntityCacheSendToIntegrationLayerStatus(entityCache[0].Id, false, A <DateTime> .That.Matches(d => d > DateTime.UtcNow.AddMinutes(5) && d < DateTime.UtcNow.AddMinutes(10)))).MustHaveHappened();

            A.CallTo(() => logger.LogInformation($"Exception thrown while executing call to service layer. EntityCacheMessage Status Reason: {Enum.GetName(typeof(EntityCacheMessageStatusReason), EntityCacheMessageStatusReason.Failed)}")).MustHaveHappened();
            A.CallTo(() => logger.LogError(A <string> ._)).MustHaveHappened();
        }
Пример #4
0
        public void TestUpdateMaxRetries()
        {
            // Given
            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.Update,
                    RecordId       = "id1",
                    SourceSystemId = "ssId1",
                    Type           = "type1",
                    RequestsCount  = 4,
                    StatusReason   = EntityCacheStatusReason.InProgress
                }
            };
            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.Unauthorized,
                Content    = "content",
                Cookies    = new Dictionary <string, string>()
            };

            A.CallTo(() => outboundSynchDataService.GetUpdatedEntityCacheToProcess(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);

            // When
            outboundSynchService.ProcessEntityCacheOperation(Operation.Update);

            // Then
            A.CallTo(() => logger.LogInformation($"Processing {Enum.GetName(typeof(EntityCacheMessageStatusReason), Operation.Update)} EntityCache for entity: {entityName}")).MustHaveHappened();
            A.CallTo(() => logger.LogInformation($"Integration layer endpoint: {updateServiceUrl}")).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($"EntityCache record: name1 reached maximum retries 3 of calls to integration layer and will be failed")).MustHaveHappened();
            A.CallTo(() => outboundSynchDataService.UpdateEntityCacheStatus(entityCache[0].Id, Status.Inactive, EntityCacheStatusReason.Failed)).MustHaveHappened();
            A.CallTo(() => jwtService.SendHttpRequest(A <HttpMethod> ._, A <string> ._, A <string> ._, A <string> ._, A <string> ._)).MustNotHaveHappened();
        }
        private void ProcessUpdateEntityCache()
        {
            List <EntityCache> entityCacheCollection = outboundSynchronisationDataService.GetUpdatedEntityCacheToProcess(configurationService.EntityName, configurationService.BatchSize);

            if (entityCacheCollection == null)
            {
                return;
            }

            var token      = jwtService.CreateJwtToken(outboundSynchronisationDataService.GetSecretKey(), CreateTokenPayload());
            var serviceUrl = configurationService.UpdateServiceUrl;

            foreach (EntityCache entityCache in entityCacheCollection)
            {
                var entityCacheMessage = new EntityCacheMessage();
                entityCacheMessage.Id            = Guid.NewGuid();
                entityCacheMessage.EntityCacheId = entityCache.Id;
                entityCacheMessage.Name          = entityCacheMessage.Id.ToString();

                var entityCacheMessageId = CreateEntityCacheMessage(entityCacheMessage);
                UpdateEntityCacheStatus(entityCache.Id, Status.Active, EntityCacheStatusReason.InProgress);

                try
                {
                    var entityModel    = JsonConvert.DeserializeObject <EntityModel>(entityCache.Data);
                    var requestPayload = requestPayloadCreator.GetPayload(entityModel);
                    var response       = jwtService.SendHttpRequest(HttpMethod.Patch, serviceUrl, token, requestPayload, entityCacheMessageId.ToString());

                    if (IsResponseSuccessful(response.StatusCode))
                    {
                        UpdateEntityCacheMessageStatus(entityCacheMessageId, Status.Inactive, EntityCacheMessageStatusReason.SuccessfullySentToIL);
                    }
                    else
                    {
                        var notes = AppendNote(entityCacheMessage.Notes, response.StatusCode, response.Content);
                        UpdateEntityCacheMessageStatus(entityCacheMessageId, Status.Inactive, EntityCacheMessageStatusReason.Failed, notes);
                    }
                }
                catch (Exception e)
                {
                    logger.LogError(e.ToString());
                    var notes = AppendNote(entityCacheMessage.Notes, HttpStatusCode.InternalServerError, "Internal server error.");
                    UpdateEntityCacheMessageStatus(entityCacheMessageId, Status.Inactive, EntityCacheMessageStatusReason.Failed, notes);
                }
            }
        }
Пример #6
0
        /// <summary>
        /// To process all entitycache records which are of type contact and of operation create
        /// </summary>
        public void ProcessEntityCache()
        {
            var entityCacheCollection = outboundSynchronisationDataService.GetEntityCacheToProcess(configurationService.OutboundSyncEntityName, configurationService.OutboundSyncBatchSize);

            if (entityCacheCollection == null)
            {
                return;
            }
            foreach (EntityCache entityCache in entityCacheCollection)
            {
                var entityCacheMessage = new EntityCacheMessage();
                entityCacheMessage.Id            = Guid.NewGuid();
                entityCacheMessage.EntityCacheId = entityCache.Id;
                entityCacheMessage.Name          = entityCacheMessage.Id.ToString();

                var entityCacheMessageId = CreateEntityCacheMessage(entityCacheMessage);
                UpdateEntityCacheStatus(entityCache.Id, Status.Active, EntityCacheStatusReason.InProgress);
                UpdateEntityCacheMessageStatus(entityCacheMessageId, Status.Inactive, EntityCacheMessageStatusReason.SuccessfullySenttoIL);
            }
        }
        public Guid CreateEntityCacheMessage(EntityCacheMessage entityCacheMessageModel)
        {
            var entityCacheMessage = PrepareEntityCacheMessage(entityCacheMessageModel);

            return(CreateRecord(entityCacheMessage));
        }
Пример #8
0
 /// <summary>
 /// To create entitycachemessage record
 /// </summary>
 /// <param name="entityCacheMessageModel"></param>
 /// <returns></returns>
 public Guid CreateEntityCacheMessage(EntityCacheMessage entityCacheMessageModel)
 {
     return(outboundSynchronisationDataService.CreateEntityCacheMessage(entityCacheMessageModel));
 }
        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);
                }
            }
        }