private async Task RunRoutineAsync(RoutineEventEnvelope eventEnvelope, CancellationToken ct) { for (; ;) { var carrier = new TransitionCarrier(this, eventEnvelope); //var transitionInfo = await data.GetTransitionDescriptorAsync(ct); //if (transitionInfo.Type == TransitionType.InvokeRoutine || // transitionInfo.Type == TransitionType.ContinueRoutine) //{ // var routineDescriptor = await data.GetRoutineDescriptorAsync(ct); // if (!string.IsNullOrEmpty(transitionInfo.ETag) && // transitionInfo.ETag != routineDescriptor.ETag) // { // // Ignore - stale duplicate message // return; // } //} try { await _transitionRunner.RunAsync(carrier, ct); break; } catch (ConcurrentRoutineExecutionException) { // re-try continue; } } }
private async Task ProcessEventAsync(string filePath, CancellationToken ct) { #warning Need to exclusively lock the file var json = File.ReadAllText(filePath); var eventEnvelope = JsonConvert.DeserializeObject <RoutineEventEnvelope>( json, CloudEventsSerialization.JsonSerializerSettings); json = null; // save memory if (eventEnvelope.EventDeliveryTime.HasValue && eventEnvelope.EventDeliveryTime > DateTimeOffset.UtcNow) { await Task.Delay(eventEnvelope.EventDeliveryTime.Value - DateTimeOffset.UtcNow); } for (; ;) { var carrier = new TransitionCarrier(this, eventEnvelope); var data = carrier; //var transitionInfo = await data.GetTransitionDescriptorAsync(ct); //if (transitionInfo.Type == TransitionType.InvokeRoutine || // transitionInfo.Type == TransitionType.ContinueRoutine) //{ // var routineDescriptor = await data.GetRoutineDescriptorAsync(ct); // if (!string.IsNullOrEmpty(transitionInfo.ETag) && // transitionInfo.ETag != routineDescriptor.ETag) // { // // Ignore - stale duplicate message // return; // } //} try { await _transitionRunner.RunAsync(carrier, data, ct); break; } catch (ConcurrentRoutineExecutionException) { // re-try continue; } } File.Delete(filePath); }
private async void RunMessageInBackground(Message message) { if (message.DeliverAt.HasValue && message.DeliverAt > DateTime.UtcNow) { await Task.Delay(message.DeliverAt.Value - DateTime.UtcNow); } else { await Task.Yield(); } var ct = CancellationToken.None; for (; ;) { var carrier = new TransitionCarrier(this, message); var data = carrier; carrier.Initialize(); //var transitionInfo = await data.GetTransitionDescriptorAsync(ct); //if (transitionInfo.Type == TransitionType.InvokeRoutine || // transitionInfo.Type == TransitionType.ContinueRoutine) //{ // var routineDescriptor = await data.GetRoutineDescriptorAsync(ct); // if (!string.IsNullOrEmpty(transitionInfo.ETag) && // transitionInfo.ETag != routineDescriptor.ETag) // { // // Ignore - stale duplicate message // return; // } //} try { await _transitionRunner.RunAsync(carrier, data, ct); break; } catch (ConcurrentRoutineExecutionException) { // re-try continue; } } }
private async void RunMessageInBackground(Message message) { if (message.DeliverAt.HasValue && message.DeliverAt > DateTime.UtcNow) { await Task.Delay(message.DeliverAt.Value - DateTime.UtcNow); } else { await Task.Yield(); } var ct = CancellationToken.None; if (message.IsEvent) { var serviceId = Serializer.Deserialize <ServiceId>(message[nameof(ServiceId)]); var eventId = Serializer.Deserialize <EventId>(message[nameof(EventId)]); var eventDesc = new EventDescriptor { EventId = eventId, ServiceId = serviceId }; var subscribers = DataStore.GetEventSubscribers(eventDesc); foreach (var subscriber in subscribers) { var routineId = Interlocked.Increment(ref DataStore.RoutineCounter); var routineRecord = new RoutineStateRecord { ETag = DateTime.UtcNow.Ticks.ToString("X16"), Id = routineId.ToString(), Completion = new TaskCompletionSource <string>() }; lock (DataStore.Routines) { DataStore.Routines.Add(routineRecord.Id, routineRecord); } var transitionDescriptor = new TransitionDescriptor { Type = TransitionType.InvokeRoutine, ETag = routineRecord.ETag }; var routineDescriptor = new RoutineDescriptor { MethodId = subscriber.MethodId, IntentId = _numericIdGenerator.NewId(), RoutineId = routineRecord.Id, ETag = routineRecord.ETag }; var invokeRoutineMessage = new Message { //["IntentId"] = _serializer.Serialize(intent.Id), [nameof(TransitionDescriptor)] = Serializer.SerializeToString(transitionDescriptor), [nameof(ServiceId)] = Serializer.SerializeToString(subscriber.ServiceId), [nameof(RoutineDescriptor)] = Serializer.SerializeToString(routineDescriptor), ["Parameters"] = message["Parameters"] }; DataStore.ScheduleMessage(invokeRoutineMessage); } } else { for (; ;) { var carrier = new TransitionCarrier(this, message); carrier.Initialize(); //var transitionInfo = await data.GetTransitionDescriptorAsync(ct); //if (transitionInfo.Type == TransitionType.InvokeRoutine || // transitionInfo.Type == TransitionType.ContinueRoutine) //{ // var routineDescriptor = await data.GetRoutineDescriptorAsync(ct); // if (!string.IsNullOrEmpty(transitionInfo.ETag) && // transitionInfo.ETag != routineDescriptor.ETag) // { // // Ignore - stale duplicate message // return; // } //} try { await _transitionRunner.RunAsync(carrier, ct); break; } catch (ConcurrentRoutineExecutionException) { // re-try continue; } } } }
public async Task ProcessMessageAsync( CloudQueueMessage message, FunctionExecutionContext context, DateTimeOffset messageReceiveTime, ILogger logger, CancellationToken ct) { _functionToQueueMap.TryGetValue(context.FunctionName, out var queue); _currentFunction.Value = new ExecutingFuncionInfo { FunctionName = context.FunctionName, Queue = queue }; try { #warning Keep message invisible while transitioning var eventEnvelope = JsonConvert.DeserializeObject <RoutineEventEnvelope>( message.AsString, CloudEventsSerialization.JsonSerializerSettings); // Free memory message.SetMessageContent((string)null); message.SetMessageContent((byte[])null); var transitionCarrier = new AzureStorageTransitionCarrier( eventEnvelope, _routinesTable, _servicesTable, _defaultSerializer); var concurrentExecutionDetected = false; try { await _transitionRunner.RunAsync(transitionCarrier, ct); } catch (ConcurrentTransitionException) { concurrentExecutionDetected = true; } if (concurrentExecutionDetected) { var transitionInfo = await transitionCarrier.GetTransitionDescriptorAsync(ct); if (transitionInfo.Type != TransitionType.InvokeRoutine) { #warning Host has a setting of max re-tries. Re-enqueue another message? Delay also? throw new Exception("re-try"); //// Re-try message by resetting its invisibility time. //await transitionsQueue.UpdateMessageAsync( // message, TimeSpan.Zero, MessageUpdateFields.Visibility, ct); //continue; } // If there are 2 or more messages that try to invoke the routine // for the first time, accept the first message and drop the rest. } //await transitionsQueue.DeleteMessageAsync(message.Id, message.PopReceipt, ct); } finally { _currentFunction.Value = default; } }