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(); } }
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); } } }
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); } }
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); } }
private Task Callback(IServiceBusMessage message, IRequestInfo requestInfo) => Task.CompletedTask;
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); }
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; }