示例#1
0
 public async ValueTask Publish(IServiceBusMessage message)
 {
     await _sender.SendMessageAsync(new ServiceBusMessage
     {
         Body = BinaryData.FromStream(message.GetStream())
     });
 }
        private async Task ProcessMessage(IServiceBusMessage serviceBusMessage)
        {
            var bodyString = await serviceBusMessage.GetMessageBody();
            dynamic body = this.serialiser.Deserialise(bodyString);

            var failed = false;

            foreach (var subscriber in this.subscribers.Where(subscriber => subscriber.CanProcess(serviceBusMessage)))
            {
                try
                {
                    await this.CallSubscriber(subscriber, body, serviceBusMessage);
                }
                catch (Exception)
                {
                    failed = true;
                    break;
                }
            }

            if (failed)
            {
                await serviceBusMessage.AbandonAsync();
            }
            else
            {
                await serviceBusMessage.CompleteAsync();
            }
        }
        private async Task ProcessMessage(IServiceBusMessage serviceBusMessage)
        {
            var bodyString = await serviceBusMessage.GetMessageBody();

            dynamic body = this.serialiser.Deserialise(bodyString);

            var failed = false;

            foreach (var subscriber in this.subscribers.Where(subscriber => subscriber.CanProcess(serviceBusMessage)))
            {
                try
                {
                    await this.CallSubscriber(subscriber, body, serviceBusMessage);
                }
                catch (Exception)
                {
                    failed = true;
                    break;
                }
            }

            if (failed)
            {
                await serviceBusMessage.AbandonAsync();
            }
            else
            {
                await serviceBusMessage.CompleteAsync();
            }
        }
 public ValueTask Publish(IServiceBusMessage message)
 {
     foreach (var consumer in _consumers)
     {
         consumer.Enqueue(message);
     }
     return(new());
 }
        private IEnumerable <Dictionary <string, object> > RecieveMessages(ServiceBusSettings settings, ServiceBusReceiver reciever, ILogger logger)
        {
            int total = 0;
            int batchSize;


            while (true)
            {
                if (settings.MaxNumberOfMessages - total >= settings.BatchSize)
                {
                    batchSize = settings.BatchSize;
                }
                else
                {
                    batchSize = settings.MaxNumberOfMessages - total;
                }

                var messages = new IServiceBusMessage[0];
                if (batchSize <= 0)
                {
                    break;
                }


                var messagesTask = Task.Run(() =>
                {
                    try
                    {
                        return(reciever.ReceiveMessageBatchAsync(batchSize, TimeSpan.FromSeconds(MessageBusWaitTime)));
                    }
                    catch (Exception ex)
                    {
                        logger.Error($"Cannot receive messages. {Environment.NewLine}{ex}");
                        return(Task.FromResult(new IServiceBusMessage[0]));
                    }
                });
                messages = messagesTask.Result ?? new IServiceBusMessage[0];
                total   += messages.Length;


                // no message in queue => let's finish
                if (messages.Length == 0)
                {
                    break;
                }

                // enumerate messages
                for (int j = 0; j < messages.Length; j++)
                {
                    var oneLevelMessage = new Dictionary <string, object>(messages[j].Properties);
                    oneLevelMessage.Add("ID", messages[j].Id);
                    logger.Debug($"Enumerating message with consultant '{messages[j].Id}'.");
                    logger.Debug($"oneLevelMessage: '{string.Join(";", oneLevelMessage)}'.");

                    yield return(oneLevelMessage);
                }
            }
        }
