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); }
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); }
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; }
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(); } } }
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; }
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); }
private void MainForm_Load(object sender, EventArgs e) { DrawGraph(functionChart, _functionGenerator.Generate(_from, _to, _dt)); }
private void Form1_Load(object sender, EventArgs e) { DrawGraph(functionChart, _functionGenerator.Generate(0, 1023, 1)); DrawScalogram(); }