예제 #1
0
        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);
        }
예제 #2
0
        private static async Task <Tuple <object[], IDelayedException> > PrepareParametersAsync(IReadOnlyList <string> parameterNames,
                                                                                                IReadOnlyDictionary <string, IValueProvider> parameters)
        {
            object[]         reflectionParameters = new object[parameterNames.Count];
            List <Exception> bindingExceptions    = new List <Exception>();

            for (int index = 0; index < parameterNames.Count; index++)
            {
                string         name     = parameterNames[index];
                IValueProvider provider = parameters[name];

                BindingExceptionValueProvider exceptionProvider = provider as BindingExceptionValueProvider;

                if (exceptionProvider != null)
                {
                    bindingExceptions.Add(exceptionProvider.Exception);
                }

                reflectionParameters[index] = await parameters[name].GetValueAsync();
            }

            IDelayedException delayedBindingException = null;

            if (bindingExceptions.Count == 1)
            {
                delayedBindingException = new DelayedException(bindingExceptions[0]);
            }
            else if (bindingExceptions.Count > 1)
            {
                delayedBindingException = new DelayedException(new AggregateException(bindingExceptions));
            }

            return(new Tuple <object[], IDelayedException>(reflectionParameters, delayedBindingException));
        }
        public async Task <bool> ExecuteAsync(BrokeredMessage value, CancellationToken cancellationToken)
        {
            Guid?parentId = ServiceBusCausalityHelper.GetOwner(value);
            IFunctionInstance instance  = _instanceFactory.Create(value, parentId);
            IDelayedException exception = await _innerExecutor.TryExecuteAsync(instance, cancellationToken);

            return(exception == null);
        }
        private static IFunctionExecutor CreateStubInnerExecutor(IDelayedException result)
        {
            Mock <IFunctionExecutor> mock = new Mock <IFunctionExecutor>(MockBehavior.Strict);

            mock.Setup(e => e.TryExecuteAsync(It.IsAny <IFunctionInstance>(), It.IsAny <CancellationToken>()))
            .Returns(Task.FromResult(result));
            return(mock.Object);
        }
예제 #5
0
        public async Task <bool> ExecuteAsync(IStorageQueueMessage value, CancellationToken cancellationToken)
        {
            Guid?parentId = QueueCausalityManager.GetOwner(value);
            IFunctionInstance instance  = _instanceFactory.Create(value, parentId);
            IDelayedException exception = await _innerExecutor.TryExecuteAsync(instance, cancellationToken);

            return(exception == null);
        }
예제 #6
0
        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);
        }
예제 #7
0
        private async Task CallAsyncCore(MethodInfo method, IDictionary <string, object> arguments,
                                         CancellationToken cancellationToken)
        {
            await EnsureHostStartedAsync(cancellationToken);

            IFunctionDefinition function = ResolveFunctionDefinition(method, _context.FunctionLookup);
            IFunctionInstance   instance = CreateFunctionInstance(function, arguments);

            IDelayedException exception = await _context.Executor.TryExecuteAsync(instance, cancellationToken);

            if (exception != null)
            {
                exception.Throw();
            }
        }
예제 #8
0
        private async Task CallAsyncCore(IFunctionDefinition function, object functionKey, IDictionary <string, object> arguments, CancellationToken cancellationToken)
        {
            Validate(function, functionKey);

            IFunctionInstance instance = CreateFunctionInstance(function, arguments);

            IDelayedException exception = null;

            exception = await _context.Executor.TryExecuteAsync(instance, cancellationToken);

            if (exception != null)
            {
                exception.Throw();
            }
        }
예제 #9
0
        /// <summary>Calls a job method.</summary>
        /// <param name="name">The name of the function to call.</param>
        /// <param name="arguments">The argument names and values to bind to parameters in the job method. In addition to parameter values, these may also include binding data values. </param>
        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
        /// <returns>A <see cref="Task"/> that will call the job method.</returns>
        public async Task CallAsync(string name, IDictionary <string, object> arguments = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (name == null)
            {
                throw new ArgumentNullException(nameof(name));
            }

            ThrowIfDisposed();

            await EnsureHostInitializedAsync(cancellationToken);

            IFunctionDefinition function = _context.FunctionLookup.LookupByName(name);

            Validate(function, name);
            IFunctionInstance instance = CreateFunctionInstance(function, arguments);

            IDelayedException exception = await _context.Executor.TryExecuteAsync(instance, cancellationToken);

            if (exception != null)
            {
                exception.Throw();
            }
        }
        private static object[] PrepareParameters(IReadOnlyList <string> parameterNames,
                                                  IReadOnlyDictionary <string, IValueProvider> parameters, out IDelayedException delayedBindingException)
        {
            object[]         reflectionParameters = new object[parameterNames.Count];
            List <Exception> bindingExceptions    = new List <Exception>();

            for (int index = 0; index < parameterNames.Count; index++)
            {
                string         name     = parameterNames[index];
                IValueProvider provider = parameters[name];

                BindingExceptionValueProvider exceptionProvider = provider as BindingExceptionValueProvider;

                if (exceptionProvider != null)
                {
                    bindingExceptions.Add(exceptionProvider.Exception);
                }

                reflectionParameters[index] = parameters[name].GetValue();
            }

            if (bindingExceptions.Count == 0)
            {
                delayedBindingException = null;
            }
            else if (bindingExceptions.Count == 1)
            {
                delayedBindingException = new DelayedException(bindingExceptions[0]);
            }
            else
            {
                delayedBindingException = new DelayedException(new AggregateException(bindingExceptions));
            }

            return(reflectionParameters);
        }
 private static IFunctionExecutor CreateStubInnerExecutor(IDelayedException result)
 {
     Mock<IFunctionExecutor> mock = new Mock<IFunctionExecutor>(MockBehavior.Strict);
     mock.Setup(e => e.TryExecuteAsync(It.IsAny<IFunctionInstance>(), It.IsAny<CancellationToken>()))
         .Returns(Task.FromResult(result));
     return mock.Object;
 }