示例#6
0
        public T Deserialize <T>(IServiceBusMessage message)
        {
            using var stream = message.GetStream();
            using var reader = new StreamReader(stream);
            using var json   = new JsonTextReader(reader);
            var consumerMessage = _serializer.Deserialize <T>(json);

            return(consumerMessage);
        }
        private async Task CallSubscriber(ISubscriber subscriber, object body, IServiceBusMessage serviceBusMessage)
        {
            var dynamicSubscriber = subscriber as IDynamicSubscriber;

            if (dynamicSubscriber != null)
            {
                await dynamicSubscriber.Process(serviceBusMessage, body);
            }
        }
        private async Task <int> GetOrCreateTaskLogId(IServiceBusMessage message, CancellationToken cancellationToken, ITaskClient taskClient, Guid projectId, Guid planId, Guid jobId, Guid parentTimelineId, string timelineName, string hubName)
        {
            // attempt to get from message
            var logIdObject = message.GetProperty(VstsMessageConstants.TaskLogIdPropertyName);
            var taskLogId   = 0;
            var gotLogId    = logIdObject != null && int.TryParse(logIdObject.ToString(), out taskLogId);

            if (gotLogId)
            {
                return(taskLogId);
            }

            // attempt to find existing
            var records = await taskClient.GetRecordsAsync(projectId, hubName, planId, parentTimelineId, userState : null, cancellationToken : cancellationToken).ConfigureAwait(false);

            foreach (var record in records)
            {
                if (string.Equals(record.Name, timelineName, StringComparison.OrdinalIgnoreCase))
                {
                    return(record.Log.Id);
                }
            }

            // Create a new timeline
            var subTimelineId = Guid.NewGuid();

            // create a log file
            var logsSubtimelineId = string.Format(@"logs\{0:D}", subTimelineId);
            var taskLog           = await taskClient.CreateLogAsync(projectId, hubName, planId, new TaskLog(logsSubtimelineId), userState : null, cancellationToken : cancellationToken).ConfigureAwait(false);

            // create a sub-timeline
            var timelineRecord = new TimelineRecord
            {
                Id              = subTimelineId,
                Name            = timelineName,
                StartTime       = DateTime.UtcNow,
                State           = TimelineRecordState.InProgress,
                RecordType      = "task", // Record type can be job or task, as we will be dealing only with task here
                WorkerName      = this.settings.WorkerName,
                Order           = 1,      // The job timeline record must be at order 1
                Log             = taskLog,
                ParentId        = jobId,
                PercentComplete = 0,
                ErrorCount      = 0,
                WarningCount    = 0
            };

            await taskClient.UpdateTimelineRecordsAsync(projectId, hubName, planId, parentTimelineId, new List <TimelineRecord> {
                timelineRecord
            }, cancellationToken).ConfigureAwait(false);

            // save the taskLogId on the message
            taskLogId = taskLog.Id;

            return(taskLogId);
        }
        public Task Process(IServiceBusMessage metadata, dynamic body)
        {
            Console.WriteLine("++++++");
            Console.WriteLine("Message type: " + metadata.MessageType);
            Console.WriteLine("Foo: " + body.Foo);
            Console.WriteLine("Bar: " + body.Bar);
            Console.WriteLine("++++++");
            Console.WriteLine();

            return Task.FromResult(0);
        }
        public Task Process(IServiceBusMessage metadata, dynamic body)
        {
            Console.WriteLine("++++++");
            Console.WriteLine("Message type: " + metadata.MessageType);
            Console.WriteLine("Foo: " + body.Foo);
            Console.WriteLine("Bar: " + body.Bar);
            Console.WriteLine("++++++");
            Console.WriteLine();

            return(Task.FromResult(0));
        }
        private async Task DeadLetterMessage(T vstsMessage, IServiceBusMessage message, IDictionary <string, string> eventProperties, string errorMessage, CancellationToken cancellationToken)
        {
            if (!eventProperties.ContainsKey(VstsMessageConstants.ErrorTypePropertyName))
            {
                eventProperties[VstsMessageConstants.ErrorTypePropertyName] = errorMessage;
            }

            await this.TryFailOrchestrationPlan(vstsMessage, cancellationToken).ConfigureAwait(false);

            await clientLogger.LogError("DeadLetterMessage", errorMessage, eventProperties, cancellationToken).ConfigureAwait(false);

            await this.queueClient.DeadLetterAsync(message.GetLockToken()).ConfigureAwait(false);
        }
        public async Task ReceiveAsync(IServiceBusMessage message, CancellationToken cancellationToken)
        {
            // setup basic message properties
            var       messageStopwatch = Stopwatch.StartNew();
            var       eventProperties  = ExtractServiceBusMessageProperties(message);
            Exception exception        = null;
            T         vstsMessage      = null;

            try
            {
                // validate & extract
                string errorMessage;
                if (!ExtractMessage(message, out vstsMessage, out errorMessage))
                {
                    await this.DeadLetterMessage(null, message, eventProperties, errorMessage, cancellationToken).ConfigureAwait(false);

                    await this.StopTimer("MessageExtractionFailed", messageStopwatch, eventProperties, cancellationToken).ConfigureAwait(false);

                    return;
                }

                // merge vsts properties
                foreach (var property in vstsMessage.GetMessageProperties())
                {
                    eventProperties[property.Key] = property.Value;
                }

                // process message
                await this.ProcessMessage(message, this.scheduleHandler, cancellationToken, vstsMessage, eventProperties).ConfigureAwait(false);

                await this.queueClient.CompleteAsync(message.GetLockToken()).ConfigureAwait(false);

                await this.StopTimer("MessageProcessingSucceeded", messageStopwatch, eventProperties, cancellationToken).ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                exception = ex;
            }

            // c#6.0 allows await inside catch but this code is not 6.0 yet :-(
            if (exception != null)
            {
                await this.StopTimer("MessageProcessingFailed", messageStopwatch, eventProperties, cancellationToken).ConfigureAwait(false);

                await this.AbandonOrDeadLetterMessage(vstsMessage, message, exception, eventProperties, cancellationToken).ConfigureAwait(false);
            }
        }
