示例#1
0
        public static void LogError(PollState ps, HttpChannelPoller.PollingError error)
        {
            switch (error)
            {
            case HttpChannelPoller.PollingError.UnableToConnect:
            {
                Logger.Warn($"Error GET {ps.NextUrl}: Unable to connect to api");
                break;
            }

            case HttpChannelPoller.PollingError.UnknownErrorOnGet:
            {
                Logger.Error($"Error GET {ps.NextUrl}: Unknown error on get");
                break;
            }

            case HttpChannelPoller.PollingError.ErrorMakingHttpRequest:
            {
                Logger.Error($"Error GET {ps.NextUrl}: making request");
                break;
            }

            case HttpChannelPoller.PollingError.ErrorDeserializingContent:
            {
                Logger.Fatal($"Error GET {ps.NextUrl}: This is probably never going to work");
                break;
            }
            }
        }
示例#2
0
        public static PollState ProcessTransportMessage(
            PollState pollStatus,
            TransportMessage transportMessage,
            Func <Type, Action <DomainMessageProcessingContext, object> > processors)
        {
            // Logger.Trace("---------------------------------------------------------");
            // Logger.Trace($"PROCESSING TRANSPORT MESSAGE FOR: {pollStatus.MessageEndpointName}");
            List <DomainMessage> unprocessedMessages = transportMessage
                                                       .Messages
                                                       .Where(x => (x.Header.MessageNumber) > pollStatus.LastMessageSuccessfullyProcessed)
                                                       .OrderBy(x => x.Header.MessageNumber)
                                                       .ToList();

            Link prevLink = transportMessage.Header.Links.SingleOrDefault(l => l.Rel.Contains(Link.Previous));
            bool areUnprocessedMessagesInEarlierTransportMessage =
                unprocessedMessages.Any() &&
                prevLink != null &&
                unprocessedMessages.Min(x => x.Header.MessageNumber) != pollStatus.LastMessageSuccessfullyProcessed + 1;

            if (areUnprocessedMessagesInEarlierTransportMessage)
            {
                return(pollStatus.With(prevLink.Href, 0, pollStatus.LastMessageSuccessfullyProcessed));
            }

            var initialState = MessageEndpointContext.Start(pollStatus.MessageEndpointName);

            MessageEndpointContext ProcessMessageF(MessageEndpointContext context, DomainMessage domainMessage) =>
            ProcessNext(context, domainMessage, processors);

            var finalState = unprocessedMessages.Aggregate(
                initialState,
                ProcessMessageF);


            var nextLink = transportMessage.Header.Links.SingleOrDefault(l => l.Rel.Contains(Link.Next));
            var selfLink = transportMessage.Header.Links.Single(l => l.Rel.Contains(Link.Self));

            var finishedWithThisTransportMessage =
                nextLink != null &&
                unprocessedMessages.Count == finalState.ProcessedSuccessfully.Count;

            var newLastMessageNumberProcessed = finalState
                                                .ProcessedSuccessfully
                                                .Select(x => x.Header.MessageNumber)
                                                .Concat(new[] { pollStatus.LastMessageSuccessfullyProcessed })
                                                .Max();

            return(finishedWithThisTransportMessage ?
                   pollStatus.With(
                       nextLink.Href,
                       PollState.NoDelay,
                       newLastMessageNumberProcessed) :
                   pollStatus.With(
                       selfLink.Href,
                       pollStatus.DefaultDelayMs,
                       newLastMessageNumberProcessed));
        }
示例#3
0
        // This is the entry point for an application to use this library.
        // Calling this function sets up the system to poll an endpoint, passing messages through the
        // relevant domainMessageProcessors.
        // Incidentally, it is essentially the last function in the receiving library to be non-functional,
        // what with its returning a Task (as good as void), and having a while loop that mutates the pollStatus
        // object.
        public static async Task MainInfinitePollerAsync(
            MessageEndpointState endpointState,
            Func <Type, Action <DomainMessageProcessingContext, object> > domainMessageProcessors,
            Func <string, Either <DeserializeError, TransportMessage> > deserializeTransportMessage,
            uint pollRateMs,
            Dictionary <HttpChannelPoller.PollingError, uint> pollingErrorDelays,
            Func <IHttpService> httpServiceCreator,
            CancellationToken ct)
        {
            using (IHttpService client = httpServiceCreator())
            {
                while (!ct.IsCancellationRequested)
                {
                    var channelLocation = endpointState.Channel;
                    var uriBuilder      = new UriBuilder(
                        channelLocation.HttpChannelBase.Scheme,
                        channelLocation.HttpChannelBase.Host,
                        channelLocation.HttpChannelBase.Port)
                    {
                        Path = channelLocation.Path
                    };

                    var startUrl = uriBuilder.ToString();

                    var pollStatus = new PollState(endpointState.EndpointName,
                                                   pollRateMs, pollingErrorDelays, endpointState.LastSuccessfullyProcessedMessage, startUrl, 0);

                    while (pollStatus.CanPoll())
                    {
                        if (pollStatus.ShouldDelay())
                        {
                            await Task.Delay((int)pollStatus.DelayMs, ct);
                        }

                        pollStatus = await Execute(
                            pollStatus,
                            client,
                            ct,
                            domainMessageProcessors,
                            deserializeTransportMessage);
                    }
                }
            }
        }
示例#4
0
        // The start of a largely functional code.
        // Given the current pollstate (ps), this function polls the channel through the 'client',
        // executing the relevant domainMessageProcessors for any new messages received, in order,
        // without processing duplicates.
        public static async Task <PollState> Execute(
            PollState ps,
            IHttpService client,
            CancellationToken ct,
            Func <Type, Action <DomainMessageProcessingContext, object> > domainMessageProcessors,
            Func <string, Either <DeserializeError, TransportMessage> > deserializeTransportMessage)
        {
            Either <HttpChannelPoller.PollingError, TransportMessage> transportMessage =
                await HttpChannelPoller.Poll(ps.NextUrl, client, ct, deserializeTransportMessage);

            PollState pollStatus = transportMessage.Match(
                error =>
            {
                TransportMessageProcessor.LogError(ps, error);
                return(ps.WithDelayFor(error));
            },
                m => TransportMessageProcessor.ProcessTransportMessage(
                    ps,
                    m,
                    domainMessageProcessors));

            return(pollStatus);
        }