public Task <FunctionResult> TryExecuteAsync(TriggeredFunctionData input, CancellationToken cancellationToken) { var e = ((ResilientEventHubData)input.TriggerValue).EventData; e.Properties.TryGetValue("ExceptionCount", out var count); if (e.Properties.TryGetValue("StopInvalidData", out var exc) && exc is bool bexc && bexc == true) { return(Task.FromResult(new FunctionResult(false, (Exception)typeof(EventSubscriberStopException).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(Result) }, null) .Invoke(new object[] { CreateResult(SubscriberStatus.InvalidData, null) })))); } if ((int)count > 0) { e.Properties["ExceptionCount"] = (int)count - 1; TotalError++; return(Task.FromResult(new FunctionResult(false, new DivideByZeroException()))); } else { TotalSuccess++; return(Task.FromResult(new FunctionResult(true))); } }
internal async Task ProcessSessionMessageAsync(ProcessSessionMessageEventArgs args) { _concurrencyUpdateManager?.MessageProcessed(); using (CancellationTokenSource linkedCts = CancellationTokenSource.CreateLinkedTokenSource(args.CancellationToken, _cancellationTokenSource.Token)) { var actions = new ServiceBusSessionMessageActions(args); if (!await _sessionMessageProcessor.Value.BeginProcessingMessageAsync(actions, args.Message, linkedCts.Token).ConfigureAwait(false)) { return; } ServiceBusTriggerInput input = ServiceBusTriggerInput.CreateSingle(args.Message, actions, _client.Value); TriggeredFunctionData data = input.GetTriggerFunctionData(); FunctionResult result = await _triggerExecutor.TryExecuteAsync(data, linkedCts.Token).ConfigureAwait(false); if (actions.ShouldReleaseSession) { args.ReleaseSession(); } await _sessionMessageProcessor.Value.CompleteProcessingMessageAsync(actions, args.Message, result, linkedCts.Token).ConfigureAwait(false); } }
private async Task TryExecuteWithLoggingAsync(TriggeredFunctionData input, EventData message) { using (_logger.BeginScope(GetLinksScope(message))) { await _executor.TryExecuteAsync(input, _cts.Token).ConfigureAwait(false); } }
internal async Task InvokeJobFunction(DateTime lastOccurrence, bool isPastDue) { CancellationToken token = _cancellationTokenSource.Token; TimerInfo timerInfo = new TimerInfo(_attribute.Schedule); timerInfo.IsPastDue = isPastDue; TriggeredFunctionData input = new TriggeredFunctionData { // TODO: how to set this properly? ParentId = null, TriggerValue = timerInfo }; FunctionResult result = await _executor.TryExecuteAsync(input, token); if (!result.Succeeded) { token.ThrowIfCancellationRequested(); } if (_attribute.UseMonitor) { DateTime nextOccurrence = _schedule.GetNextOccurrence(lastOccurrence); await _scheduleMonitor.UpdateAsync(_timerName, lastOccurrence, nextOccurrence); } }
internal async Task InvokeJobFunction(DateTime lastOccurrence, bool isPastDue = false) { CancellationToken token = _cancellationTokenSource.Token; TimerInfo timerInfo = new TimerInfo(_attribute.Schedule, _scheduleStatus, isPastDue); TriggeredFunctionData input = new TriggeredFunctionData { TriggerValue = timerInfo }; try { FunctionResult result = await _executor.TryExecuteAsync(input, token); if (!result.Succeeded) { token.ThrowIfCancellationRequested(); } } catch { // We don't want any function errors to stop the execution // schedule. Errors will be logged to Dashboard already. } if (ScheduleMonitor != null) { _scheduleStatus = new ScheduleStatus { Last = lastOccurrence, Next = _schedule.GetNextOccurrence(lastOccurrence) }; await ScheduleMonitor.UpdateStatusAsync(_timerName, _scheduleStatus); } }
public async Task StartAsync(CancellationToken cancellationToken) { var connectionString = Environment.GetEnvironmentVariable(_attribute.IotHubConnectionString); var serviceClient = ServiceClient.CreateFromConnectionString(connectionString); var feedbackReceiver = serviceClient.GetFeedbackReceiver(); _listening = true; while (_listening) { var feedbackBatch = await feedbackReceiver.ReceiveAsync(); if (feedbackBatch == null) { continue; } var triggerData = new TriggeredFunctionData { TriggerValue = feedbackBatch }; await _executor.TryExecuteAsync(triggerData, CancellationToken.None); await feedbackReceiver.CompleteAsync(feedbackBatch); } }
public async Task OnMessage(MqttMessageReceivedEventArgs arg) { var token = _cancellationTokenSource.Token; var triggeredFunctionData = new TriggeredFunctionData { TriggerValue = arg.Message }; try { var result = await _executor.TryExecuteAsync(triggeredFunctionData, token).ConfigureAwait(false); if (!result.Succeeded) { if (!token.IsCancellationRequested) { _logger.LogCritical("Error firing function", result.Exception); } token.ThrowIfCancellationRequested(); } } catch (Exception e) { _logger.LogCritical("Error firing function", e); // We don't want any function errors to stop the execution. Errors will be logged to Dashboard already. } }
private IEnumerable <(TriggeredFunctionData messages, IEnumerable <string> ackIds)> getMessages(Task <BaseResponse <PullResponse> > pullTask) { var pull = pullTask.Result; if (pull != null && pull.Success && pull.Response.receivedMessages != null && pull.Response.receivedMessages.Count() > 0) { for (int i = 0; i < NumberOfMessageBlocks; i++) { var messagesBlock = pull.Response.receivedMessages.Skip(i * triggerAttribute.MaxBatchSize).Take(triggerAttribute.MaxBatchSize); IEnumerable <string> messages = messagesBlock.Select(c => System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(c.message.data))); IEnumerable <string> ackIds = messagesBlock.Select(c => c.ackId); TriggeredFunctionData input = new TriggeredFunctionData { TriggerValue = messages }; yield return(input, ackIds); } } else { if (pull != null && (!pull.Success)) { throw new Exception(pull.ErrorText); } } }
private async Task ExecuteAsync(Notification notification, CancellationToken cancellationToken) { var trigger = JObject.FromObject(notification); var input = new TriggeredFunctionData { TriggerValue = trigger }; var result = await _executor.TryExecuteAsync(input, cancellationToken); string?error = null; if (result.Exception != null && !(result.Exception is OperationCanceledException)) { _logger.LogError($"Exception during execution: {result.Exception}"); error = (result.Exception.InnerException ?? result.Exception).Message; } if (trigger.ContainsKey("Call")) { // TODO: Can we somehow detect that PerperTriggerValueBinder was already invoked for this? var call = (string)trigger["Call"] !; var callsCache = _ignite.GetCache <string, CallData>("calls"); var callDataResult = await callsCache.TryGetAsync(call); if (callDataResult.Success) { var callData = callDataResult.Value; callData.Finished = true; callData.Error = error; await callsCache.ReplaceAsync(call, callData); } } }
internal async Task ProcessMessageAsync(ProcessMessageEventArgs args) { EnsureIsRunning(); _concurrencyUpdateManager?.MessageProcessed(); using (CancellationTokenSource linkedCts = CancellationTokenSource.CreateLinkedTokenSource(args.CancellationToken, _cancellationTokenSource.Token)) { var actions = new ServiceBusMessageActions(args); if (!await _messageProcessor.Value.BeginProcessingMessageAsync(actions, args.Message, linkedCts.Token).ConfigureAwait(false)) { return; } var receiveActions = new ServiceBusReceiveActions(args); ServiceBusTriggerInput input = ServiceBusTriggerInput.CreateSingle(args.Message, actions, receiveActions, _client.Value); TriggeredFunctionData data = input.GetTriggerFunctionData(); FunctionResult result = await _triggerExecutor.TryExecuteAsync(data, linkedCts.Token).ConfigureAwait(false); try { await _messageProcessor.Value.CompleteProcessingMessageAsync(actions, args.Message, result, linkedCts.Token) .ConfigureAwait(false); } finally { receiveActions.EndExecutionScope(); } } }
private async Task InvokeJobFunction(MqttApplicationMessageReceivedEventArgs mqttApplicationMessageReceivedEventArgs) { var token = _cancellationTokenSource.Token; var mqttInfo = new PublishedMqttMessage( mqttApplicationMessageReceivedEventArgs.ApplicationMessage.Topic, mqttApplicationMessageReceivedEventArgs.ApplicationMessage.Payload, mqttApplicationMessageReceivedEventArgs.ApplicationMessage.QualityOfServiceLevel.ToString(), mqttApplicationMessageReceivedEventArgs.ApplicationMessage.Retain); var triggeredFunctionData = new TriggeredFunctionData { TriggerValue = mqttInfo }; try { var result = await _executor.TryExecuteAsync(triggeredFunctionData, token).ConfigureAwait(false); if (!result.Succeeded) { if (!token.IsCancellationRequested) { _logger.LogCritical("Error firing function", result.Exception); } token.ThrowIfCancellationRequested(); } } catch (Exception e) { _logger.LogCritical("Error firing function", e); // We don't want any function errors to stop the execution. Errors will be logged to Dashboard already. } }
private async Task ProcessPartitionItemsAsync(int partition, IEnumerable <IKafkaEventData> events, CancellationToken cancellationToken) { TopicPartition topicPartition = null; foreach (var kafkaEventData in events) { var triggerInput = KafkaTriggerInput.New(kafkaEventData); var triggerData = new TriggeredFunctionData { TriggerValue = triggerInput, }; await this.ExecuteFunctionAsync(triggerData, cancellationToken); if (topicPartition == null) { topicPartition = new TopicPartition(kafkaEventData.Topic, partition); } // Commiting after each function execution plays nicer with function scaler. // When processing a large batch of events where the execution of each event takes time // it would take Events_In_Batch_For_Partition * Event_Processing_Time to update the current offset. // Doing it after each event minimizes the delay this.Commit(new[] { new TopicPartitionOffset(topicPartition, kafkaEventData.Offset + 1) }); // offset is inclusive when resuming } }
public override async Task <string> RunAsync(TaskContext context, string rawInput) { string instanceId = context.OrchestrationInstance.InstanceId; var inputContext = new DurableActivityContext(instanceId, rawInput); // TODO: Wire up the parent ID to improve dashboard logging. Guid?parentId = null; var triggerInput = new TriggeredFunctionData { ParentId = parentId, TriggerValue = inputContext }; this.config.TraceHelper.FunctionStarting( this.config.HubName, this.activityName, this.activityVersion, instanceId, this.config.GetIntputOutputTrace(rawInput), functionType: FunctionType.Activity, isReplay: false); FunctionResult result = await this.executor.TryExecuteAsync(triggerInput, CancellationToken.None); if (!result.Succeeded) { // Flow the original activity function exception to the orchestration // without the outer FunctionInvocationException. Exception exceptionToReport = StripFunctionInvocationException(result.Exception); this.config.TraceHelper.FunctionFailed( this.config.HubName, this.activityName, this.activityVersion, instanceId, exceptionToReport?.ToString() ?? string.Empty, functionType: FunctionType.Activity, isReplay: false); if (exceptionToReport != null) { throw new TaskFailureException( $"Activity function '{this.activityName}' failed: {exceptionToReport.Message}", Utils.SerializeCause(exceptionToReport, MessagePayloadDataConverter.Default)); } } string serializedOutput = inputContext.GetSerializedOutput(); this.config.TraceHelper.FunctionCompleted( this.config.HubName, this.activityName, this.activityVersion, instanceId, this.config.GetIntputOutputTrace(serializedOutput), continuedAsNew: false, functionType: FunctionType.Activity, isReplay: false); return(serializedOutput); }
/// <summary> /// Process the file indicated by the specified <see cref="FileSystemEventArgs"/>. /// </summary> /// <param name="eventArgs">The <see cref="FileSystemEventArgs"/> indicating the file to process.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> to use.</param> /// <returns> /// A <see cref="Task"/> that returns true if the file was processed successfully, false otherwise. /// </returns> public virtual async Task <bool> ProcessFileAsync(FileSystemEventArgs eventArgs, CancellationToken cancellationToken) { try { string filePath = eventArgs.FullPath; using (StreamWriter statusWriter = AquireStatusFileLock(filePath, eventArgs.ChangeType)) { if (statusWriter == null) { return(false); } // write an entry indicating the file is being processed StatusFileEntry status = new StatusFileEntry { State = ProcessingState.Processing, Timestamp = DateTime.UtcNow, LastWrite = File.GetLastWriteTimeUtc(filePath), ChangeType = eventArgs.ChangeType, InstanceId = InstanceId }; _serializer.Serialize(statusWriter, status); statusWriter.WriteLine(); // invoke the job function TriggeredFunctionData input = new TriggeredFunctionData { // TODO: set this properly ParentId = null, TriggerValue = eventArgs }; FunctionResult result = await _executor.TryExecuteAsync(input, cancellationToken); if (result.Succeeded) { // write a status entry indicating processing is complete status.State = ProcessingState.Processed; status.Timestamp = DateTime.UtcNow; _serializer.Serialize(statusWriter, status); statusWriter.WriteLine(); return(true); } else { // If the function failed, we leave the in progress status // file as is (it will show "Processing"). The file will be // reprocessed later on a clean-up pass. statusWriter.Close(); cancellationToken.ThrowIfCancellationRequested(); return(false); } } } catch { return(false); } }
public static async Task <WrappedFunctionResult> ExecuteFunctionInOrchestrationMiddleware( ITriggeredFunctionExecutor executor, TriggeredFunctionData triggerInput, DurableCommonContext context, CancellationToken cancellationToken) { #pragma warning disable CS0618 // InvokeHandler approved for use by this extension if (triggerInput.InvokeHandler == null) { throw new ArgumentException( $"{nameof(ExecuteFunctionInOrchestrationMiddleware)} should only be used when ${nameof(triggerInput)} has a value for ${nameof(TriggeredFunctionData.InvokeHandler)}"); } try { context.ExecutorCalledBack = false; FunctionResult result = await executor.TryExecuteAsync(triggerInput, cancellationToken); if (context.ExecutorCalledBack) { if (result.Succeeded) { return(WrappedFunctionResult.Success()); } if (cancellationToken.IsCancellationRequested) { return(WrappedFunctionResult.FunctionRuntimeFailure(result.Exception)); } return(WrappedFunctionResult.UserCodeFailure(result.Exception)); } else { // This can happen if the constructor for a non-static function fails. // We want to treat this case exactly as if the function itself is throwing the exception. // So we execute the middleware directly, instead of via the executor. try { var exception = result.Exception ?? new InvalidOperationException("The function failed to start executing."); await triggerInput.InvokeHandler(() => Task.FromException <object>(exception)); return(WrappedFunctionResult.Success()); } catch (Exception e) when(!cancellationToken.IsCancellationRequested) { return(WrappedFunctionResult.UserCodeFailure(e)); } } #pragma warning restore CS0618 } catch (Exception e) { return(WrappedFunctionResult.FunctionRuntimeFailure(e)); } }
private void OnCompleted() { var input = new TriggeredFunctionData { TriggerValue = new LiveProcessingStartedTriggerValue(null) }; _executor.TryExecuteAsync(input, _cancellationToken).Wait(); }
private void OnNotification(object sender, NpgsqlNotificationEventArgs e) { TriggeredFunctionData input = new TriggeredFunctionData { TriggerValue = e.AdditionalInformation }; _executor.TryExecuteAsync(input, CancellationToken.None).RunSynchronously(); }
public Task <FunctionResult> TryExecuteAsync(JObject data, CancellationToken cancellationToken) { TriggeredFunctionData input = new TriggeredFunctionData { TriggerValue = data }; return(_executor.TryExecuteAsync(input, cancellationToken)); }
private void ProcessEvent(IEnumerable <ResolvedEvent> events) { TriggeredFunctionData input = new TriggeredFunctionData { TriggerValue = new EventStoreTriggerValue(events) }; _executor.TryExecuteAsync(input, _cancellationToken).Wait(); }
Task FunctionsMessageHandler(Message message, object userContext) { var input = new TriggeredFunctionData { TriggerValue = message, }; return(this.executor.TryExecuteAsync(input, CancellationToken.None)); }
/// <summary> /// Invokes the job function. /// </summary> /// <param name="invocationTime">The time of the invocation, likely DateTime.Now.</param> /// <param name="isPastDue">True if the invocation is because the invocation is due to a past due timer.</param> /// <param name="runOnStartup">True if the invocation is because the timer is configured to run on startup.</param> internal async Task InvokeJobFunction(DateTime invocationTime, bool isPastDue = false, bool runOnStartup = false) { CancellationToken token = _cancellationTokenSource.Token; ScheduleStatus timerInfoStatus = null; if (ScheduleMonitor != null) { timerInfoStatus = ScheduleStatus; } TimerInfo timerInfo = new TimerInfo(_schedule, timerInfoStatus, isPastDue); TriggeredFunctionData input = new TriggeredFunctionData { TriggerValue = timerInfo }; try { FunctionResult result = await _executor.TryExecuteAsync(input, token); if (!result.Succeeded) { token.ThrowIfCancellationRequested(); } } catch { // We don't want any function errors to stop the execution // schedule. Errors will be logged to Dashboard already. } // If the trigger fired before it was officially scheduled (likely under 1 second due to clock skew), // adjust the invocation time forward for the purposes of calculating the next occurrence. // Without this, it's possible to set the 'Next' value to the same time twice in a row, // which results in duplicate triggers if the site restarts. DateTime adjustedInvocationTime = invocationTime; if (!isPastDue && !runOnStartup && ScheduleStatus?.Next > invocationTime) { adjustedInvocationTime = ScheduleStatus.Next; } // Create the Last value with the adjustedInvocationTime; otherwise, the listener will // consider this a schedule change when the host next starts. ScheduleStatus = new ScheduleStatus { Last = adjustedInvocationTime, Next = _schedule.GetNextOccurrence(adjustedInvocationTime), LastUpdated = adjustedInvocationTime }; if (ScheduleMonitor != null) { await ScheduleMonitor.UpdateStatusAsync(_timerName, ScheduleStatus); _logger.LogDebug($"Function '{_timerName}' updated status: Last='{ScheduleStatus.Last.ToString("o")}', Next='{ScheduleStatus.Next.ToString("o")}', LastUpdated='{ScheduleStatus.LastUpdated.ToString("o")}'"); } }
private async Task ConnectionOnOnMessageReceived(SlackMessage message) { var triggerData = new TriggeredFunctionData { TriggerValue = message }; await Executor.TryExecuteAsync(triggerData, CancellationToken.None); }
private async void OnMessageReceived(object sender, MqttApplicationMessageReceivedEventArgs e) { var triggerData = new TriggeredFunctionData { TriggerValue = e.ApplicationMessage }; await Executor.TryExecuteAsync(triggerData, CancellationToken.None); }
public static async Task <WrappedFunctionResult> ExecuteFunctionInOrchestrationMiddleware( ITriggeredFunctionExecutor executor, TriggeredFunctionData triggerInput, CancellationToken cancellationToken) { #pragma warning disable CS0618 // InvokeHandler approved for use by this extension if (triggerInput.InvokeHandler == null) { throw new ArgumentException( $"{nameof(ExecuteFunctionInOrchestrationMiddleware)} should only be used when ${nameof(triggerInput)} has a value for ${nameof(TriggeredFunctionData.InvokeHandler)}"); } try { bool executedUserCode = false; var triggeredFunctionData = new TriggeredFunctionData() { TriggerValue = triggerInput.TriggerValue, ParentId = triggerInput.ParentId, InvokeHandler = userCodeHandler => { executedUserCode = true; return(triggerInput.InvokeHandler(userCodeHandler)); }, #if !FUNCTIONS_V1 TriggerDetails = triggerInput.TriggerDetails, #endif }; #pragma warning restore CS0618 FunctionResult result = await executor.TryExecuteAsync(triggerInput, cancellationToken); if (result.Succeeded) { return(WrappedFunctionResult.Success()); } if (cancellationToken.IsCancellationRequested) { return(WrappedFunctionResult.FunctionRuntimeFailure(result.Exception)); } if (!executedUserCode) { WrappedFunctionResult.UserCodeFailure(new InvalidOperationException( "The function failed to start executing. " + "For .NET functions, this can happen if an unhandled exception is thrown in the function's class constructor.")); } return(WrappedFunctionResult.UserCodeFailure(result.Exception)); } catch (Exception e) { return(WrappedFunctionResult.FunctionRuntimeFailure(e)); } }
private void OnMessageArrived(RedisChannel channel, RedisValue value) { var triggerData = new TriggeredFunctionData { TriggerValue = value.ToString() }; var task = _executor.TryExecuteAsync(triggerData, CancellationToken.None); task.Wait(); }
public override async Task <string> RunAsync(TaskContext context, string rawInput) { string instanceId = context.OrchestrationInstance.InstanceId; var inputContext = new DurableActivityContext(instanceId, rawInput); // TODO: Wire up the parent ID to improve dashboard logging. Guid?parentId = null; var triggerInput = new TriggeredFunctionData { ParentId = parentId, TriggerValue = inputContext }; this.config.TraceHelper.FunctionStarting( this.config.HubName, this.activityName, this.activityVersion, instanceId, this.config.GetIntputOutputTrace(rawInput), isOrchestrator: false, isReplay: false); FunctionResult result = await this.executor.TryExecuteAsync(triggerInput, CancellationToken.None); if (!result.Succeeded) { this.config.TraceHelper.FunctionFailed( this.config.HubName, this.activityName, this.activityVersion, instanceId, result.Exception?.ToString() ?? string.Empty, isOrchestrator: false, isReplay: false); if (result.Exception != null) { // Preserve the original exception context so that the durable task // framework can report useful failure information. ExceptionDispatchInfo.Capture(result.Exception).Throw(); } } string serializedOutput = inputContext.GetSerializedOutput(); this.config.TraceHelper.FunctionCompleted( config.HubName, this.activityName, this.activityVersion, instanceId, this.config.GetIntputOutputTrace(serializedOutput), continuedAsNew: false, isOrchestrator: false, isReplay: false); return(serializedOutput); }
protected override async Task ReaderAsync(ChannelReader <IKafkaEventData[]> reader, CancellationToken cancellationToken, ILogger logger) { var pendingTasks = new List <Task <FunctionResult> >(); while (!cancellationToken.IsCancellationRequested && await reader.WaitToReadAsync(cancellationToken)) { while (!cancellationToken.IsCancellationRequested && reader.TryRead(out var itemsToExecute)) { try { // Execute multiple topic in parallel. // Order in a partition must be followed. var partitionOffsets = new Dictionary <int, long>(); var itemsByPartition = itemsToExecute.GroupBy(x => x.Partition); var i = 0; do { pendingTasks.Clear(); foreach (var partition in itemsByPartition) { var kafkaEventData = partition.ElementAtOrDefault(i); if (kafkaEventData != null) { var triggerInput = KafkaTriggerInput.New(kafkaEventData); var triggerData = new TriggeredFunctionData { TriggerValue = triggerInput, }; partitionOffsets[partition.Key] = kafkaEventData.Offset + 1; // offset is inclusive when resuming pendingTasks.Add(this.ExecuteFunctionAsync(triggerData, cancellationToken)); } } i++; await Task.WhenAll(pendingTasks); } while (!cancellationToken.IsCancellationRequested && pendingTasks.Count > 0); if (!cancellationToken.IsCancellationRequested) { this.Commit(partitionOffsets.Select((kv) => new TopicPartitionOffset(new TopicPartition(itemsToExecute[0].Topic, kv.Key), kv.Value))); } } catch (Exception ex) { logger.LogError(ex, $"Error in executor reader"); } } } logger.LogInformation("Exiting reader {processName}", nameof(SingleItemFunctionExecutor <TKey, TValue>)); }
private void OnTimer(object sender, System.Timers.ElapsedEventArgs e) { // TODO: When you receive new events from your event source, // invoke the function executor TriggeredFunctionData input = new TriggeredFunctionData { TriggerValue = new SampleTriggerValue() }; _executor.TryExecuteAsync(input, CancellationToken.None).Wait(); }
private Task OnFileWatcher(IFileItem file, object obj) { ApiHubFile apiHubFile = new ApiHubFile(file); TriggeredFunctionData input = new TriggeredFunctionData { TriggerValue = apiHubFile }; return(_executor.TryExecuteAsync(input, CancellationToken.None)); }
public async Task <FunctionResult> ExecuteAsync(Message value, CancellationToken cancellationToken) { Guid?parentId = ServiceBusCausalityHelper.GetOwner(value); TriggeredFunctionData input = new TriggeredFunctionData { ParentId = parentId, TriggerValue = value }; return(await _innerExecutor.TryExecuteAsync(input, cancellationToken)); }