示例#13
0
        public async ValueTask Publish(IServiceBusMessage message)
        {
            var now      = _client.GetDbTime();
            var data     = message.GetString();
            var messages = _client.GetCachedSubscriptions(_topic).Select(d => new MessageDocument
            {
                Id             = Guid.NewGuid(),
                DeliveryDate   = message.DeliveryDate,
                LockExpiration = now,
                PublishDate    = now,
                Queue          = d.Queue,
                Topic          = _topic,
                Data           = data,
                Attempt        = 0,
            }).ToList();

            if (messages.Count > 0)
            {
                await _client.Messages.InsertManyAsync(messages);
            }
        }
        private async Task DelayedAbandon(IServiceBusMessage message, int attempt, Exception exception, IDictionary <string, string> eventProperties, CancellationToken cancellationToken)
        {
            // exponential backoff
            var delayMsecs = this.settings.AbandonDelayMsecs + (1000 * (int)(Math.Pow(2, Math.Max(0, attempt - 1)) - 1));

            delayMsecs = Math.Min(delayMsecs, this.settings.MaxAbandonDelayMsecs);
            var abandoningMessageDueToException = string.Format("Abandoning message due to exception in [{0}]ms", delayMsecs);
            await clientLogger.LogException(exception, "MessageProcessingException", abandoningMessageDueToException, eventProperties, cancellationToken).ConfigureAwait(false);

            while (delayMsecs > 0)
            {
                // await message.RenewLockAsync().ConfigureAwait(false);
                var delay = settings.LockRefreshDelayMsecs == 0 ? 10 : settings.LockRefreshDelayMsecs;
                await Task.Delay(delay, cancellationToken);

                delayMsecs -= delay;
                cancellationToken.ThrowIfCancellationRequested();
            }

            await this.queueClient.AbandonAsync(message.GetLockToken()).ConfigureAwait(false);
        }
        private async Task AbandonOrDeadLetterMessage(T vstsMessage, IServiceBusMessage message, Exception exception, IDictionary <string, string> eventProperties, CancellationToken cancellationToken)
        {
            // best effort to get attempt safely
            int    attempt;
            string attemptString;

            eventProperties.TryGetValue(VstsMessageConstants.RetryAttemptPropertyName, out attemptString);
            int.TryParse(attemptString, out attempt);

            var exceptionTypeName = exception.GetType().Name;

            eventProperties[VstsMessageConstants.ErrorMessagePropertyName] = exception.Message.Substring(0, Math.Min(exception.Message.Length, MaxExceptionMessageLength));
            eventProperties[VstsMessageConstants.ErrorTypePropertyName]    = exceptionTypeName;

            if (attempt > this.settings.MaxRetryAttempts)
            {
                var errorMessage = string.Format("[{0} exceeded max attempts [{1}]. Last Ex [{2}] {3}", attempt, this.settings.MaxRetryAttempts, exceptionTypeName, exception.Message);
                await this.DeadLetterMessage(vstsMessage, message, eventProperties, errorMessage, cancellationToken).ConfigureAwait(false);
            }
            else
            {
                await this.DelayedAbandon(message, attempt, exception, eventProperties, cancellationToken).ConfigureAwait(false);
            }
        }
