Beispiel #1
0
        private static MethodInfo GenerateMethod(BindingMetadata trigger)
        {
            string           rootPath = Path.Combine(Environment.CurrentDirectory, @"TestScripts\Node");
            FunctionMetadata metadata = new FunctionMetadata();

            metadata.Name       = "Test";
            metadata.ScriptFile = Path.Combine(rootPath, @"Common\test.js");
            metadata.Bindings.Add(trigger);

            List <FunctionMetadata> metadatas = new List <FunctionMetadata>();

            metadatas.Add(metadata);

            ScriptHostConfiguration scriptConfig = new ScriptHostConfiguration()
            {
                RootScriptPath = rootPath
            };
            ScriptHost host = ScriptHost.Create(scriptConfig);

            FunctionDescriptorProvider[] descriptorProviders = new FunctionDescriptorProvider[]
            {
                new NodeFunctionDescriptorProvider(host, scriptConfig)
            };

            var  functionDescriptors = host.ReadFunctions(metadatas, descriptorProviders);
            Type t = FunctionGenerator.Generate("TestScriptHost", "Host.Functions", functionDescriptors);

            MethodInfo method = t.GetMethods(BindingFlags.Public | BindingFlags.Static).First();

            return(method);
        }
        /// <summary>
        /// Generate function wrappers from descriptors.
        /// </summary>
        private void GenerateFunctions()
        {
            // generate Type level attributes
            var typeAttributes = CreateTypeAttributes(ScriptOptions);

            string generatingMsg = string.Format(CultureInfo.InvariantCulture, "Generating {0} job function(s)", Functions.Count);

            _logger?.LogInformation(generatingMsg);

            // generate the Type wrapper
            string typeName            = string.Format(CultureInfo.InvariantCulture, "{0}.{1}", GeneratedTypeNamespace, GeneratedTypeName);
            Type   functionWrapperType = FunctionGenerator.Generate(HostAssemblyName, typeName, typeAttributes, Functions);

            // configure the Type locator
            var types = new HashSet <Type>
            {
                functionWrapperType
            };

            foreach (var descriptor in Functions)
            {
                if (descriptor.Metadata.Properties.TryGetValue(ScriptConstants.FunctionMetadataDirectTypeKey, out Type type))
                {
                    types.Add(type);
                }
            }

            _typeLocator.SetTypes(types);
        }
        public async Task Generate_EndToEnd()
        {
            // construct our TimerTrigger attribute ([TimerTrigger("00:00:02", RunOnStartup = true)])
            Collection <ParameterDescriptor> parameters = new Collection <ParameterDescriptor>();
            ParameterDescriptor    parameter            = new ParameterDescriptor("timerInfo", typeof(TimerInfo));
            ConstructorInfo        ctorInfo             = typeof(TimerTriggerAttribute).GetConstructor(new Type[] { typeof(string) });
            PropertyInfo           runOnStartupProperty = typeof(TimerTriggerAttribute).GetProperty("RunOnStartup");
            CustomAttributeBuilder attributeBuilder     = new CustomAttributeBuilder(
                ctorInfo,
                new object[] { "00:00:02" },
                new PropertyInfo[] { runOnStartupProperty },
                new object[] { true });

            parameter.CustomAttributes.Add(attributeBuilder);
            parameters.Add(parameter);

            // create the FunctionDefinition
            FunctionMetadata   metadata = new FunctionMetadata();
            TestInvoker        invoker  = new TestInvoker();
            FunctionDescriptor function = new FunctionDescriptor("TimerFunction", invoker, metadata, parameters, null, null, null);
            Collection <FunctionDescriptor> functions = new Collection <FunctionDescriptor>();

            functions.Add(function);

            // Get the Type Attributes (in this case, a TimeoutAttribute)
            ScriptHostConfiguration scriptConfig = new ScriptHostConfiguration();

            scriptConfig.FunctionTimeout = TimeSpan.FromMinutes(5);
            Collection <CustomAttributeBuilder> typeAttributes = new Collection <CustomAttributeBuilder>();

            // generate the Type
            Type functionType = FunctionGenerator.Generate("TestScriptHost", "TestFunctions", typeAttributes, functions);

            // verify the generated function
            MethodInfo            method           = functionType.GetMethod("TimerFunction");
            ParameterInfo         triggerParameter = method.GetParameters()[0];
            TimerTriggerAttribute triggerAttribute = triggerParameter.GetCustomAttribute <TimerTriggerAttribute>();

            Assert.NotNull(triggerAttribute);

            // start the JobHost which will start running the timer function
            JobHostConfiguration config = new JobHostConfiguration()
            {
                TypeLocator   = new TypeLocator(functionType),
                LoggerFactory = new LoggerFactory()
            };

            config.UseTimers();
            JobHost host = new JobHost(config);

            await host.StartAsync();

            await Task.Delay(3000);

            await host.StopAsync();

            // verify our custom invoker was called
            Assert.True(invoker.InvokeCount >= 2);
        }
        private void btnDFT_Click(object sender, EventArgs e)
        {
            Clear();
            DrawGraph(functionChart, _functionGenerator.Generate(_from, _to, _dt));
            var result = _dftProcessor.Transform(_functionGenerator.Generate(_from, _to, _dt), false);
            var t      = result.Select((_, i) => (double)1 / (i / _dt / result.Length)).ToArray();

            DrawGraph(fourierChartA,
                      result.Select(x => Math.Sqrt(Math.Pow(x.Real, 2) + Math.Pow(x.Imaginary, 2)) / result.Length).ToArray(),
                      t);

            DrawGraph(fourierChartP, result.Select(x => Math.Atan2(x.Imaginary, x.Real)).ToArray(), t);
            fourierChartA.AxisChange();
            fourierChartP.AxisChange();
            fourierChartP.Invalidate();
            fourierChartA.Invalidate();
        }
        public void Generate_WithMultipleOutParameters()
        {
            string functionName = "FunctionWithOuts";
            Collection <ParameterDescriptor> parameters = new Collection <ParameterDescriptor>();

            parameters.Add(new ParameterDescriptor("param1", typeof(string)));
            parameters.Add(new ParameterDescriptor("param2", typeof(string).MakeByRefType())
            {
                Attributes = ParameterAttributes.Out
            });
            parameters.Add(new ParameterDescriptor("param3", typeof(string).MakeByRefType())
            {
                Attributes = ParameterAttributes.Out
            });

            FunctionMetadata   metadata = new FunctionMetadata();
            TestInvoker        invoker  = new TestInvoker();
            FunctionDescriptor function = new FunctionDescriptor(functionName, invoker, metadata, parameters);
            Collection <FunctionDescriptor> functions = new Collection <FunctionDescriptor>();

            functions.Add(function);

            // Make sure we don't generate a TimeoutAttribute if FunctionTimeout is null.
            ScriptHostConfiguration scriptConfig = new ScriptHostConfiguration();

            scriptConfig.FunctionTimeout = null;
            Collection <CustomAttributeBuilder> typeAttributes = ScriptHost.CreateTypeAttributes(scriptConfig);

            // generate the Type
            Type functionType = FunctionGenerator.Generate("TestScriptHost", "TestFunctions", typeAttributes, functions);

            // verify the generated function
            MethodInfo method = functionType.GetMethod(functionName);
            IEnumerable <Attribute> attributes = functionType.GetCustomAttributes();

            Assert.Empty(attributes);
            ParameterInfo[] functionParams = method.GetParameters();

            // Verify that we have the correct number of parameters
            Assert.Equal(parameters.Count, functionParams.Length);

            // Verify that out parameters were correctly generated
            Assert.True(functionParams[1].IsOut);
            Assert.True(functionParams[2].IsOut);

            // Verify that the method is invocable
            method.Invoke(null, new object[] { "test", null, null });

            // verify our custom invoker was called
            Assert.Equal(1, invoker.InvokeCount);
        }
        public async Task Generate_WithReturnValue(string userFuncName, Type generatedMethodReturnType, string expectedResult)
        {
            var userFunc = this.GetType().GetMethod(userFuncName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);

            string functionName = "FunctionWithStrReturn";
            Collection <ParameterDescriptor> parameters = new Collection <ParameterDescriptor>();

            var userRetType = userFunc.ReturnType;
            ParameterDescriptor returnParameter;

            if (DotNetFunctionDescriptorProvider.TryCreateReturnValueParameterDescriptor(userRetType, new FunctionBinding[0], out returnParameter))
            {
                parameters.Add(returnParameter);
            }

            FunctionMetadata metadata = new FunctionMetadata();
            var invoker = new RealInvoker(userFunc);
            FunctionDescriptor function = new FunctionDescriptor(functionName, invoker, metadata, parameters, null, null, null);
            Collection <FunctionDescriptor> functions = new Collection <FunctionDescriptor>();

            functions.Add(function);

            // generate the Type
            Type functionType = FunctionGenerator.Generate("TestScriptHost", "TestFunctions", null, functions);

            // verify the generated function
            MethodInfo method = functionType.GetMethod(functionName);
            IEnumerable <Attribute> attributes = functionType.GetCustomAttributes();

            Assert.Empty(attributes);
            ParameterInfo[] functionParams = method.GetParameters();

            // One input parameter
            Assert.Equal(0, functionParams.Length);

            // The final generated function is always Task
            Assert.Equal(generatedMethodReturnType, method.ReturnType);

            // Verify that the method is invocable
            var result = method.Invoke(null, new object[] { });

            Task <object> taskResult = Unwrap(result);
            var           realResult = await taskResult;

            Assert.Equal(expectedResult, realResult);
        }
        public void Generate_WithOutParams_CorrectlyUpdatesOutput()
        {
            string functionName = "FunctionWithOutValue";
            Collection <ParameterDescriptor> parameters = new Collection <ParameterDescriptor>();

            parameters.Add(new ParameterDescriptor("param1", typeof(string).MakeByRefType())
            {
                Attributes = ParameterAttributes.Out
            });

            FunctionMetadata metadata = new FunctionMetadata();

            object[]    invocationArguments = null;
            TestInvoker invoker             = new TestInvoker(args =>
            {
                invocationArguments    = args;
                invocationArguments[0] = "newvalue";
            });
            FunctionDescriptor function = new FunctionDescriptor(functionName, invoker, metadata, parameters);
            Collection <FunctionDescriptor> functions = new Collection <FunctionDescriptor>();

            functions.Add(function);

            // generate the Type
            Type functionType = FunctionGenerator.Generate("TestScriptHost", "TestFunctions", null, functions);

            // verify the generated function
            MethodInfo method = functionType.GetMethod(functionName);

            ParameterInfo[] functionParams = method.GetParameters();

            // Verify that we have the correct number of parameters
            Assert.Equal(parameters.Count, functionParams.Length);

            // Verify that the method is invocable
            DateTimeOffset input = DateTimeOffset.Now;

            method.Invoke(null, new object[] { null });

            // verify our custom invoker was called
            Assert.Equal(1, invoker.InvokeCount);

            Assert.NotNull(invocationArguments);
            Assert.Equal("newvalue", (string)invocationArguments[0]);
        }
        public void Generate_WithValueTypes_Succeeds()
        {
            string functionName = "FunctionWithValueTypes";
            Collection <ParameterDescriptor> parameters = new Collection <ParameterDescriptor>();

            parameters.Add(new ParameterDescriptor("param1", typeof(string)));
            parameters.Add(new ParameterDescriptor("param2", typeof(DateTimeOffset)));
            parameters.Add(new ParameterDescriptor("param3", typeof(int)));

            FunctionMetadata metadata = new FunctionMetadata();

            object[]           invocationArguments    = null;
            TestInvoker        invoker                = new TestInvoker(args => { invocationArguments = args; });
            FunctionDescriptor function               = new FunctionDescriptor(functionName, invoker, metadata, parameters);
            Collection <FunctionDescriptor> functions = new Collection <FunctionDescriptor>();

            functions.Add(function);

            // generate the Type
            Type functionType = FunctionGenerator.Generate("TestScriptHost", "TestFunctions", null, functions);

            // verify the generated function
            MethodInfo method = functionType.GetMethod(functionName);

            ParameterInfo[] functionParams = method.GetParameters();

            // Verify that we have the correct number of parameters
            Assert.Equal(parameters.Count, functionParams.Length);

            // Verify that the method is invocable
            DateTimeOffset input = DateTimeOffset.Now;

            method.Invoke(null, new object[] { "test", input, 44 });

            // verify our custom invoker was called
            Assert.Equal(1, invoker.InvokeCount);

            Assert.NotNull(invocationArguments);
            Assert.Equal(input, (DateTimeOffset)invocationArguments[1]);
            Assert.Equal(44, (int)invocationArguments[2]);
        }
        /// <summary>
        /// Generate function wrappers from descriptors.
        /// </summary>
        private void GenerateFunctions(IEnumerable <Type> directTypes)
        {
            // generate Type level attributes
            var typeAttributes = CreateTypeAttributes(ScriptOptions);

            string generatingMsg = string.Format(CultureInfo.InvariantCulture, "Generating {0} job function(s)", Functions.Count);

            _logger?.LogInformation(generatingMsg);

            // generate the Type wrapper
            string typeName            = string.Format(CultureInfo.InvariantCulture, "{0}.{1}", GeneratedTypeNamespace, GeneratedTypeName);
            Type   functionWrapperType = FunctionGenerator.Generate(HostAssemblyName, typeName, typeAttributes, Functions);

            // configure the Type locator
            var types = new List <Type>();

            types.Add(functionWrapperType);
            types.AddRange(directTypes);

            _typeLocator.SetTypes(types);
        }
