public async Task <FunctionResult> TryExecuteAsync(TriggeredFunctionData input, CancellationToken cancellationToken) { var context = new FunctionInstanceFactoryContext <TTriggerValue>() { TriggerValue = (TTriggerValue)input.TriggerValue, ParentId = input.ParentId, TriggerDetails = input.TriggerDetails }; if (input.InvokeHandler != null) { context.InvokeHandler = async next => { await input.InvokeHandler(next); // NOTE: The InvokeHandler code path currently does not support flowing the return // value back to the trigger. return(null); }; } IFunctionInstance instance = _instanceFactory.Create(context); IDelayedException exception = await _executor.TryExecuteAsync(instance, cancellationToken); FunctionResult result = exception != null ? new FunctionResult(exception.Exception) : new FunctionResult(true); return(result); }
public async Task<FunctionResult> ExecuteAsync(BrokeredMessage value, CancellationToken cancellationToken) { Guid? parentId = ServiceBusCausalityHelper.GetOwner(value); TriggeredFunctionData input = new TriggeredFunctionData { ParentId = parentId, TriggerValue = value }; return await _innerExecutor.TryExecuteAsync(input, cancellationToken); }
public async Task <FunctionResult> TryExecuteAsync(TriggeredFunctionData input, CancellationToken cancellationToken) { IFunctionInstance instance = _instanceFactory.Create((TTriggerValue)input.TriggerValue, input.ParentId); IDelayedException exception = await _executor.TryExecuteAsync(instance, cancellationToken); FunctionResult result = exception != null ? new FunctionResult(exception.Exception) : new FunctionResult(true); return(result); }
internal async Task ProcessMessageAsync(string message, CancellationToken cancellationToken) { if (!await _redisProcessor.BeginMessageArrivedAsync(message, cancellationToken)) { return; } TriggeredFunctionData input = new TriggeredFunctionData { TriggerValue = message }; FunctionResult result = await _triggerExecutor.TryExecuteAsync(input, cancellationToken); await _redisProcessor.EndMessageArrivedAsync(message, result, cancellationToken); }
private void CreateTestListener(string expression, bool useMonitor = true) { _attribute = new TimerTriggerAttribute(expression); _attribute.UseMonitor = useMonitor; _config = new TimersConfiguration(); _mockScheduleMonitor = new Mock<ScheduleMonitor>(MockBehavior.Strict); _config.ScheduleMonitor = _mockScheduleMonitor.Object; _mockTriggerExecutor = new Mock<ITriggeredFunctionExecutor>(MockBehavior.Strict); FunctionResult result = new FunctionResult(true); _mockTriggerExecutor.Setup(p => p.TryExecuteAsync(It.IsAny<TriggeredFunctionData>(), It.IsAny<CancellationToken>())) .Callback<TriggeredFunctionData, CancellationToken>((mockFunctionData, mockToken) => { _triggeredFunctionData = mockFunctionData; }) .Returns(Task.FromResult(result)); _listener = new TimerListener(_attribute, _testTimerName, _config, _mockTriggerExecutor.Object, new TestTraceWriter()); }
internal static TraceMonitor CreateTraceMonitor(ParameterInfo parameter, ITriggeredFunctionExecutor executor) { ErrorTriggerAttribute attribute = parameter.GetCustomAttribute<ErrorTriggerAttribute>(inherit: false); // Determine whether this is a method level filter, and if so, create the filter Func<TraceEvent, bool> methodFilter = null; MethodInfo method = (MethodInfo)parameter.Member; string functionLevelMessage = null; if (method.Name.EndsWith(ErrorHandlerSuffix, StringComparison.OrdinalIgnoreCase)) { string sourceMethodName = method.Name.Substring(0, method.Name.Length - ErrorHandlerSuffix.Length); MethodInfo sourceMethod = method.DeclaringType.GetMethod(sourceMethodName); if (sourceMethod != null) { string sourceMethodFullName = string.Format("{0}.{1}", method.DeclaringType.FullName, sourceMethod.Name); methodFilter = p => { FunctionInvocationException functionException = p.Exception as FunctionInvocationException; return p.Level == System.Diagnostics.TraceLevel.Error && functionException != null && string.Compare(functionException.MethodName, sourceMethodFullName, StringComparison.OrdinalIgnoreCase) == 0; }; string sourceMethodShortName = string.Format("{0}.{1}", method.DeclaringType.Name, sourceMethod.Name); functionLevelMessage = string.Format("Function '{0}' failed.", sourceMethodShortName); } } string errorHandlerFullName = string.Format("{0}.{1}", method.DeclaringType.FullName, method.Name); ErrorHandlers.Add(errorHandlerFullName); // Create the TraceFilter instance TraceFilter traceFilter = null; if (attribute.FilterType != null) { if (methodFilter != null) { TraceFilter innerTraceFilter = (TraceFilter)Activator.CreateInstance(attribute.FilterType); traceFilter = new CompositeTraceFilter(innerTraceFilter, methodFilter, attribute.Message ?? functionLevelMessage); } else { traceFilter = (TraceFilter)Activator.CreateInstance(attribute.FilterType); } } else if (!string.IsNullOrEmpty(attribute.Window)) { TimeSpan window = TimeSpan.Parse(attribute.Window); traceFilter = new SlidingWindowTraceFilter(window, attribute.Threshold, methodFilter, attribute.Message); } else { traceFilter = TraceFilter.Create(methodFilter, attribute.Message ?? functionLevelMessage); } TraceMonitor traceMonitor = new TraceMonitor().Filter(traceFilter); // Apply any additional monitor options if (!string.IsNullOrEmpty(attribute.Throttle)) { TimeSpan throttle = TimeSpan.Parse(attribute.Throttle); traceMonitor.Throttle(throttle); } // Subscribe the error handler function to the error stream traceMonitor.Subscribe(p => { TriggeredFunctionData triggerData = new TriggeredFunctionData { TriggerValue = p }; Task<FunctionResult> task = executor.TryExecuteAsync(triggerData, CancellationToken.None); task.Wait(); }); return traceMonitor; }
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(); }
/// <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; } }
/// <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 { StatusFileEntry status = null; string filePath = eventArgs.FullPath; using (StreamWriter statusWriter = AcquireStatusFileLock(filePath, eventArgs.ChangeType, out status)) { if (statusWriter == null) { return false; } // We've acquired the lock. The current status might be either Failed // or Processing (if processing failed before we were unable to update // the file status to Failed) int processCount = 0; if (status != null) { processCount = status.ProcessCount; } while (processCount++ < MaxProcessCount) { FunctionResult result = null; if (result != null) { TimeSpan delay = GetRetryInterval(result, processCount); await Task.Delay(delay); } // write an entry indicating the file is being processed status = new StatusFileEntry { State = ProcessingState.Processing, Timestamp = DateTime.Now, LastWrite = File.GetLastWriteTimeUtc(filePath), ChangeType = eventArgs.ChangeType, InstanceId = InstanceId, ProcessCount = processCount }; _serializer.Serialize(statusWriter, status); statusWriter.WriteLine(); // invoke the job function TriggeredFunctionData input = new TriggeredFunctionData { TriggerValue = eventArgs }; result = await _executor.TryExecuteAsync(input, cancellationToken); // write a status entry indicating the state of processing status.State = result.Succeeded ? ProcessingState.Processed : ProcessingState.Failed; status.Timestamp = DateTime.Now; _serializer.Serialize(statusWriter, status); statusWriter.WriteLine(); if (result.Succeeded) { return true; } } return false; } } catch { return 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); } }
private async Task<HttpResponseMessage> ProcessRequest(HttpRequestMessage request) { // First check if we have a WebHook function registered for // this route string routeKey = request.RequestUri.LocalPath.ToLowerInvariant(); ITriggeredFunctionExecutor executor = null; if (!_functions.TryGetValue(routeKey, out executor)) { // If no WebHook function is registered, we'll see if there is a job function // that matches based on name, and if so invoke it directly MethodInfo methodInfo = null; if (TryGetMethodInfo(routeKey, out methodInfo)) { // Read the method arguments from the request body // and invoke the function string body = await request.Content.ReadAsStringAsync(); IDictionary<string, JToken> parsed = JObject.Parse(body); IDictionary<string, object> args = parsed.ToDictionary(p => p.Key, q => (object)q.Value.ToString()); await _host.CallAsync(methodInfo, args); return new HttpResponseMessage(HttpStatusCode.OK); } return new HttpResponseMessage(HttpStatusCode.NotFound); } TriggeredFunctionData data = new TriggeredFunctionData { TriggerValue = request }; FunctionResult result = await executor.TryExecuteAsync(data, CancellationToken.None); HttpStatusCode statusCode = result.Succeeded ? HttpStatusCode.OK : HttpStatusCode.InternalServerError; return new HttpResponseMessage(statusCode); }
private async Task<HttpResponseMessage> ProcessRequest(HttpRequestMessage request) { // First check if we have a WebHook function registered for this route string routeKey = request.RequestUri.LocalPath.ToLowerInvariant(); ITriggeredFunctionExecutor executor = null; HttpResponseMessage response = null; if (!_functions.TryGetValue(routeKey, out executor)) { if (request.Method != HttpMethod.Post) { return new HttpResponseMessage(HttpStatusCode.MethodNotAllowed); } // No WebHook function is registered for this route // See see if there is a job function that matches based // on name, and if so invoke it directly response = await TryInvokeNonWebHook(routeKey, request); } else { // Define a function to invoke the job function that we can reuse below Func<HttpRequestMessage, Task<HttpResponseMessage>> invokeJobFunction = async (req) => { TriggeredFunctionData data = new TriggeredFunctionData { TriggerValue = req }; FunctionResult result = await executor.TryExecuteAsync(data, CancellationToken.None); object value = null; if (request.Properties.TryGetValue(WebHookTriggerBinding.WebHookContextRequestKey, out value)) { // If this is a WebHookContext binding, see if a custom response has been set. // If so, we'll return that. WebHookContext context = (WebHookContext)value; if (context.Response != null) { response = context.Response; response.RequestMessage = request; } } if (response != null) { return response; } else { return new HttpResponseMessage(result.Succeeded ? HttpStatusCode.OK : HttpStatusCode.InternalServerError); } }; // See if there is a WebHookReceiver registered for this request // Note: receivers will do their own HttpMethod validation (e.g. some // support HEAD/GET/etc. response = await _webHookReceiverManager.TryHandle(request, invokeJobFunction); if (response == null) { if (request.Method != HttpMethod.Post) { return new HttpResponseMessage(HttpStatusCode.MethodNotAllowed); } // No WebHook receivers have been registered for this request, so dispatch // it directly. response = await invokeJobFunction(request); } } return response; }