示例#16
0
 private Task Callback(IServiceBusMessage message, IRequestInfo requestInfo) => Task.CompletedTask;
示例#17
0
 public DefaultPublisherContext(IPublisherTransport transport, IServiceBusMessage message)
 {
     Transport = transport;
     Message   = message;
 }
 public DefaultConsumerContext(IServiceBusMessage message, IConsumerDefinition consumerDefinition)
 {
     Message            = message;
     ConsumerDefinition = consumerDefinition;
 }
        private static IDictionary <string, string> ExtractServiceBusMessageProperties(IServiceBusMessage message)
        {
            var eventProperties = new Dictionary <string, string>();
            var attemptObject   = message.GetProperty(VstsMessageConstants.RetryAttemptPropertyName) ?? "0";
            int attempt;

            int.TryParse(attemptObject.ToString(), out attempt);
            attempt++;

            var taskLogIdObject = message.GetProperty(VstsMessageConstants.TaskLogIdPropertyName) ?? string.Empty;

            eventProperties[VstsMessageConstants.RetryAttemptPropertyName] = attempt.ToString();
            eventProperties[VstsMessageConstants.MessageIdPropertyName]    = message.GetMessageId();
            eventProperties[VstsMessageConstants.MachineNamePropertyName]  = Environment.MachineName;
            eventProperties[VstsMessageConstants.TaskLogIdPropertyName]    = taskLogIdObject.ToString();

            return(eventProperties);
        }
        private async Task CallSubscriber(ISubscriber subscriber, object body, IServiceBusMessage serviceBusMessage)
        {
            var dynamicSubscriber = subscriber as IDynamicSubscriber;

            if (dynamicSubscriber != null)
            {
                await dynamicSubscriber.Process(serviceBusMessage, body);
            }
        }
        internal static bool ExtractMessage(IServiceBusMessage message, out T vstsMessage, out string validationErrors)
        {
            T extractedMessage;

            vstsMessage      = null;
            validationErrors = null;

            var messageBody = message.GetBody();

            if (string.IsNullOrEmpty(messageBody))
            {
                validationErrors = "Message with null or empty body is invalid";
                return(false);
            }

            try
            {
                extractedMessage = JsonConvert.DeserializeObject <T>(messageBody);
            }
            catch (Exception ex)
            {
                validationErrors = string.Format("Failed to de-serialize message with exception: [{0}] : {1}", ex.GetType().Name, ex.Message);
                return(false);
            }

            if (extractedMessage == null)
            {
                validationErrors = "Empty message is invalid";
                return(false);
            }

            var errorMessageBuilder = new StringBuilder();
            var hasErrors           = false;

            if (extractedMessage.ProjectId == Guid.Empty)
            {
                errorMessageBuilder.AppendFormat("{0}ProjectId is empty", string.Empty);
                hasErrors = true;
            }

            if (string.IsNullOrEmpty(extractedMessage.AuthToken))
            {
                errorMessageBuilder.AppendFormat("{0}AuthToken is null", hasErrors ? " | " : string.Empty);
                hasErrors = true;
            }

            if (extractedMessage.JobId == Guid.Empty)
            {
                errorMessageBuilder.AppendFormat("{0}JobId is empty", hasErrors ? " | " : string.Empty);
                hasErrors = true;
            }

            if (extractedMessage.PlanId == Guid.Empty)
            {
                errorMessageBuilder.AppendFormat("{0}PlanId is empty", hasErrors ? " | " : string.Empty);
                hasErrors = true;
            }

            if (string.IsNullOrEmpty(extractedMessage.VstsUrl))
            {
                errorMessageBuilder.AppendFormat("{0}VstsUrl is null", hasErrors ? " | " : string.Empty);
                hasErrors = true;
            }

            // use ScheduleRequesterAlias if RequesterEmail is null or unresolved
            if (string.IsNullOrEmpty(extractedMessage.RequesterEmail) || extractedMessage.RequesterEmail.StartsWith("$("))
            {
                extractedMessage.RequesterEmail = extractedMessage.ScheduleRequesterAlias;
            }

            Uri vstsUri;

            if (!Uri.TryCreate(extractedMessage.VstsUrl, UriKind.Absolute, out vstsUri))
            {
                errorMessageBuilder.AppendFormat("{0}VstsUrl is not a valid URI{1}", hasErrors ? " | " : string.Empty, extractedMessage.VstsUrl);
                hasErrors = true;
            }

            extractedMessage.VstsUri = vstsUri;

            // temp hack until we get the correct URL to use from VSTS
            if (!hasErrors && extractedMessage.VstsHub == HubType.Release && (string.IsNullOrEmpty(extractedMessage.VstsPlanUrl) || extractedMessage.VstsPlanUrl.StartsWith("$(")))
            {
                extractedMessage.VstsPlanUrl = extractedMessage.VstsUrl.ToLowerInvariant().Contains("vsrm")
                    ? extractedMessage.VstsUrl
                    : extractedMessage.VstsUrl.Replace(".visualstudio.com", ".vsrm.visualstudio.com");
            }

            Uri vstsPlanUri;

            if (!Uri.TryCreate(extractedMessage.VstsPlanUrl, UriKind.Absolute, out vstsPlanUri))
            {
                errorMessageBuilder.AppendFormat("{0}VstsPlanUrl is not a valid URI{1}", hasErrors ? " | " : string.Empty, extractedMessage.VstsPlanUrl);
                hasErrors = true;
            }

            extractedMessage.VstsPlanUri = vstsPlanUri;

            switch (extractedMessage.VstsHub)
            {
            case HubType.Build:
                hasErrors = ValidateAndExtractBuildProperties(extractedMessage, errorMessageBuilder, hasErrors);
                break;

            case HubType.Release:
                hasErrors = ValidateReleaseProperties(extractedMessage, errorMessageBuilder, hasErrors);
                break;

            default:
                throw new NotSupportedException(string.Format("Hub [{0}] is not suppported", extractedMessage.VstsHub));
            }

            vstsMessage      = hasErrors ? null : extractedMessage;
            validationErrors = hasErrors ? errorMessageBuilder.ToString() : null;
            return(!hasErrors);
        }
 public bool CanProcess(IServiceBusMessage metadata)
 {
     return(true);
 }
        private async Task ProcessMessage(IServiceBusMessage message, IVstsScheduleHandler <T> handler, CancellationToken cancellationToken, T vstsMessage, IDictionary <string, string> eventProperties)
        {
            // create client
            var projectId        = vstsMessage.ProjectId;
            var planId           = vstsMessage.PlanId;
            var vstsPlanUrl      = vstsMessage.VstsPlanUri;
            var vstsUrl          = vstsMessage.VstsUri;
            var authToken        = vstsMessage.AuthToken;
            var parentTimelineId = vstsMessage.TimelineId;
            var jobId            = vstsMessage.JobId;
            var hubName          = vstsMessage.VstsHub.ToString();
            var taskHttpClient   = this.GetTaskClient(vstsPlanUrl, authToken, vstsMessage.SkipRaisePlanEvents);

            // create a timeline if required
            var timelineName = string.Format("{0}_{1}", this.settings.TimeLineNamePrefix, jobId.ToString("D"));
            var taskLogId    = await this.GetOrCreateTaskLogId(message, cancellationToken, taskHttpClient, projectId, planId, jobId, parentTimelineId, timelineName, hubName).ConfigureAwait(false);

            eventProperties[VstsMessageConstants.TaskLogIdPropertyName] = taskLogId.ToString();
            vstsMessage.TaskLogId = taskLogId;

            // setup VSTS instrumentation and wrap handler
            var vstsLogger       = new VstsLogger(clientLogger, taskHttpClient, hubName, projectId, planId, taskLogId, parentTimelineId, jobId);
            var loggersAggregate = new LoggersAggregate(new List <ILogger> {
                clientLogger, vstsLogger
            });
            var instrumentedHandler = new HandlerWithInstrumentation <T>(loggersAggregate, handler);

            // process request
            if (vstsMessage.RequestType == RequestType.Cancel)
            {
                // attempt to cancel
                await instrumentedHandler.Cancel(vstsMessage, cancellationToken).ConfigureAwait(false);
            }
            else
            {
                // already cancelled?
                var buildHttpClientWrapper   = GetBuildClient(vstsUrl, authToken);
                var releaseHttpClientWrapper = GetReleaseClient(vstsPlanUrl, authToken);
                var isSessionValid           = await JobStatusReportingHelper.IsSessionValid(vstsMessage, buildHttpClientWrapper, releaseHttpClientWrapper, cancellationToken).ConfigureAwait(false);

                if (!isSessionValid)
                {
                    await clientLogger.LogInfo("SessionAlreadyCancelled",
                                               string.Format("Skipping Execute for cancelled or deleted {0}", vstsMessage.VstsHub),
                                               eventProperties, cancellationToken).ConfigureAwait(false);

                    return;
                }

                // raise assigned event (to signal we got the message)
                var assignedEvent = new JobAssignedEvent(jobId);
                await taskHttpClient.RaisePlanEventAsync(projectId, hubName, planId, assignedEvent, cancellationToken).ConfigureAwait(false);

                // attempt to schedule
                var scheduleResult = await instrumentedHandler.Execute(vstsMessage, cancellationToken).ConfigureAwait(false);

                var reportingHelper = GetVstsJobStatusReportingHelper(vstsMessage, vstsLogger);

                if (scheduleResult.ScheduleFailed)
                {
                    // must first call job started, otherwise it cannot be completed
                    await reportingHelper.ReportJobStarted(DateTimeOffset.Now, "Started processing job.", CancellationToken.None).ConfigureAwait(false);

                    await reportingHelper.ReportJobCompleted(DateTimeOffset.Now, string.Format("Failed to schedule job. Message: {0}", scheduleResult.Message), false, CancellationToken.None).ConfigureAwait(false);
                }
                else if (vstsMessage.CompleteSychronously)
                {
                    // raise completed event
                    await reportingHelper.ReportJobCompleted(DateTimeOffset.Now, "Completed processing job.", true, CancellationToken.None).ConfigureAwait(false);
                }
            }
        }
 public bool CanProcess(IServiceBusMessage metadata)
 {
     return true;
 }