예제 #12
0
        internal static async Task ExecuteWithWatchersAsync(IFunctionInstance instance,
                                                            IReadOnlyDictionary <string, IValueProvider> parameters,
                                                            TraceWriter traceWriter,
                                                            CancellationTokenSource functionCancellationTokenSource)
        {
            IFunctionInvoker       invoker        = instance.Invoker;
            IReadOnlyList <string> parameterNames = invoker.ParameterNames;

            Tuple <object[], IDelayedException> preparedParameters = await PrepareParametersAsync(parameterNames, parameters);

            object[]          invokeParameters        = preparedParameters.Item1;
            IDelayedException delayedBindingException = preparedParameters.Item2;

            if (delayedBindingException != null)
            {
                // This is done inside a watcher context so that each binding error is publish next to the binding in
                // the parameter status log.
                delayedBindingException.Throw();
            }

            // if the function is a Singleton, aquire the lock
            SingletonLock singleton = await GetSingletonLockAsync(parameters);

            if (singleton != null)
            {
                await singleton.AcquireAsync(functionCancellationTokenSource.Token);
            }

            // Create a source specifically for timeouts
            using (CancellationTokenSource timeoutTokenSource = new CancellationTokenSource())
            {
                MethodInfo       method           = instance.FunctionDescriptor.Method;
                TimeoutAttribute timeoutAttribute = TypeUtility.GetHierarchicalAttributeOrNull <TimeoutAttribute>(method);
                bool             throwOnTimeout   = timeoutAttribute == null ? false : timeoutAttribute.ThrowOnTimeout;
                var      timer         = StartFunctionTimeout(instance, timeoutAttribute, timeoutTokenSource, traceWriter);
                TimeSpan timerInterval = timer == null ? TimeSpan.MinValue : TimeSpan.FromMilliseconds(timer.Interval);
                try
                {
                    await InvokeAsync(invoker, invokeParameters, timeoutTokenSource, functionCancellationTokenSource,
                                      throwOnTimeout, timerInterval, instance);
                }
                finally
                {
                    if (timer != null)
                    {
                        timer.Stop();
                        timer.Dispose();
                    }
                }
            }

            // Process any out parameters and persist any pending values.
            // Ensure IValueBinder.SetValue is called in BindStepOrder. This ordering is particularly important for
            // ensuring queue outputs occur last. That way, all other function side-effects are guaranteed to have
            // occurred by the time messages are enqueued.
            string[] parameterNamesInBindOrder = SortParameterNamesInStepOrder(parameters);
            foreach (string name in parameterNamesInBindOrder)
            {
                IValueProvider provider = parameters[name];
                IValueBinder   binder   = provider as IValueBinder;

                if (binder != null)
                {
                    object argument = invokeParameters[GetParameterIndex(parameterNames, name)];

                    try
                    {
                        // This could do complex things that may fail. Catch the exception.
                        await binder.SetValueAsync(argument, functionCancellationTokenSource.Token);
                    }
                    catch (OperationCanceledException)
                    {
                        throw;
                    }
                    catch (Exception exception)
                    {
                        string message = String.Format(CultureInfo.InvariantCulture,
                                                       "Error while handling parameter {0} after function returned:", name);
                        throw new InvalidOperationException(message, exception);
                    }
                }
            }

            if (singleton != null)
            {
                await singleton.ReleaseAsync(functionCancellationTokenSource.Token);
            }
        }
        public async Task <bool> ExecuteAsync(IStorageQueueMessage value, CancellationToken cancellationToken)
        {
            BlobTriggerMessage message = JsonConvert.DeserializeObject <BlobTriggerMessage>(value.AsString,
                                                                                            JsonSerialization.Settings);

            if (message == null)
            {
                throw new InvalidOperationException("Invalid blob trigger message.");
            }

            string functionId = message.FunctionId;

            if (functionId == null)
            {
                throw new InvalidOperationException("Invalid function ID.");
            }

            // Ensure that the function ID is still valid. Otherwise, ignore this message.
            ITriggeredFunctionInstanceFactory <IStorageBlob> instanceFactory;

            if (!_registrations.TryGetValue(functionId, out instanceFactory))
            {
                return(true);
            }

            IStorageBlobContainer container = _client.GetContainerReference(message.ContainerName);
            string blobName = message.BlobName;

            IStorageBlob blob;

            switch (message.BlobType)
            {
            case StorageBlobType.PageBlob:
                blob = container.GetPageBlobReference(blobName);
                break;

            case StorageBlobType.BlockBlob:
            default:
                blob = container.GetBlockBlobReference(blobName);
                break;
            }

            // Ensure the blob still exists with the same ETag.
            string possibleETag = await _eTagReader.GetETagAsync(blob, cancellationToken);

            if (possibleETag == null)
            {
                // If the blob no longer exists, just ignore this message.
                return(true);
            }

            // If the blob still exists but the ETag is different, delete the message but do a fast path notification.
            if (!String.Equals(message.ETag, possibleETag, StringComparison.Ordinal))
            {
                _blobWrittenWatcher.Notify(blob);
                return(true);
            }

            //// If the blob still exists and its ETag is still valid, execute.
            //// Note: it's possible the blob could change/be deleted between now and when the function executes.
            Guid?parentId = await _causalityReader.GetWriterAsync(blob, cancellationToken);

            IFunctionInstance instance  = instanceFactory.Create(blob, parentId);
            IDelayedException exception = await _innerExecutor.TryExecuteAsync(instance, cancellationToken);

            return(exception == null);
        }