/// <summary> /// Unloads a module. /// </summary> /// <param name="moduleData">The module.</param> private static void StopModule(ModuleData moduleData) { try { for (int i = moduleData.Tasks.Length - 1; i >= 0; i--) { TaskManagerService.Logger.Log(string.Format("Stopping task '{0}'...", moduleData.Tasks[i].TaskName)); TaskSupervisor.RemoveTask(moduleData.Tasks[i]); } TaskManagerService.Logger.Log(string.Format("Unloading AppDomain '{0}'...", moduleData.Domain.FriendlyName)); AppDomain.Unload(moduleData.Domain); TaskManagerService.Logger.Log("AppDomain successfully unloaded."); if (moduleData.ZipFile != null && moduleData.ZipDirectory != null) { Directory.Delete(moduleData.ZipDirectory, true); } _moduleList.Remove(moduleData); } catch (Exception e) { TaskManagerService.Logger.Log(string.Format("Exception caught while shutting down module '{0}'", moduleData.DllFile), e); throw; } }
/// <summary> /// Called when the service is being started by the SCM. /// </summary> /// <param name="args">The arguments.</param> protected override void OnStart(string[] args) { ////#if DEBUG //// System.Threading.Thread.Sleep(10000); ////#endif LogInfo("Starting service..."); try { var options = TaskManagerOptions.Create("Start parameters: ", args); Initialize(options.EventLog); TaskSupervisor.Initialize(options.StatsStrategy); ModuleSupervisor.Initialize(); LogInfo("Service successfully started..."); ModuleSupervisor.Execute(); } catch (Exception e) { LogError("Unable to start service.", e); File.WriteAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TaskManager.start.error.txt"), e.Message); throw; } }
/// <summary> /// Loads a module. /// </summary> /// <param name="dllFile">The path to the module DLL file.</param> /// <param name="xmlFile">The path to the module XML configuration file.</param> /// <param name="startImmediately">True if execution should be started immediately after configuring the module, false if module should be configured but not started.</param> private static void LoadAndConfigure(string dllFile, string xmlFile, bool startImmediately) { string modulePath = Path.GetDirectoryName(dllFile); if (!modulePath.EndsWith(Path.DirectorySeparatorChar.ToString())) { modulePath += Path.DirectorySeparatorChar; } string[] files = Directory.GetFiles(modulePath, "*.*", SearchOption.AllDirectories); AppDomainSetup domainSetup = new AppDomainSetup(); domainSetup.ShadowCopyFiles = "true"; domainSetup.ApplicationBase = modulePath; domainSetup.ConfigurationFile = dllFile + ".config"; AppDomain domain = AppDomain.CreateDomain(dllFile, null, domainSetup); TaskManagerService.Logger.Log(string.Format("Module found: '{0}', configuration file: '{1}', scanning assembly for tasks...", dllFile, xmlFile)); if (modulePath != AppDomain.CurrentDomain.BaseDirectory) { string loaderDll = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TaskManager.Loader.dll"); string tempLoaderDll = Path.Combine(modulePath, "TaskManager.Loader.dll"); string commonDll = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TaskManager.Common.dll"); string tempCommonDll = Path.Combine(modulePath, "TaskManager.Common.dll"); File.Copy(loaderDll, tempLoaderDll, true); File.Copy(commonDll, tempCommonDll, true); } AssemblyName loaderAssemblyName = AssemblyName.GetAssemblyName(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TaskManager.Loader.dll")); Loader loader = (Loader)domain.CreateInstanceAndUnwrap(loaderAssemblyName.ToString(), "TaskManager.Loader"); TaskWrapper[] tasks = loader.LoadAndConfigure(dllFile, xmlFile, TaskManagerService.Logger, AppDomain.CurrentDomain.BaseDirectory); ModuleData newModule = new ModuleData(); newModule.BasePath = Path.GetDirectoryName(dllFile); newModule.Tasks = tasks; newModule.DllFile = dllFile; newModule.XmlFile = xmlFile; newModule.Files = new List <string>(files); newModule.Domain = domain; if (startImmediately) { foreach (TaskWrapper task in newModule.Tasks) { TaskSupervisor.ScheduleTask(task); } } _moduleList.Add(newModule); }
/// <summary> /// Runs the task manager from the console. /// </summary> private static void RunFromConsole() { Console.WriteLine("Press ENTER to locate task modules."); Console.ReadLine(); TaskManagerService.LogInfo("Initializing service..."); try { TaskSupervisor.Initialize(); ModuleSupervisor.Initialize(); } catch (Exception e) { TaskManagerService.LogError("Unable to initialize service.", e); return; } Console.WriteLine("Press ENTER to start."); Console.ReadLine(); try { TaskManagerService.LogInfo("Service successfully started..."); ModuleSupervisor.Execute(); } catch (Exception e) { TaskManagerService.LogError("Unable to start service.", e); return; } Console.WriteLine("Press ENTER to stop."); // If you are debugging, you can freeze the main thread here. Console.ReadLine(); TaskManagerService.LogInfo("Stopping service..."); try { ModuleSupervisor.Shutdown(); TaskSupervisor.Shutdown(); TaskManagerService.LogInfo("Service successfully stopped..."); } catch (Exception e) { TaskManagerService.LogError("Unable to stop service.", e); return; } Console.WriteLine("Press ENTER to finish."); Console.ReadLine(); }
/// <summary> /// Loads all modules. /// </summary> public static void Execute() { if (null == _moduleList) { throw new Exception("TaskManager failed to initialize."); } lock (_moduleListLock) { foreach (ModuleData module in _moduleList) { foreach (TaskWrapper task in module.Tasks) { TaskManagerService.Logger.Log(string.Format("Registering task '{0}'...", task.TaskName)); TaskSupervisor.ScheduleTask(task); } } } }
/// <summary> /// Called when the service is being stopped by the SCM. /// </summary> protected override void OnStop() { LogInfo("Stopping service..."); try { ModuleSupervisor.Shutdown(); TaskSupervisor.Shutdown(); LogInfo("Service successfully stopped..."); } catch (Exception e) { LogError("Unable to stop service.", e); throw; } lock (_eventLog) { _eventLog.Close(); _eventLog = null; } }
/// <summary> /// Called when the service is being started by the SCM. /// </summary> /// <param name="args">The arguments.</param> protected override void OnStart(string[] args) { ////#if DEBUG //// System.Threading.Thread.Sleep(10000); ////#endif LogInfo("Starting service..."); try { TaskSupervisor.Initialize(); ModuleSupervisor.Initialize(); LogInfo("Service successfully started..."); ModuleSupervisor.Execute(); } catch (Exception e) { LogError("Unable to start service.", e); throw; } }
/// <summary> /// The thread loop. /// </summary> private void Loop() { DateTime lastRun = DateTime.Now; while (true) { lock (TaskSupervisor._taskLock) { this._task = TaskSupervisor.GetScheduledTask(this); } System.Threading.Thread.MemoryBarrier(); if (null != this._task) { bool result = false; long runTime = -1; TaskSupervisor.NotifyStart(this._task); this.StartingTime = lastRun = DateTime.Now; this.IsRunning = true; System.Threading.Thread.MemoryBarrier(); Stopwatch timer = Stopwatch.StartNew(); try { result = this._task.Execute(); runTime = timer.ElapsedTicks; } catch (ThreadAbortException) { this._task = null; throw; } catch (AppDomainUnloadedException) { this._task = null; throw; } catch (Exception ex) { this.IsRunning = false; if (!TaskSupervisor.NotifyException("Exception caught while executing task.", ex)) { this._task = null; System.Threading.Thread.MemoryBarrier(); throw; } } finally { lastRun = DateTime.Now; this.IsRunning = false; this.StartingTime = DateTime.MinValue; System.Threading.Thread.MemoryBarrier(); TaskSupervisor.NotifyEnd(this._task, runTime); } lock (TaskSupervisor._taskLock) { try { TaskWrapper toReturn = this._task; this._task = null; TaskSupervisor.RescheduleTask(toReturn, result); } catch (AppDomainUnloadedException) { } this._task = null; } System.Threading.Thread.MemoryBarrier(); Thread.Sleep(100); } else { if (lastRun.AddSeconds(IdleTimeout) <= DateTime.Now) { TaskSupervisor.NotifyIdleThread(this); } Thread.Sleep(250); } } }
private static void RunFromConsole(string[] args) { ShowHeader(); TaskManagerOptions options; try { options = TaskManagerOptions.Create("TaskManager.exe", args); } catch (Exception ex) { Show("Argument parsing error: "); Show(ex.Message); Show("Try `TaskManager --help` for more information"); Environment.Exit(3); return; } if (options.ShowHelp) { Show(options.HelpText); return; } WaitUserInteraction(options, "Press ENTER to locate task modules."); TaskManagerService.LogInfo("Initializing service..."); try { Show("Event log: {0}", options.EventLog.GetType().Name); Show("Stats strategy: {0}", options.StatsStrategy.GetType().Name); TaskSupervisor.Initialize(options.StatsStrategy); TaskManagerService.Initialize(options.EventLog); ModuleSupervisor.Initialize(); } catch (Exception e) { TaskManagerService.LogError("Unable to initialize service.", e); WaitUserInteraction(options); return; } WaitUserInteraction(options, "Press ENTER to start."); try { TaskManagerService.LogInfo("Service successfully started..."); ModuleSupervisor.Execute(); if (options.NonStop && options.NonStopWait > 0) { Show("Waiting {0} milliseconds to tasks execution...", options.NonStopWait); Thread.Sleep(options.NonStopWait); } } catch (Exception e) { TaskManagerService.LogError("Unable to start service.", e); WaitUserInteraction(options); return; } // If you are debugging, you can freeze the main thread here. WaitUserInteraction(options, "Press ENTER to stop."); TaskManagerService.LogInfo("Stopping service..."); try { ModuleSupervisor.Shutdown(); TaskSupervisor.Shutdown(); TaskManagerService.LogInfo("Service successfully stopped..."); } catch (Exception e) { TaskManagerService.LogError("Unable to stop service.", e); return; } WaitUserInteraction(options, "Press ENTER to finish."); }
/// <summary> /// Loads a module from a zip file. /// </summary> /// <param name="zipFile">The path to the zip file.</param> /// <param name="startImmediately">True if execution should be started immediately after configuring the module, false if module should be configured but not started.</param> private static void LoadZipAndConfigure(string zipFile, bool startImmediately) { string tempPath = null; int i = 0; while (Directory.Exists(tempPath = Path.Combine(Path.Combine(Path.GetTempPath(), "TaskManager"), Path.GetRandomFileName()))) { i++; if (i == 10) { throw new Exception("Failed to create a new temporary folder."); } } if (!tempPath.EndsWith(Path.DirectorySeparatorChar.ToString())) { tempPath += Path.DirectorySeparatorChar; } string overridePath = Path.Combine(Path.GetDirectoryName(zipFile), Path.GetFileNameWithoutExtension(zipFile)) + Path.DirectorySeparatorChar; string loaderDll = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TaskManager.Loader.dll"); string tempLoaderDll = Path.Combine(tempPath, "TaskManager.Loader.dll"); string commonDll = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TaskManager.Common.dll"); string tempCommonDll = Path.Combine(tempPath, "TaskManager.Common.dll"); List <string> dependencies = new List <string>(); DirectoryInfo directoryInfo = Directory.CreateDirectory(tempPath); try { using (Stream fileStream = File.Open(zipFile, FileMode.Open, FileAccess.Read)) { using (ZipArchive zip = new ZipArchive(fileStream, ZipArchiveMode.Read)) { var directory = zip.Entries; foreach (var compressedFile in directory) { string destinationFile = Path.Combine(tempPath, compressedFile.FullName); string overrideFile = Path.Combine(overridePath, compressedFile.FullName); dependencies.Add(overrideFile); compressedFile.ExtractToFile(destinationFile, true); } } } if (Directory.Exists(overridePath)) { foreach (string overrideFile in Directory.GetFiles(overridePath, "*.*", SearchOption.AllDirectories)) { if (!dependencies.Contains(overrideFile)) { dependencies.Add(overrideFile); } dependencies.Add(Path.Combine(overridePath, overrideFile.Replace(tempPath, string.Empty))); string relativeName = overrideFile.Replace(overridePath, string.Empty); string destination = Path.Combine(tempPath, relativeName); string destinationPath = Path.GetDirectoryName(destination); if (!Directory.Exists(destinationPath)) { Directory.CreateDirectory(destinationPath); } File.Copy(overrideFile, destination, true); } } List <string> possibleFiles = new List <string>(); foreach (string moduleFile in Directory.GetFiles(tempPath, "*" + ModuleFileDefaultExtension, SearchOption.AllDirectories)) { string xmlFile = Path.ChangeExtension(moduleFile, ConfigFileDefaultExtension); if (File.Exists(xmlFile)) { possibleFiles.Add(moduleFile); } } File.Copy(loaderDll, tempLoaderDll, true); File.Copy(commonDll, tempCommonDll, true); foreach (string dllFile in possibleFiles) { string xmlFile = Path.ChangeExtension(dllFile, ConfigFileDefaultExtension); if (File.Exists(xmlFile)) { if (!xmlFile.IsValidConfigurationFile()) { continue; } string modulePath = Path.GetDirectoryName(dllFile); string[] files = Directory.GetFiles(modulePath, "*.*", SearchOption.AllDirectories); AppDomainSetup domainSetup = new AppDomainSetup(); domainSetup.ShadowCopyFiles = "true"; domainSetup.ApplicationBase = tempPath; domainSetup.ConfigurationFile = dllFile + ".config"; AppDomain domain = AppDomain.CreateDomain(dllFile, null, domainSetup); TaskWrapper[] tasks = new TaskWrapper[0]; try { TaskManagerService.Logger.Log(string.Format("Module found: '{0}', configuration file: '{1}', scanning assembly for tasks...", dllFile, xmlFile)); AssemblyName loaderAssemblyName = AssemblyName.GetAssemblyName(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TaskManager.Loader.dll")); Loader loader = (Loader)domain.CreateInstanceAndUnwrap(loaderAssemblyName.ToString(), "TaskManager.Loader"); tasks = loader.LoadAndConfigure(dllFile, xmlFile, TaskManagerService.Logger, AppDomain.CurrentDomain.BaseDirectory); ModuleData newModule = new ModuleData(); newModule.BasePath = overridePath; newModule.Tasks = tasks; newModule.DllFile = dllFile; newModule.XmlFile = xmlFile; newModule.ZipFile = zipFile; newModule.ZipDirectory = tempPath; newModule.Files = new List <string>(files); newModule.Files.AddRange(dependencies); newModule.Files.Add(zipFile); newModule.Domain = domain; if (startImmediately) { foreach (TaskWrapper task in newModule.Tasks) { TaskSupervisor.ScheduleTask(task); } } _moduleList.Add(newModule); } catch (Exception ex) { foreach (TaskWrapper task in tasks) { try { TaskSupervisor.RemoveTask(task); } catch { } } AppDomain.Unload(domain); TaskManagerService.Logger.Log(string.Format("Unable to load module '{0}' from zipped file '{1}'.", dllFile, zipFile), ex); } } } foreach (ModuleData module in _moduleList) { if (module.ZipFile == zipFile) { return; } } throw new Exception(string.Format("Unable to find tasks in zipped file '{0}'.", zipFile)); } catch { try { Directory.Delete(tempPath, true); } catch (Exception ex) { TaskManagerService.Logger.Log(string.Format("Unable to remove temporary directory '{0}'.", tempPath), ex); } throw; } }