Beispiel #10
0
        private static MethodInfo GenerateMethod(BindingMetadata trigger)
        {
            string           rootPath = Path.Combine(Environment.CurrentDirectory, @"TestScripts\Node");
            FunctionMetadata metadata = new FunctionMetadata();

            metadata.Name       = "Test";
            metadata.ScriptFile = Path.Combine(rootPath, @"Common\test.js");
            metadata.Bindings.Add(trigger);

            List <FunctionMetadata> functions = new List <FunctionMetadata>();

            functions.Add(metadata);

            var environment = new Mock <IScriptHostEnvironment>();

            ScriptHostConfiguration scriptConfig = new ScriptHostConfiguration()
            {
                RootScriptPath = rootPath
            };

            Collection <FunctionDescriptor> functionDescriptors = null;

            using (ScriptHost host = ScriptHost.Create(environment.Object, scriptConfig, SettingsManager))
            {
                FunctionDescriptorProvider[] descriptorProviders = new FunctionDescriptorProvider[]
                {
                    new NodeFunctionDescriptorProvider(host, scriptConfig)
                };

                functionDescriptors = host.GetFunctionDescriptors(functions, descriptorProviders);
            }

            Type t = FunctionGenerator.Generate("TestScriptHost", "Host.Functions", null, functionDescriptors);

            MethodInfo method = t.GetMethods(BindingFlags.Public | BindingFlags.Static).First();

            return(method);
        }
