因此,我们有一个多个SSIS包,它们并行运行以对多个多维数据集执行增量加载.这个套餐每晚都有.偶尔我们会遇到网络问题.现在,如果SSIS连接失去连接,它会使所有软件包失败.
即使连接变为活动状态并且再次可用,它也不会自动尝试重新连接.它继续使用在执行开始时获取的相同连接信息来执行包.现在由于这个原因,所有剩余的包都失败了.为了再次连接,允许完成执行,然后有人必须手动重新处理包以获取新的连接信息.
所以我的问题是,我可以实现一个系统,如果SSIS失去网络连接,它会尝试自动检查连接在处理过程中是否可用并尝试重新连接而不是使所有软件包失败?
@billinkc的包依赖和可重启性方法
我赞成一种非常精简的执行框架方法 - 它是一个双表系统,但它已经足够了.在每个包的开头,都会触发一个启动日志记录的执行SQL任务.当SSIS包成功完成时,最后一步是关闭进程的审计行 - 另一个执行SQL任务.
因缺乏的关闭时间和SSIS不正确的运行其实现在,我知道软件包异常结束.也许它抛出了外键违规,也许网络掉线了.我真的不在乎这张桌子.唯一的功能是完成/未完成.如果它没有完成,那么当我们重新启动它时,它就是一个处理候选者.
处理你的候选人说?是的,工人包是愚蠢的 - 他们只做我上面概述的.orchestrator/parent/master包的责任是担心需要运行什么包以及以什么顺序运行.如果子包开始运行,那是因为它被告知了.它不"知道"它是否已经完成它的工作.
包执行历史记录全部在一个表中完成.它不是 SSIS将记录到的sysdtslog90/sysssislog/catalog.operation_messages表的替代品.这些表将根据您的版本保留有关包开始但未完成的实际详细信息.
为了让主人知道什么没有运行,它需要知道三件事
刷新间隔 - 您的业务需求和/或数据可用性有助于规定这一点,但我认为它需要每天运行一次.然而,魔鬼的细节,你如何定义那一天 - 从午夜,或过去24小时,或其他一些规则.无论是什么,你需要知道在部分重试变成中止并完全运行之前多久.
需要运行的内容 - 至少,这是父级将调用的所有子包的列表.我喜欢做的听起来与你的方法类似,我并行运行了很多包,但在并行块中执行了串行执行.我在那里得到了很好的并行化而没有淹没盒子.
什么运行成功 - 你已经知道答案!我们查看已开始运行但没有结束日期的任何软件包的软件包执行历史记录.任何这些记录都需要重新启动(减少刷新间隔所需的烦恼).
这是高级概念,希望不是tl;博士
选择一个数据库,任何数据库来保存这些信息.有些地方我创建了一个专用的SSISAudit数据库,有时我将它与其他元数据存储库相吻合.
这将在您的数据库中创建3个对象(不包括表的insert/update/delete方法).这两个表和一个存储过程确定了需要运行的包.将程序包主程序包名称输入需要工作的容器以及需要工作的程序包记录集(也就是自午夜以来未成功运行).
-- This is my package execution history table
CREATE TABLE
dbo.PackageHistory
(
PackageName sysname NOT NULL
, PackageID uniqueidentifier NOT NULL
, ParentPackageID uniqueidentifier NULL
, ExecutionID bigint NULL
, StartTime datetime NOT NULL
, StopTime datetime NULL
, Duration_s AS (DATEDIFF(SECOND, StartTime, StopTime))
);
CREATE TABLE dbo.PackageDependency
(
MasterPackageName sysname NOT NULL
, ContainerName sysname NOT NULL
, ChildPackageName sysname NOT NULL
, ExecutionOrderSequence int NOT NULL
, CONSTRAINT PK_PackageDependency PRIMARY KEY
CLUSTERED
(
MasterPackageName ASC
, ContainerName ASC
, ChildPackageName ASC
)
);
GO
-----------------------------------------------------------------------------
-- Function: AUD.PackageProcesssingControlListGet
-- Author: Bill Fellows
-- Date: 2016-01-18
--
-- This procedure will return a list of outstanding pacakges that need to
-- be processed for a given container. Assumes that processing is done daily
--
-- Recordsets:
-- 0 to N rows will be returned to the caller
--
-- Side-effects:
-- None
--
-- See also:
--
-- Modified:
--
-----------------------------------------------------------------------------
CREATE PROCEDURE dbo.PackageProcesssingControlListGet
(
@MasterPackageName sysname
, @ContainerName sysname
)
AS
BEGIN
SET NOCOUNT ON;
SELECT
PD.ChildPackageName
FROM
dbo.PackageDependency AS PD
LEFT OUTER JOIN
-- Find packages that have not completed
AUD.PackageControl AS PC
ON PC.PackageName = PD.ChildPackageName
-- Since midnight
AND PC.StartTime > CAST(CURRENT_TIMESTAMP AS date)
-- StopTime is only populated when package completes successfully
AND PC.StopTime IS NOT NULL
WHERE
PD.MasterPackageName = @MasterPackageName
AND PD.ContainerName = @ContainerName
AND PC.PackageName IS NULL
ORDER BY
PD.ExecutionOrderSequence ASC;
END
GO
Run Code Online (Sandbox Code Playgroud)
怎么办?让我们举一个简单的例子
这是主包的样子.原谅缺少注释,我没有安装Snagit而且我很害怕mspaint
这是PackageHistory表的插入.我在整个板上指定系统变量,没有为ParentPackageID或StopTime指定值.ExecutionID将是来自的价值System::ServerExecutionID我认为其余的是不言而喻的.
这是一个序列容器.根据需要制作尽可能多的内容并行运行.但是,只有在完成第一个完成后才能复制和粘贴,以使您的生活更轻松.
注意我定义了3个变量,它们的作用域是Sequence Container.默认情况下,在2012+中,变量是在包级别范围创建的.在2005/2008年,创建了鼠标焦点的变量.对于2012+,按正常方式创建变量,然后单击变量列表中的第二个图标,即"移动变量".将这三个移动到序列容器.
这将允许我们使用作用域规则来保持变量对其他容器隐藏.懒惰 - 我是懒惰的粉丝
3个变量.
ContainerNamePackageDependency表的列中的值.我们需要获取此容器应运行的所有包的列表.记住我们创建的存储过程,让我们使用它.SQL语句是,您需要指定执行SQL任务将返回完整结果集.
EXECUTE dbo.PackageProcesssingControlListGet ?, ?;
Run Code Online (Sandbox Code Playgroud)
在"结果集"选项卡中,将名称0映射到User :: rwWorkList
这是记录集的标准碎化.我们在上一步中填充了变量,所以让我们通过结果进行枚举.我们的结果集中将有一列,您将其映射到User :: CurrentPackageName
序列中的最后一步是实际运行我们刚刚从工作列表中弹出的包,以便执行包任务,其中包含基于变量@ [User :: CurrentPackageName]的PackageName的表达式.
此外,我将使用参数绑定选项卡(2012+)将当前的System :: ExecutionID作为参数ParentExecutionID传递给子包.
如果我们完成此任务,我们将更新ExecutionID和PackageID匹配的PackageHistory行以及StopTime IS NULL.
这实际上只是父包,除了在中间没有0到N个序列容器,我们只做子包的操作.我有一个包级别参数来接受父包ID,但您不必这样做.
看似合理吗?如果是这样,那么你所拥有的就是在dbo.PackageDependency表上做一些记账.
INSERT INTO
dbo.PackageDependency
( MasterPackageName
, ContainerName
, ChildPackageName
, ExecutionOrderSequence
)
SELECT
*
FROM
(
VALUES
(
'so_34866238.dtsx'
, 'List0'
, 'C1.dtsx'
, 10
)
,
(
'so_34866238.dtsx'
, 'List0'
, 'C2.dtsx'
, 20
)
,
(
'so_34866238.dtsx'
, 'List1'
, 'D1.dtsx'
, 10
)
) D (MasterPackageName, ContainerName, ChildPackageName, ExecutionOrderSequence);
GO
-- Test we get expected results
-- 2 rows
EXECUTE dbo.PackageProcesssingControlListGet 'so_34866238.dtsx', 'List0';
-- 1 row
EXECUTE dbo.PackageProcesssingControlListGet 'so_34866238.dtsx', 'List1';
-- NULL rows
EXECUTE dbo.PackageProcesssingControlListGet 'so_34866238.dtsx', 'List2';
Run Code Online (Sandbox Code Playgroud)
最后,虽然这还不错,但有点单调乏味.如果我这样做,我会用一些Biml自动化它的日光.今晚太晚了,让我写下来,但是在我太分心之前我会完成它.