SQLXAgent 包运行机制解析

本文是关于 SQLXAgent 工具的系列文章的第五部分,将详细解析 SQLXAgent 包的运行机制。首先需要明确的是,SQLXAgent 包与传统的 DTSX 包有很大的不同。SQLXAgent 包通常只包含一个任务,并且这个任务是一个脚本任务,需要编写代码来实现。可以使用任何 .NET 语言来创建包,只要最终编译成 .PKG 程序集(实质上是一个带有 "PKG" 扩展名的 DLL)。

在本文中,可能会展示一些代码片段,这些代码可能不是最新版本,但与实际代码非常接近。在编写文章过程中,可能会发现一些问题,这就是为什么代码可能不完全匹配的原因。

包的运行方式

包是通过 SQLXPkgRunner 命令行应用程序运行的。一切从 JobThread.ExecuteJob 方法开始,该方法调用应用程序。下面省略了不相关的代码,但这些内容在本系列文章的第四部分中有详细讨论。

public virtual void ExecuteJob() { if (!this.IsWorking) { foreach (StepItem step in this.Job.Steps) { if (step.StepIsEnabled) { switch (step.StepType) { case "SQL": // ... break; case "PKG": try { if (string.IsNullOrEmpty(step.SsisFilePath)) { // ... } else { string pkgDLLFileName = step.SsisFilePath; string path = System.IO.Path.Combine(Globals.AppPath, "SQLXPkgRunner.exe"); string args = string.Format("-p\"{0}\" -s\"{1}\" -c\"{2}\"", pkgDLLFileName, step.ID, step.ConnectionString); Process app = new Process(); ProcessStartInfo info = new ProcessStartInfo() { Arguments = args, CreateNoWindow = true, FileName = path, UseShellExecute = true, }; app.StartInfo = info; app.Start(); app.WaitForExit(); int result = app.ExitCode; if (result > 0) { status = "FAIL"; SQLXExceptionEnum exception = Globals.IntToEnum(result, SQLXExceptionEnum.Unknown); switch (exception) { case SQLXExceptionEnum.PkgFileNotFound: reason = string.Concat(SQLXExceptionCodes.Codes[(int)exception], "- ", pkgDLLFileName); break; default: reason = SQLXExceptionCodes.Codes[(int)exception]; break; } } else { status = "SUCCESS"; reason = string.Empty; } } } catch (Exception ex) { status = "FAIL"; reason = ex.Message; } // DebugMsgs... break; } } else { // ... } } } }

SQLXPkgRunner 应用程序没有窗口或界面,因为它实际上是在 Windows 服务中执行的。当应用程序启动时,会对参数进行一些基本的检查。

static int Main(string[] args) { var options = new CommandlineOptions(); CommandLine.Parser.Default.ParseArguments(args, options); Globals.SetExtensionFileSystemObjects(Assembly.GetExecutingAssembly()); int result = 0; if (args.Length > 0) { if (string.IsNullOrEmpty(options.Package)) { result = (int)SQLXExceptionEnum.CmdLineArgPkgFilename; } else if (!File.Exists(options.Package)) { result = (int)SQLXExceptionEnum.PkgFileNotFound; } else if (string.IsNullOrEmpty(options.StepID)) { result = (int)SQLXExceptionEnum.CmdLineArgStepID; } else if (string.IsNullOrEmpty(options.ConnectionString)) { result = (int)SQLXExceptionEnum.CmdLineArgPkgConnString; } else { string connStr = ""; result = GetSQLXConnString(ref connStr); } if (result == 0) { result = LoadDllAndRun(options.Package.Trim(), options.StepID.Trim(), options.ConnectionString.Trim()); } } else { result = (int)SQLXExceptionEnum.NoCmdLineArgs; } return result; }

如果一切检查通过,将加载并运行包程序集。假设(并建议)一个包只包含一个从 SQLXAgentPkgBase 派生的类,因为只查找找到的第一个对象,并且使用它。这个方法中的大部分代码都涉及到可能的异常。

private static int LoadDllAndRun(string path, string stepID, string connString) { int result = 0; SQLXAgentPkgBase pkg = null; var dll = Assembly.LoadFile(path); bool foundObject = false; try { Type type = dll.GetExportedTypes().FirstOrDefault(x => x.BaseType.Name.IsLike("%SQLXAgentPkgBase")); if (type != null) { pkg = (SQLXAgentPkgBase)(Activator.CreateInstance(type)); if (pkg != null) { foundObject = true; pkg.Run(stepID, connString); string failReason = pkg.FailReason; } } if (!foundObject) { result = (int)SQLXExceptionEnum.SQLXPkgBaseClassNotFound; } } catch (BadImageFormatException) { result = (int)SQLXExceptionEnum.PkgRunnerBadImageFormat; } catch (System.IO.FileNotFoundException) { result = (int)SQLXExceptionEnum.PkgRunnerFileNotFound; } catch (System.IO.FileLoadException) { result = (int)SQLXExceptionEnum.PkgRunnerFileLoad; } catch (ArgumentException) { result = (int)SQLXExceptionEnum.PkgRunnerArgument; } catch (NotSupportedException) { result = (int)SQLXExceptionEnum.PkgRunnerNotSupported; } catch (System.Reflection.TargetInvocationException) { result = (int)SQLXExceptionEnum.PkgRunnerTargetInvocation; } catch (MethodAccessException) { result = (int)SQLXExceptionEnum.PkgRunnerMethodAccess; } catch (System.Runtime.InteropServices.InvalidComObjectException) { result = (int)SQLXExceptionEnum.PkgRunnerInvalidComObject; } catch (MissingMethodException) { result = (int)SQLXExceptionEnum.PkgRunnerMissingMethod; } catch (TypeLoadException) { result = (int)SQLXExceptionEnum.PkgRunnerTypeLoad; } catch (Exception) { result = (int)SQLXExceptionEnum.PkgRunnerUnexpected; } return result; }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485