Beispiel #11
0
        protected virtual void Initialize()
        {
            List <FunctionDescriptorProvider> descriptionProviders = new List <FunctionDescriptorProvider>()
            {
                new ScriptFunctionDescriptorProvider(this, ScriptConfig),
                new NodeFunctionDescriptorProvider(this, ScriptConfig)
            };

            if (ScriptConfig.HostConfig.IsDevelopment)
            {
                ScriptConfig.HostConfig.UseDevelopmentSettings();
            }

            // read host.json and apply to JobHostConfiguration
            string hostConfigFilePath = Path.Combine(ScriptConfig.RootScriptPath, "host.json");

            _traceWriter.Verbose(string.Format("Reading host configuration file '{0}'", hostConfigFilePath));
            string  json       = File.ReadAllText(hostConfigFilePath);
            JObject hostConfig = JObject.Parse(json);

            ApplyConfiguration(hostConfig, ScriptConfig);

            // read all script functions and apply to JobHostConfiguration
            Collection <FunctionDescriptor> functions = ReadFunctions(ScriptConfig, descriptionProviders);
            string defaultNamespace = "Host";
            string typeName         = string.Format("{0}.{1}", defaultNamespace, "Functions");

            _traceWriter.Verbose(string.Format("Generating {0} job function(s)", functions.Count));
            Type        type  = FunctionGenerator.Generate(HostAssemblyName, typeName, functions);
            List <Type> types = new List <Type>();

            types.Add(type);

            ScriptConfig.HostConfig.TypeLocator  = new TypeLocator(types);
            ScriptConfig.HostConfig.NameResolver = new NameResolver();

            Functions = functions;
        }
