Example #1
0
        public void TestInitialize()
        {
            logger     = A.Fake <ILogger>();
            jwtService = A.Fake <IJwtService>();
            outboundSynchDataService         = A.Fake <IOutboundSynchronisationDataService>();
            createRequestPayloadCreator      = A.Fake <IRequestPayloadCreator>();
            updateRequestPayloadCreator      = A.Fake <IRequestPayloadCreator>();
            outboundSyncConfigurationService = A.Fake <IOutboundSyncConfigurationService>();
            entityModelDeserializer          = A.Fake <IEntityModelDeserializer>();

            A.CallTo(() => outboundSyncConfigurationService.BatchSize).Returns(batchSize);
            A.CallTo(() => outboundSyncConfigurationService.EntityName).Returns(entityName);
            A.CallTo(() => outboundSynchDataService.GetSecretKey()).Returns(secretKey);
            A.CallTo(() => outboundSynchDataService.GetRetries()).Returns(retries);
            A.CallTo(() => outboundSyncConfigurationService.CreateServiceUrl).Returns(createServiceUrl);
            A.CallTo(() => outboundSyncConfigurationService.UpdateServiceUrl).Returns(updateServiceUrl);
            A.CallTo(() => entityModelDeserializer.Deserialize(A <string> ._)).Returns(
                new Crm.Common.IntegrationLayer.Model.EntityModel
            {
                Fields = new List <Crm.Common.IntegrationLayer.Model.Field>
                {
                    new Crm.Common.IntegrationLayer.Model.Field
                    {
                        Name  = Tc.Crm.Common.Constants.Attributes.Customer.FirstName,
                        Type  = Crm.Common.IntegrationLayer.Model.FieldType.String,
                        Value = "Name"
                    }
                }
            });

            outboundSynchService = new OutboundSynchronisationService(
                logger,
                outboundSynchDataService,
                jwtService,
                createRequestPayloadCreator,
                updateRequestPayloadCreator,
                outboundSyncConfigurationService,
                entityModelDeserializer);
        }
        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);
                }
            }
        }