private static JObject GetTestWorkerConfig(string language, string[] arguments, bool invalid, string profileName) { var description = new WorkerDescription() { DefaultExecutablePath = "foopath", DefaultWorkerPath = $"{testWorkerPathInWorkerConfig}.{language}", Language = language, Extension = $".{language}", Arguments = arguments.ToList() }; JObject config = new JObject(); config["Description"] = JObject.FromObject(description); if (!string.IsNullOrEmpty(profileName)) { var appSvcDescription = new WorkerDescription() { DefaultExecutablePath = "myFooPath", }; JObject profiles = new JObject(); profiles[profileName] = JObject.FromObject(appSvcDescription); config[LanguageWorkerConstants.WorkerDescriptionProfiles] = profiles; } if (invalid) { config["Description"] = "invalidWorkerConfig"; } return(config); }
internal void AddProvider(string workerDir, ILogger logger) { try { string workerConfigPath = Path.Combine(workerDir, LanguageWorkerConstants.WorkerConfigFileName); if (!File.Exists(workerConfigPath)) { logger.LogTrace($"Did not find worker config file at: {workerConfigPath}"); return; } logger.LogTrace($"Found worker config: {workerConfigPath}"); string json = File.ReadAllText(workerConfigPath); JObject workerConfig = JObject.Parse(json); WorkerDescription workerDescription = workerConfig.Property(LanguageWorkerConstants.WorkerDescription).Value.ToObject <WorkerDescription>(); workerDescription.WorkerDirectory = workerDir; var languageSection = _config.GetSection($"{LanguageWorkerConstants.LanguageWorkersSectionName}:{workerDescription.Language}"); workerDescription.Arguments = workerDescription.Arguments ?? new List <string>(); var argumentsSection = languageSection.GetSection($"{LanguageWorkerConstants.WorkerDescriptionArguments}"); if (argumentsSection.Value != null) { workerDescription.Arguments.AddRange(Regex.Split(argumentsSection.Value, @"\s+")); } logger.LogTrace($"Will load worker provider for language: {workerDescription.Language}"); _workerProviderDictionary[workerDescription.Language] = new GenericWorkerProvider(workerDescription, workerDir); } catch (Exception ex) { logger?.LogError(ex, $"Failed to initialize worker provider for: {workerDir}"); } }
public void ReadWorkerProviderFromConfig_AddAppSvcProfile_ReturnsAppServiceEnvDescription() { var expectedArguments = new string[] { "-v", "verbose" }; var configs = new List <TestLanguageWorkerConfig>() { MakeTestConfig(testLanguage, expectedArguments, false, LanguageWorkerConstants.WorkerDescriptionAppServiceEnvProfileName) }; var testLogger = new TestLogger(testLanguage); WorkerDescription testWorkerDescription = GetTestDefaultWorkerDescription(testLanguage, expectedArguments); // Creates temp directory w/ worker.config.json and runs ReadWorkerProviderFromConfig IEnumerable <IWorkerProvider> providers = TestReadWorkerProviderFromConfig(configs, testLogger, null, null, true); Assert.Single(providers); IWorkerProvider worker = providers.FirstOrDefault(); var actualWorkerDescription = worker.GetDescription(); Assert.Equal("myFooPath", worker.GetDescription().DefaultExecutablePath); Assert.Equal(testWorkerDescription.DefaultWorkerPath, actualWorkerDescription.DefaultWorkerPath); Assert.False(testWorkerDescription.Extensions.Except(actualWorkerDescription.Extensions).Any()); Assert.Equal($"{testLanguage}", worker.GetDescription().Language); if (testWorkerDescription.Arguments == null) { Assert.Null(actualWorkerDescription.Arguments); } else { Assert.False(testWorkerDescription.Arguments.Except(actualWorkerDescription.Arguments).Any()); } }
private static TestLanguageWorkerConfig MakeTestConfig(string language, string[] arguments, bool invalid = false) { var description = new WorkerDescription() { DefaultExecutablePath = "foopath", DefaultWorkerPath = $"./src/index.{language}", Language = language, Extension = $".{language}" }; JObject config = new JObject(); config["Description"] = JObject.FromObject(description); config["Arguments"] = JArray.FromObject(arguments); if (invalid) { config["Description"] = "invalidWorkerConfig"; } string json = config.ToString(); return(new TestLanguageWorkerConfig() { Json = json, Language = language, }); }
public void GetDescription_ReturnsDescription() { var workerDescription = new WorkerDescription(); var provider = new GenericWorkerProvider(workerDescription, string.Empty); Assert.Equal(workerDescription, provider.GetDescription()); }
private static JObject GetTestWorkerConfig(string language, string[] arguments, bool invalid, string profileName) { WorkerDescription description = GetTestDefaultWorkerDescription(language, arguments); JObject config = new JObject(); config[LanguageWorkerConstants.WorkerDescription] = JObject.FromObject(description); if (!string.IsNullOrEmpty(profileName)) { var appSvcDescription = new WorkerDescription() { DefaultExecutablePath = "myFooPath", }; JObject profiles = new JObject(); profiles[profileName] = JObject.FromObject(appSvcDescription); config[LanguageWorkerConstants.WorkerDescriptionProfiles] = profiles; } if (invalid) { config[LanguageWorkerConstants.WorkerDescription] = "invalidWorkerConfig"; } return(config); }
public void GetDescription_ReturnsDescription() { var workerDescription = new WorkerDescription(); var arguments = new List <string>(); var provider = new GenericWorkerProvider(workerDescription, arguments); Assert.Equal(workerDescription, provider.GetDescription()); }
private static void AddArgumentsFromAppSettings(WorkerDescription workerDescription, IConfigurationSection languageSection) { var argumentsSection = languageSection.GetSection($"{LanguageWorkerConstants.WorkerDescriptionArguments}"); if (argumentsSection.Value != null) { workerDescription.Arguments.AddRange(Regex.Split(argumentsSection.Value, @"\s+")); } }
public static JObject GetTestHttpInvokerConfig(string[] arguments, bool invalid = false) { WorkerDescription description = GetTestHttpInvokerDescription(arguments, invalid); JObject config = new JObject(); config[OutOfProcConstants.WorkerDescription] = JObject.FromObject(description); return(config); }
public void ValidateWorkerDescription_Succeeds(WorkerDescription workerDescription) { try { WorkerConfigTestUtilities.CreateTestWorkerFileInCurrentDir(); workerDescription.ApplyDefaultsAndValidate(); } finally { WorkerConfigTestUtilities.DeleteTestWorkerFileInCurrentDir(); } }
public void ValidateWorkerDescription_Succeeds(WorkerDescription workerDescription) { var testLogger = new TestLogger(testLanguage); try { RpcWorkerConfigTestUtilities.CreateTestWorkerFileInCurrentDir(); workerDescription.ApplyDefaultsAndValidate(Directory.GetCurrentDirectory(), testLogger); } finally { RpcWorkerConfigTestUtilities.DeleteTestWorkerFileInCurrentDir(); } }
private static WorkerDescription GetWorkerDescriptionFromProfiles(string key, Dictionary <string, WorkerDescription> descriptionProfiles, WorkerDescription defaultWorkerDescription) { WorkerDescription profileDescription = null; if (descriptionProfiles.TryGetValue(key, out profileDescription)) { profileDescription.Arguments = profileDescription.Arguments?.Count > 0 ? profileDescription.Arguments : defaultWorkerDescription.Arguments; profileDescription.DefaultExecutablePath = string.IsNullOrEmpty(profileDescription.DefaultExecutablePath) ? defaultWorkerDescription.DefaultExecutablePath : profileDescription.DefaultExecutablePath; profileDescription.DefaultWorkerPath = string.IsNullOrEmpty(profileDescription.DefaultWorkerPath) ? defaultWorkerDescription.DefaultWorkerPath : profileDescription.DefaultWorkerPath; profileDescription.Extensions = profileDescription.Extensions ?? defaultWorkerDescription.Extensions; profileDescription.Language = string.IsNullOrEmpty(profileDescription.Language) ? defaultWorkerDescription.Language : profileDescription.Language; profileDescription.WorkerDirectory = string.IsNullOrEmpty(profileDescription.WorkerDirectory) ? defaultWorkerDescription.WorkerDirectory : profileDescription.WorkerDirectory; return(profileDescription); } return(defaultWorkerDescription); }
internal void AddProvider(string workerDir) { try { Dictionary <string, WorkerDescription> descriptionProfiles = new Dictionary <string, WorkerDescription>(); string workerConfigPath = Path.Combine(workerDir, LanguageWorkerConstants.WorkerConfigFileName); if (!File.Exists(workerConfigPath)) { _logger.LogDebug($"Did not find worker config file at: {workerConfigPath}"); return; } _logger.LogDebug($"Found worker config: {workerConfigPath}"); string json = File.ReadAllText(workerConfigPath); JObject workerConfig = JObject.Parse(json); WorkerDescription workerDescription = workerConfig.Property(LanguageWorkerConstants.WorkerDescription).Value.ToObject <WorkerDescription>(); workerDescription.WorkerDirectory = workerDir; var languageSection = _config.GetSection($"{LanguageWorkerConstants.LanguageWorkersSectionName}:{workerDescription.Language}"); workerDescription.Arguments = workerDescription.Arguments ?? new List <string>(); descriptionProfiles = GetWorkerDescriptionProfiles(workerConfig); if (ScriptSettingsManager.Instance.IsAppServiceEnvironment) { // Overwrite default Description with AppServiceEnv profile // TODO:pgopa delete after ANT78 workerDescription = GetWorkerDescriptionFromProfiles(LanguageWorkerConstants.WorkerDescriptionAppServiceEnvProfileName, descriptionProfiles, workerDescription); } GetDefaultExecutablePathFromAppSettings(workerDescription, languageSection); AddArgumentsFromAppSettings(workerDescription, languageSection); string workerPath = workerDescription.GetWorkerPath(); if (string.IsNullOrEmpty(workerPath) || File.Exists(workerPath)) { _logger.LogDebug($"Will load worker provider for language: {workerDescription.Language}"); workerDescription.Validate(); _workerProviderDictionary[workerDescription.Language] = new GenericWorkerProvider(workerDescription, workerDir); } else { throw new FileNotFoundException($"Did not find worker for for language: {workerDescription.Language}", workerPath); } } catch (Exception ex) { _logger?.LogError(ex, $"Failed to initialize worker provider for: {workerDir}"); } }
private static Dictionary <string, WorkerDescription> GetWorkerDescriptionProfiles(JObject workerConfig) { Dictionary <string, WorkerDescription> descriptionProfiles = new Dictionary <string, WorkerDescription>(); var profiles = workerConfig.Property("profiles")?.Value.ToObject <JObject>(); if (profiles != null) { foreach (var profile in profiles) { string name = profile.Key; JToken value = profile.Value; WorkerDescription description = profile.Value.ToObject <WorkerDescription>(); descriptionProfiles.Add(name, description); } } return(descriptionProfiles); }
internal static void AddArgumentsFromAppSettings(WorkerDescription workerDescription, IConfigurationSection languageSection) { if (workerDescription.Language.Equals(LanguageWorkerConstants.JavaLanguageWorkerName)) { // For Java either provide arguments via JAVA_OPTS or languageWorkers:java:arguments. Both cannot be supported string javaOpts = ScriptSettingsManager.Instance.GetSetting("JAVA_OPTS"); if (!string.IsNullOrEmpty(javaOpts)) { workerDescription.Arguments.Add(javaOpts); return; } } var argumentsSection = languageSection.GetSection($"{LanguageWorkerConstants.WorkerDescriptionArguments}"); if (argumentsSection.Value != null) { workerDescription.Arguments.AddRange(Regex.Split(argumentsSection.Value, @"\s+")); } }
public static List <IWorkerProvider> ReadWorkerProviderFromConfig(ScriptHostConfiguration config, ILogger logger, ScriptSettingsManager settingsManager = null) { var providers = new List <IWorkerProvider>(); settingsManager = settingsManager ?? ScriptSettingsManager.Instance; var assemblyDir = Path.GetDirectoryName(new Uri(typeof(WorkerConfigFactory).Assembly.CodeBase).LocalPath); var workerDirPath = settingsManager.Configuration.GetSection("workers:config:path").Value ?? Path.Combine(assemblyDir, "workers"); foreach (var workerDir in Directory.EnumerateDirectories(workerDirPath)) { try { // check if worker config exists string workerConfigPath = Path.Combine(workerDir, ScriptConstants.WorkerConfigFileName); // TODO: Move to constant if (!File.Exists(workerConfigPath)) { // not a worker directory continue; } string json = File.ReadAllText(workerConfigPath); JObject workerConfig = JObject.Parse(json); WorkerDescription description = workerConfig.Property("Description").Value.ToObject <WorkerDescription>(); // var workerSettings = settingsManager.Configuration.GetSection($"workers:{description.Language}"); var arguments = new List <string>(); arguments.AddRange(workerConfig.Property("Arguments").Value.ToObject <string[]>()); var provider = new GenericWorkerProvider(description, arguments); providers.Add(provider); } catch (Exception e) { logger.LogCritical(e, $"Failed to initialize worker provider for: {workerDir}"); } } return(providers); }
public void ReadWorkerProviderFromConfig_ReturnsProviderNoArguments() { string language = "test"; var description = new WorkerDescription() { DefaultExecutablePath = "foopath", DefaultWorkerPath = "./src/index.test", Language = "test", Extension = ".test" }; var arguments = new string[] { }; JObject config = new JObject(); config["Description"] = JObject.FromObject(description); config["Arguments"] = JArray.FromObject(arguments); string json = config.ToString(); var mockLogger = new Mock <ILogger <object> >(MockBehavior.Loose); mockLogger.Setup(x => x.Log <object>( It.IsAny <LogLevel>(), It.IsAny <EventId>(), It.IsAny <object>(), It.IsAny <Exception>(), It.IsAny <Func <object, Exception, string> >())); // Creates temp directory w/ worker.config.json and runs ReadWorkerProviderFromConfig var providers = TestReadWorkerProviderFromConfig(language, json, arguments, mockLogger); mockLogger.Verify(x => x.Log <object>( It.IsAny <LogLevel>(), It.IsAny <EventId>(), It.IsAny <object>(), It.IsAny <Exception>(), It.IsAny <Func <object, Exception, string> >()), Times.Never()); Assert.Single(providers); }
private static JObject GetTestWorkerConfig(string language, string[] arguments, bool invalid) { var description = new WorkerDescription() { DefaultExecutablePath = "foopath", DefaultWorkerPath = $"./src/index.{language}", Language = language, Extension = $".{language}", Arguments = arguments.ToList() }; JObject config = new JObject(); config["Description"] = JObject.FromObject(description); if (invalid) { config["Description"] = "invalidWorkerConfig"; } return(config); }
public void AddArgumentsFromAppSettings_JavaOpts(string expectedArgument, string javaOpts) { WorkerDescription workerDescription = new WorkerDescription() { Arguments = new List <string>() { "-jar" }, DefaultExecutablePath = "java", DefaultWorkerPath = "javaworker.jar", Extensions = new List <string>() { ".jar" }, Language = "java" }; var configBuilder = ScriptSettingsManager.CreateDefaultConfigurationBuilder() .AddInMemoryCollection(new Dictionary <string, string> { ["languageWorker"] = "test", ["languageWorkers:java:arguments"] = "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005" }); var config = configBuilder.Build(); var scriptSettingsManager = new ScriptSettingsManager(config); var testLogger = new TestLogger("test"); var configFactory = new WorkerConfigFactory(config, testLogger); var languageSection = config.GetSection("languageWorkers:java"); var testEnvVariables = new Dictionary <string, string> { { "JAVA_OPTS", javaOpts } }; using (var variables = new TestScopedSettings(scriptSettingsManager, testEnvVariables)) { WorkerConfigFactory.AddArgumentsFromAppSettings(workerDescription, languageSection); Assert.Equal(2, workerDescription.Arguments.Count); Assert.Equal(expectedArgument, workerDescription.Arguments[1]); } }
public void ReadWorkerProviderFromConfig_BadConfigFile() { string language = "test"; var description = new WorkerDescription() { DefaultExecutablePath = "foopath", DefaultWorkerPath = "./src/index.test", Language = "test", Extension = ".test" }; var arguments = new string[] { }; string json = "garbage"; var mockLogger = new Mock <ILogger <object> >(MockBehavior.Loose); mockLogger.Setup(x => x.Log <object>( It.IsAny <LogLevel>(), It.IsAny <EventId>(), It.IsAny <object>(), It.IsAny <Exception>(), It.IsAny <Func <object, Exception, string> >())); // Creates temp directory w/ worker.config.json and runs ReadWorkerProviderFromConfig var providers = TestReadWorkerProviderFromConfig(language, json, arguments, mockLogger); mockLogger.Verify(x => x.Log <object>( It.IsAny <LogLevel>(), It.IsAny <EventId>(), It.IsAny <object>(), It.IsAny <Exception>(), It.IsAny <Func <object, Exception, string> >()), Times.Once()); Assert.Empty(providers); }
public static IWorkerProvider GetProviderFromConfig(string workerDir, ILogger logger) { try { string workerConfigPath = Path.Combine(workerDir, ScriptConstants.WorkerConfigFileName); if (File.Exists(workerConfigPath)) { logger.LogInformation($"Found worker config: {workerConfigPath}"); string json = File.ReadAllText(workerConfigPath); JObject workerConfig = JObject.Parse(json); WorkerDescription workerDescription = workerConfig.Property(WorkerConstants.Description).Value.ToObject <WorkerDescription>(); var arguments = new List <string>(); arguments.AddRange(workerConfig.Property(WorkerConstants.Arguments).Value.ToObject <string[]>()); logger.LogInformation($"Will load worker provider for language: {workerDescription.Language}"); return(new GenericWorkerProvider(workerDescription, arguments, workerDir)); } return(null); } catch (Exception ex) { logger?.LogError(ex, $"Failed to initialize worker provider for: {workerDir}"); return(null); } }
public async Task <string> OrchestrateWorker(WorkerDescription workerDescription) { if (_processorDictionary == null) { this._processorDictionary = this.StateManager .GetOrAddAsync <IReliableDictionary <string, ProcessorInformation> >("orchestrator.ProcessorDictionary").Result; } ServiceEventSource.Current.ServiceMessage(this.Context, $"Orchestrate worker called for {workerDescription.Identifier}"); var address = String.Empty; using (var tx = this.StateManager.CreateTransaction()) { ConditionalValue <ProcessorInformation> result = new ConditionalValue <ProcessorInformation>(false, null); int retryAttempt = 0; getProcessorInfo: try { result = await _processorDictionary.TryGetValueAsync(tx, workerDescription.Identifier); } catch (TimeoutException) { // see below for explanation if (retryAttempt++ <= 5) { goto getProcessorInfo; } else { throw; } } if (result.HasValue) { var info = result.Value; retryAttempt = 0; // reset // when running on "slow" machines, if the incoming data is bad and incorrectly partitoned // we will run into time-outs, therefore it is wise to retry the operation, but we'll limit // it to 5 retry attempts updateRetry: try { await _processorDictionary.TryUpdateAsync(tx, workerDescription.Identifier, new ProcessorInformation() { Address = info.Address, TicksLastUpdated = DateTime.UtcNow.Ticks }, info); await tx.CommitAsync(); } catch (TimeoutException) { retryAttempt++; if (retryAttempt >= 5) { throw; } await Task.Delay(100); goto updateRetry; } address = info.Address; } else { // spin up the new service here ServiceEventSource.Current.ServiceMessage(this.Context, $"Creating processor for {workerDescription.Identifier}"); var appName = Context.CodePackageActivationContext.ApplicationName; var svcName = $"{appName}/{Names.ProcessorSuffix}/{workerDescription.Identifier}"; address = svcName; try { await _fabricClient.ServiceManager.CreateServiceAsync(new StatefulServiceDescription() { HasPersistedState = true, PartitionSchemeDescription = new UniformInt64RangePartitionSchemeDescription(1), ServiceTypeName = Names.ProcessorTypeName, ApplicationName = new System.Uri(appName), ServiceName = new System.Uri(svcName) }); ServiceEventSource.Current.ServiceMessage(this.Context, $"Processor for {workerDescription.Identifier} running on {svcName}"); retryAttempt = 0; svcToDictionaryAdd: try { await _processorDictionary.AddAsync(tx, workerDescription.Identifier, new ProcessorInformation() { Address = svcName, TicksLastUpdated = DateTime.UtcNow.Ticks }); await tx.CommitAsync(); } catch (TimeoutException) { retryAttempt++; if (retryAttempt >= 5) { throw; } await Task.Delay(100); // see above for explanation goto svcToDictionaryAdd; } } catch (FabricElementAlreadyExistsException) { // this is a weird case, that happens if the same ID was sent to multiple ServiceEventSource.Current.ServiceMessage(this.Context, $"Processor already existed for {workerDescription.Identifier} on {svcName}"); tx.Abort(); } } } return(address); }
public GenericWorkerProvider(WorkerDescription workerDescription, List <string> arguments) { this.workerDescription = workerDescription ?? throw new ArgumentNullException(nameof(workerDescription)); this.arguments = arguments ?? throw new ArgumentNullException(nameof(arguments)); }
private static void GetDefaultExecutablePathFromAppSettings(WorkerDescription workerDescription, IConfigurationSection languageSection) { var defaultExecutablePath = languageSection.GetSection($"{LanguageWorkerConstants.WorkerDescriptionDefaultExecutablePath}"); workerDescription.DefaultExecutablePath = defaultExecutablePath.Value != null ? defaultExecutablePath.Value : workerDescription.DefaultExecutablePath; }
public void InvalidWorkerDescription_Throws(WorkerDescription workerDescription) { Assert.Throws <ValidationException>(() => workerDescription.Validate()); }
public void ValidateWorkerDescription_Succeeds(WorkerDescription workerDescription) { workerDescription.Validate(); }
public void InvalidWorkerDescription_Throws(WorkerDescription workerDescription) { var testLogger = new TestLogger(testLanguage); Assert.Throws <ValidationException>(() => workerDescription.ApplyDefaultsAndValidate(Directory.GetCurrentDirectory(), testLogger)); }
public GenericWorkerProvider(WorkerDescription workerDescription, List <string> arguments, string pathToWorkerDir) { _workerDescription = workerDescription ?? throw new ArgumentNullException(nameof(workerDescription)); _arguments = arguments ?? throw new ArgumentNullException(nameof(arguments)); _pathToWorkerDir = pathToWorkerDir ?? throw new ArgumentNullException(nameof(pathToWorkerDir)); }
public async Task <string> OrchestrateWorker(WorkerDescription workerDescription) { if (_processorDictionary == null) { this._processorDictionary = this.StateManager .GetOrAddAsync <IReliableDictionary <string, ProcessorInformation> >("orchestrator.ProcessorDictionary").Result; } ServiceEventSource.Current.ServiceMessage(this.Context, $"Orchestrate worker called for {workerDescription.Identifier}"); var address = String.Empty; using (var tx = this.StateManager.CreateTransaction()) { var result = await _processorDictionary.TryGetValueAsync(tx, workerDescription.Identifier); if (result.HasValue) { var info = result.Value; await _processorDictionary.TryUpdateAsync(tx, workerDescription.Identifier, new ProcessorInformation() { Address = info.Address, TicksLastUpdated = DateTime.UtcNow.Ticks }, info); await tx.CommitAsync(); address = info.Address; } else { // spin up the new service here ServiceEventSource.Current.ServiceMessage(this.Context, $"Creating processor for {workerDescription.Identifier}"); var appName = Context.CodePackageActivationContext.ApplicationName; var svcName = $"{appName}/{Names.ProcessorSuffix}/{workerDescription.Identifier}"; await _fabricClient.ServiceManager.CreateServiceAsync(new StatefulServiceDescription() { HasPersistedState = true, PartitionSchemeDescription = new UniformInt64RangePartitionSchemeDescription(1), ServiceTypeName = Names.ProcessorTypeName, ApplicationName = new System.Uri(appName), ServiceName = new System.Uri(svcName) }); ServiceEventSource.Current.ServiceMessage(this.Context, $"Processor for {workerDescription.Identifier} running on {svcName}"); await _processorDictionary.AddAsync(tx, workerDescription.Identifier, new ProcessorInformation() { Address = svcName, TicksLastUpdated = DateTime.UtcNow.Ticks }); address = svcName; await tx.CommitAsync(); } } return(address); }