Beispiel #12
0
        private static MethodInfo GenerateMethod(BindingMetadata trigger, ScriptHostInfo scriptHostInfo)
        {
            FunctionMetadata metadata = new FunctionMetadata();

            metadata.Name       = FunctionName;
            metadata.ScriptFile = Path.Combine(scriptHostInfo.RootPath, @"Common\test.ps1");
            metadata.Bindings.Add(trigger);
            metadata.ScriptType = ScriptType.PowerShell;

            List <FunctionMetadata> functions = new List <FunctionMetadata>();

            functions.Add(metadata);
            FunctionDescriptorProvider[] descriptorProviders = new FunctionDescriptorProvider[]
            {
                new PowerShellFunctionDescriptorProvider(scriptHostInfo.Host, scriptHostInfo.Configuration)
            };

            var  functionDescriptors = scriptHostInfo.Host.GetFunctionDescriptors(functions, descriptorProviders);
            Type t = FunctionGenerator.Generate("TestScriptHost", "Host.Functions", null, functionDescriptors);

            MethodInfo method = t.GetMethods(BindingFlags.Public | BindingFlags.Static).First();

            return(method);
        }
        protected virtual void Initialize()
        {
            // read host.json and apply to JobHostConfiguration
            string hostConfigFilePath = Path.Combine(ScriptConfig.RootScriptPath, ScriptConstants.HostMetadataFileName);

            // If it doesn't exist, create an empty JSON file
            if (!File.Exists(hostConfigFilePath))
            {
                File.WriteAllText(hostConfigFilePath, "{}");
            }

            if (ScriptConfig.HostConfig.IsDevelopment)
            {
                ScriptConfig.HostConfig.UseDevelopmentSettings();
            }
            else
            {
                // TEMP: Until https://github.com/Azure/azure-webjobs-sdk-script/issues/100 is addressed
                // we're using some presets that are a good middle ground
                ScriptConfig.HostConfig.Queues.MaxPollingInterval    = TimeSpan.FromSeconds(10);
                ScriptConfig.HostConfig.Singleton.ListenerLockPeriod = TimeSpan.FromSeconds(15);
            }

            string json = File.ReadAllText(hostConfigFilePath);

            JObject hostConfig;

            try
            {
                hostConfig = JObject.Parse(json);
            }
            catch (JsonException ex)
            {
                throw new FormatException(string.Format("Unable to parse {0} file.", ScriptConstants.HostMetadataFileName), ex);
            }

            ApplyConfiguration(hostConfig, ScriptConfig);

            // Set up a host level TraceMonitor that will receive notificaition
            // of ALL errors that occur. This allows us to inspect/log errors.
            var traceMonitor = new TraceMonitor()
                               .Filter(p => { return(true); })
                               .Subscribe(HandleHostError);

            ScriptConfig.HostConfig.Tracing.Tracers.Add(traceMonitor);

            TraceWriter = ScriptConfig.TraceWriter;
            TraceLevel hostTraceLevel = ScriptConfig.HostConfig.Tracing.ConsoleLevel;

            if (ScriptConfig.FileLoggingEnabled)
            {
                string      hostLogFilePath = Path.Combine(ScriptConfig.RootLogPath, "Host");
                TraceWriter fileTraceWriter = new FileTraceWriter(hostLogFilePath, hostTraceLevel);
                if (TraceWriter != null)
                {
                    // create a composite writer so our host logs are written to both
                    TraceWriter = new CompositeTraceWriter(new[] { TraceWriter, fileTraceWriter });
                }
                else
                {
                    TraceWriter = fileTraceWriter;
                }
            }

            if (TraceWriter != null)
            {
                ScriptConfig.HostConfig.Tracing.Tracers.Add(TraceWriter);
            }
            else
            {
                // if no TraceWriter has been configured, default it to Console
                TraceWriter = new ConsoleTraceWriter(hostTraceLevel);
            }

            var bindingProviders = LoadBindingProviders(ScriptConfig, hostConfig, TraceWriter);

            ScriptConfig.BindingProviders = bindingProviders;

            TraceWriter.Info(string.Format(CultureInfo.InvariantCulture, "Reading host configuration file '{0}'", hostConfigFilePath));

            if (ScriptConfig.FileWatchingEnabled)
            {
                _fileWatcher = new FileSystemWatcher(ScriptConfig.RootScriptPath)
                {
                    IncludeSubdirectories = true,
                    EnableRaisingEvents   = true
                };
                _fileWatcher.Changed += OnFileChanged;
                _fileWatcher.Created += OnFileChanged;
                _fileWatcher.Deleted += OnFileChanged;
                _fileWatcher.Renamed += OnFileChanged;
            }

            // If a file change should result in a restart, we debounce the event to
            // ensure that only a single restart is triggered within a specific time window.
            // This allows us to deal with a large set of file change events that might
            // result from a bulk copy/unzip operation. In such cases, we only want to
            // restart after ALL the operations are complete and there is a quiet period.
            _restart = (e) =>
            {
                TraceWriter.Info(string.Format(CultureInfo.InvariantCulture, "File change of type '{0}' detected for '{1}'", e.ChangeType, e.FullPath));
                TraceWriter.Info("Host configuration has changed. Signaling restart.");

                // signal host restart
                _restartEvent.Set();
            };
            _restart = _restart.Debounce(500);

            // take a snapshot so we can detect function additions/removals
            _directoryCountSnapshot = Directory.EnumerateDirectories(ScriptConfig.RootScriptPath).Count();

            IMetricsLogger metricsLogger = ScriptConfig.HostConfig.GetService <IMetricsLogger>();

            if (metricsLogger == null)
            {
                ScriptConfig.HostConfig.AddService <IMetricsLogger>(new MetricsLogger());
            }

            var storageString = AmbientConnectionStringProvider.Instance.GetConnectionString(ConnectionStringNames.Storage);

            if (storageString == null)
            {
                // Disable core storage
                ScriptConfig.HostConfig.StorageConnectionString = null;
            }
            else
            {
                // Create the lease manager that will keep handle the primary host blob lease acquisition and renewal
                // and subscribe for change notifications.
                _blobLeaseManager = BlobLeaseManager.Create(storageString, TimeSpan.FromSeconds(15), ScriptConfig.HostConfig.HostId, InstanceId, TraceWriter);
                _blobLeaseManager.HasLeaseChanged += BlobLeaseManagerHasLeaseChanged;
            }

            List <FunctionDescriptorProvider> descriptionProviders = new List <FunctionDescriptorProvider>()
            {
                new ScriptFunctionDescriptorProvider(this, ScriptConfig),
                new NodeFunctionDescriptorProvider(this, ScriptConfig),
                new DotNetFunctionDescriptorProvider(this, ScriptConfig),
                new PowerShellFunctionDescriptorProvider(this, ScriptConfig)
            };

            // read all script functions and apply to JobHostConfiguration
            Collection <FunctionDescriptor> functions = ReadFunctions(ScriptConfig, descriptionProviders);
            string defaultNamespace = "Host";
            string typeName         = string.Format(CultureInfo.InvariantCulture, "{0}.{1}", defaultNamespace, "Functions");

            TraceWriter.Info(string.Format(CultureInfo.InvariantCulture, "Generating {0} job function(s)", functions.Count));
            Type        type  = FunctionGenerator.Generate(HostAssemblyName, typeName, functions);
            List <Type> types = new List <Type>();

            types.Add(type);

            ScriptConfig.HostConfig.TypeLocator = new TypeLocator(types);

            // Allow BindingProviders to complete their initialization
            foreach (var bindingProvider in ScriptConfig.BindingProviders)
            {
                try
                {
                    bindingProvider.Initialize();
                }
                catch (Exception ex)
                {
                    // If we're unable to initialize a binding provider for any reason, log the error
                    // and continue
                    TraceWriter.Error(string.Format("Error initializing binding provider '{0}'", bindingProvider.GetType().FullName), ex);
                }
            }

            Functions = functions;

            if (ScriptConfig.FileLoggingEnabled)
            {
                PurgeOldLogDirectories();
            }
        }
        protected virtual void Initialize()
        {
            string hostLogPath = Path.Combine(ScriptConfig.RootLogPath, "Host");

            FileUtility.EnsureDirectoryExists(hostLogPath);
            string debugSentinelFileName = Path.Combine(hostLogPath, ScriptConstants.DebugSentinelFileName);

            this.LastDebugNotify = File.GetLastWriteTime(debugSentinelFileName);

            IMetricsLogger metricsLogger = ScriptConfig.HostConfig.GetService <IMetricsLogger>();

            if (metricsLogger == null)
            {
                metricsLogger = new MetricsLogger();
                ScriptConfig.HostConfig.AddService <IMetricsLogger>(metricsLogger);
            }

            using (metricsLogger.LatencyEvent(MetricEventNames.HostStartupLatency))
            {
                // read host.json and apply to JobHostConfiguration
                string hostConfigFilePath = Path.Combine(ScriptConfig.RootScriptPath, ScriptConstants.HostMetadataFileName);

                // If it doesn't exist, create an empty JSON file
                if (!File.Exists(hostConfigFilePath))
                {
                    File.WriteAllText(hostConfigFilePath, "{}");
                }

                if (ScriptConfig.HostConfig.IsDevelopment || InDebugMode)
                {
                    // If we're in debug/development mode, use optimal debug settings
                    ScriptConfig.HostConfig.UseDevelopmentSettings();
                }

                string  json = File.ReadAllText(hostConfigFilePath);
                JObject hostConfig;
                try
                {
                    hostConfig = JObject.Parse(json);
                }
                catch (JsonException ex)
                {
                    throw new FormatException(string.Format("Unable to parse {0} file.", ScriptConstants.HostMetadataFileName), ex);
                }

                ApplyConfiguration(hostConfig, ScriptConfig);

                // Set up a host level TraceMonitor that will receive notification
                // of ALL errors that occur. This allows us to inspect/log errors.
                var traceMonitor = new TraceMonitor()
                                   .Filter(p => { return(true); })
                                   .Subscribe(HandleHostError);
                ScriptConfig.HostConfig.Tracing.Tracers.Add(traceMonitor);

                TraceLevel hostTraceLevel = ScriptConfig.HostConfig.Tracing.ConsoleLevel;
                if (ScriptConfig.FileLoggingMode != FileLoggingMode.Never)
                {
                    // Host file logging is only done conditionally
                    string      hostLogFilePath = Path.Combine(ScriptConfig.RootLogPath, "Host");
                    TraceWriter fileTraceWriter = new FileTraceWriter(hostLogFilePath, hostTraceLevel).Conditional(p => FileLoggingEnabled);

                    if (TraceWriter != null)
                    {
                        // create a composite writer so our host logs are written to both
                        TraceWriter = new CompositeTraceWriter(new[] { TraceWriter, fileTraceWriter });
                    }
                    else
                    {
                        TraceWriter = fileTraceWriter;
                    }
                }

                if (TraceWriter != null)
                {
                    ScriptConfig.HostConfig.Tracing.Tracers.Add(TraceWriter);
                }
                else
                {
                    // if no TraceWriter has been configured, default it to Console
                    TraceWriter = new ConsoleTraceWriter(hostTraceLevel);
                }

                _debugModeFileWatcher = new AutoRecoveringFileSystemWatcher(hostLogPath, ScriptConstants.DebugSentinelFileName,
                                                                            includeSubdirectories: false, changeTypes: WatcherChangeTypes.Created | WatcherChangeTypes.Changed);

                _debugModeFileWatcher.Changed += OnDebugModeFileChanged;

                var storageString = AmbientConnectionStringProvider.Instance.GetConnectionString(ConnectionStringNames.Storage);
                Task <BlobLeaseManager> blobManagerCreation = null;
                if (storageString == null)
                {
                    // Disable core storage
                    ScriptConfig.HostConfig.StorageConnectionString = null;
                    blobManagerCreation = Task.FromResult <BlobLeaseManager>(null);
                }
                else
                {
                    blobManagerCreation = BlobLeaseManager.CreateAsync(storageString, TimeSpan.FromSeconds(15), ScriptConfig.HostConfig.HostId, InstanceId, TraceWriter);
                }

                var bindingProviders = LoadBindingProviders(ScriptConfig, hostConfig, TraceWriter);
                ScriptConfig.BindingProviders = bindingProviders;

                TraceWriter.Info(string.Format(CultureInfo.InvariantCulture, "Reading host configuration file '{0}'", hostConfigFilePath));

                if (ScriptConfig.FileWatchingEnabled)
                {
                    _scriptFileWatcher = new AutoRecoveringFileSystemWatcher(ScriptConfig.RootScriptPath);

                    _scriptFileWatcher.Changed += OnFileChanged;
                }

                // If a file change should result in a restart, we debounce the event to
                // ensure that only a single restart is triggered within a specific time window.
                // This allows us to deal with a large set of file change events that might
                // result from a bulk copy/unzip operation. In such cases, we only want to
                // restart after ALL the operations are complete and there is a quiet period.
                _restart = (e) =>
                {
                    TraceWriter.Info(string.Format(CultureInfo.InvariantCulture, "File change of type '{0}' detected for '{1}'", e.ChangeType, e.FullPath));
                    TraceWriter.Info("Host configuration has changed. Signaling restart.");
                    RestartHost();
                };
                _restart = _restart.Debounce(500);

                // take a snapshot so we can detect function additions/removals
                _directoryCountSnapshot = Directory.EnumerateDirectories(ScriptConfig.RootScriptPath).Count();

                List <FunctionDescriptorProvider> descriptionProviders = new List <FunctionDescriptorProvider>()
                {
                    new ScriptFunctionDescriptorProvider(this, ScriptConfig),
                    new NodeFunctionDescriptorProvider(this, ScriptConfig),
                    new DotNetFunctionDescriptorProvider(this, ScriptConfig),
                    new PowerShellFunctionDescriptorProvider(this, ScriptConfig)
                };

                // Allow BindingProviders to initialize
                foreach (var bindingProvider in ScriptConfig.BindingProviders)
                {
                    try
                    {
                        bindingProvider.Initialize();
                    }
                    catch (Exception ex)
                    {
                        // If we're unable to initialize a binding provider for any reason, log the error
                        // and continue
                        TraceWriter.Error(string.Format("Error initializing binding provider '{0}'", bindingProvider.GetType().FullName), ex);
                    }
                }

                // Create the lease manager that will keep handle the primary host blob lease acquisition and renewal
                // and subscribe for change notifications.
                _blobLeaseManager = blobManagerCreation.GetAwaiter().GetResult();
                if (_blobLeaseManager != null)
                {
                    _blobLeaseManager.HasLeaseChanged += BlobLeaseManagerHasLeaseChanged;
                }

                // read all script functions and apply to JobHostConfiguration
                Collection <FunctionDescriptor>     functions      = ReadFunctions(descriptionProviders);
                Collection <CustomAttributeBuilder> typeAttributes = CreateTypeAttributes(ScriptConfig);
                string defaultNamespace = "Host";
                string typeName         = string.Format(CultureInfo.InvariantCulture, "{0}.{1}", defaultNamespace, "Functions");
                TraceWriter.Info(string.Format(CultureInfo.InvariantCulture, "Generating {0} job function(s)", functions.Count));
                Type        type  = FunctionGenerator.Generate(HostAssemblyName, typeName, typeAttributes, functions);
                List <Type> types = new List <Type>();
                types.Add(type);

                ScriptConfig.HostConfig.TypeLocator = new TypeLocator(types);

                Functions = functions;

                if (ScriptConfig.FileLoggingMode != FileLoggingMode.Never)
                {
                    PurgeOldLogDirectories();
                }
            }
        }
Beispiel #15
0
        protected virtual void Initialize()
        {
            // read host.json and apply to JobHostConfiguration
            string hostConfigFilePath = Path.Combine(ScriptConfig.RootScriptPath, HostConfigFileName);

            // If it doesn't exist, create an empty JSON file
            if (!File.Exists(hostConfigFilePath))
            {
                File.WriteAllText(hostConfigFilePath, "{}");
            }

            if (ScriptConfig.HostConfig.IsDevelopment)
            {
                ScriptConfig.HostConfig.UseDevelopmentSettings();
            }
            else
            {
                // TEMP: Until https://github.com/Azure/azure-webjobs-sdk-script/issues/100 is addressed
                // we're using some presets that are a good middle ground
                ScriptConfig.HostConfig.Queues.MaxPollingInterval    = TimeSpan.FromSeconds(10);
                ScriptConfig.HostConfig.Singleton.ListenerLockPeriod = TimeSpan.FromSeconds(15);
            }

            string  json       = File.ReadAllText(hostConfigFilePath);
            JObject hostConfig = JObject.Parse(json);

            ApplyConfiguration(hostConfig, ScriptConfig);

            // Set up a host level TraceMonitor that will receive notificaition
            // of ALL errors that occur. This allows us to inspect/log errors.
            var traceMonitor = new TraceMonitor()
                               .Filter(p => { return(true); })
                               .Subscribe(HandleHostError);

            ScriptConfig.HostConfig.Tracing.Tracers.Add(traceMonitor);

            if (ScriptConfig.FileLoggingEnabled)
            {
                string hostLogFilePath = Path.Combine(ScriptConfig.RootLogPath, "Host");
                TraceWriter = new FileTraceWriter(hostLogFilePath, TraceLevel.Verbose);
                ScriptConfig.HostConfig.Tracing.Tracers.Add(TraceWriter);
            }
            else
            {
                TraceWriter = NullTraceWriter.Instance;
            }

            TraceWriter.Verbose(string.Format(CultureInfo.InvariantCulture, "Reading host configuration file '{0}'", hostConfigFilePath));

            if (ScriptConfig.TraceWriter != null)
            {
                ScriptConfig.HostConfig.Tracing.Tracers.Add(ScriptConfig.TraceWriter);
            }
            else
            {
                ScriptConfig.TraceWriter = NullTraceWriter.Instance;
            }

            if (ScriptConfig.FileWatchingEnabled)
            {
                _fileWatcher = new FileSystemWatcher(ScriptConfig.RootScriptPath)
                {
                    IncludeSubdirectories = true,
                    EnableRaisingEvents   = true
                };
                _fileWatcher.Changed += OnFileChanged;
                _fileWatcher.Created += OnFileChanged;
                _fileWatcher.Deleted += OnFileChanged;
                _fileWatcher.Renamed += OnFileChanged;
            }

            // If a file change should result in a restart, we debounce the event to
            // ensure that only a single restart is triggered within a specific time window.
            // This allows us to deal with a large set of file change events that might
            // result from a bulk copy/unzip operation. In such cases, we only want to
            // restart after ALL the operations are complete and there is a quiet period.
            _restart = (e) =>
            {
                TraceWriter.Verbose(string.Format(CultureInfo.InvariantCulture, "File change of type '{0}' detected for '{1}'", e.ChangeType, e.FullPath));
                TraceWriter.Verbose("Host configuration has changed. Signaling restart.");

                // signal host restart
                _restartEvent.Set();
            };
            _restart = _restart.Debounce(500);

            // take a snapshot so we can detect function additions/removals
            _directoryCountSnapshot = Directory.EnumerateDirectories(ScriptConfig.RootScriptPath).Count();

            var dashboardString = AmbientConnectionStringProvider.Instance.GetConnectionString(ConnectionStringNames.Dashboard);

            var config = ScriptConfig.HostConfig;

            if (dashboardString != null)
            {
                var fastLogger = new FastLogger(dashboardString);
                config.AddService <IAsyncCollector <FunctionInstanceLogEntry> >(fastLogger);
            }
            config.DashboardConnectionString = null; // disable slow logging

            IMetricsLogger metricsLogger = ScriptConfig.HostConfig.GetService <IMetricsLogger>();

            if (metricsLogger == null)
            {
                ScriptConfig.HostConfig.AddService <IMetricsLogger>(new MetricsLogger());
            }

            // Bindings may use name resolution, so provide this before reading the bindings.
            var nameResolver = new NameResolver();

            var storageString = AmbientConnectionStringProvider.Instance.GetConnectionString(ConnectionStringNames.Storage);

            if (storageString == null)
            {
                // Disable core storage
                ScriptConfig.HostConfig.StorageConnectionString = null;
            }

            ScriptConfig.HostConfig.NameResolver = nameResolver;

            List <FunctionDescriptorProvider> descriptionProviders = new List <FunctionDescriptorProvider>()
            {
                new ScriptFunctionDescriptorProvider(this, ScriptConfig),
                new NodeFunctionDescriptorProvider(this, ScriptConfig),
                new CSharpFunctionDescriptionProvider(this, ScriptConfig)
            };

            // read all script functions and apply to JobHostConfiguration
            Collection <FunctionDescriptor> functions = ReadFunctions(ScriptConfig, descriptionProviders);
            string defaultNamespace = "Host";
            string typeName         = string.Format(CultureInfo.InvariantCulture, "{0}.{1}", defaultNamespace, "Functions");

            TraceWriter.Verbose(string.Format(CultureInfo.InvariantCulture, "Generating {0} job function(s)", functions.Count));
            Type        type  = FunctionGenerator.Generate(HostAssemblyName, typeName, functions);
            List <Type> types = new List <Type>();

            types.Add(type);

            ScriptConfig.HostConfig.TypeLocator = new TypeLocator(types);

            ApplyBindingConfiguration(functions, ScriptConfig.HostConfig);

            Functions = functions;
        }
Beispiel #16
0
        public async Task Generate_EndToEnd()
        {
            // construct our TimerTrigger attribute ([TimerTrigger("00:00:02", RunOnStartup = true)])
            Collection <ParameterDescriptor> parameters = new Collection <ParameterDescriptor>();

            ParameterDescriptor    parameter            = new ParameterDescriptor("timerInfo", typeof(TimerInfo));
            ConstructorInfo        ctorInfo             = typeof(TimerTriggerAttribute).GetConstructor(new Type[] { typeof(string) });
            PropertyInfo           runOnStartupProperty = typeof(TimerTriggerAttribute).GetProperty("RunOnStartup");
            CustomAttributeBuilder attributeBuilder     = new CustomAttributeBuilder(
                ctorInfo,
                new object[] { "00:00:02" },
                new PropertyInfo[] { runOnStartupProperty },
                new object[] { true });

            parameter.CustomAttributes.Add(attributeBuilder);
            parameters.Add(parameter);

            // create the FunctionDefinition
            FunctionMetadata   metadata = new FunctionMetadata();
            TestInvoker        invoker  = new TestInvoker();
            FunctionDescriptor function = new FunctionDescriptor("TimerFunction", invoker, metadata, parameters, null, null, null);
            Collection <FunctionDescriptor> functions = new Collection <FunctionDescriptor>();

            functions.Add(function);

            // Get the Type Attributes (in this case, a TimeoutAttribute)
            ScriptJobHostOptions scriptConfig = new ScriptJobHostOptions();

            scriptConfig.FunctionTimeout = TimeSpan.FromMinutes(5);
            Collection <CustomAttributeBuilder> typeAttributes = new Collection <CustomAttributeBuilder>();

            // generate the Type
            Type functionType = FunctionGenerator.Generate("TestScriptHost", "TestFunctions", typeAttributes, functions);

            // verify the generated function
            MethodInfo            method           = functionType.GetMethod("TimerFunction");
            ParameterInfo         triggerParameter = method.GetParameters()[0];
            TimerTriggerAttribute triggerAttribute = triggerParameter.GetCustomAttribute <TimerTriggerAttribute>();

            Assert.NotNull(triggerAttribute);

            // start the JobHost which will start running the timer function
            var builder = new HostBuilder()
                          .ConfigureWebJobs(b =>
            {
                b.AddTimers()
                .AddAzureStorageCoreServices();
            })
                          .ConfigureServices(s =>
            {
                s.AddSingleton <ITypeLocator>(new TestTypeLocator(functionType));
                s.AddSingleton <ILoggerFactory>(new LoggerFactory());

                TestHelpers.AddTestAzureBlobStorageProvider(s, TestHelpers.GetTestConfiguration());
                TestHostBuilderExtensions.AddMockedSingleton <IScriptHostManager>(s);
            });

            using (var host = builder.Build())
            {
                await host.StartAsync();

                await Task.Delay(3000);

                await host.StopAsync();
            }

            // verify our custom invoker was called
            Assert.True(invoker.InvokeCount >= 2);
        }
Beispiel #17
0
 private void MainForm_Load(object sender, EventArgs e)
 {
     DrawGraph(functionChart, _functionGenerator.Generate(_from, _to, _dt));
 }
Beispiel #18
0
 private void Form1_Load(object sender, EventArgs e)
 {
     DrawGraph(functionChart, _functionGenerator.Generate(0, 1023, 1));
     DrawScalogram();
 }