Начиная с SQL Server 2012 структура проектов SSIS претерпела существенные изменения, путем перехода от модели управления единичными пакетами (package deployment model) к модели управления проектами (project deployment model). Последний подход упрощает и унифицирует разработку, позволяя группировать логически связанные пакеты в проекты и управлять ими как общей единицей. При развертывании проекта на сервер, все его компоненты размещаются в общей базе данных SSISDB.
Сегодняшняя статья будет посвящена процессу выполнения пакетов, развернутых в SSIS при помощи project deployment model.
В SSIS, начиная с 2012 версии обновился компонент Execute package task. Для запуска пакета, находящихся в одном проекте можно воспользоваться данным компонентом с опцией Project Reference. В выпадающем списке PackageNameFromProjectReference отобразятся все пакеты текущего проекта. Перейдя на вкладку Parameter Bindings можно задать значения переменных запускаемого пакета. Особых комментариев по работе данного компонента не требуется, за исключением одного. Данные компонент не позволяет выполнить пакет из другого проекта.
Чтобы запустить пакет из другого проекта можно воспользоваться одним из следующих способов:
Создадим тестовый SSIS проект с двумя пакетами, один из которых выполняется успешно, другой падает с ошибкой, определим для каждого пакета переменные и опубликуем проект на сервере. После публикации создадим тестовое окружение для данного проекта и привяжем его к переменным проекта.
Приступим к тестированию процедуры выполнения пакета.
Запустим оба пакета, не определяя для них никаких параметров
Сегодняшняя статья будет посвящена процессу выполнения пакетов, развернутых в SSIS при помощи project deployment model.
В SSIS, начиная с 2012 версии обновился компонент Execute package task. Для запуска пакета, находящихся в одном проекте можно воспользоваться данным компонентом с опцией Project Reference. В выпадающем списке PackageNameFromProjectReference отобразятся все пакеты текущего проекта. Перейдя на вкладку Parameter Bindings можно задать значения переменных запускаемого пакета. Особых комментариев по работе данного компонента не требуется, за исключением одного. Данные компонент не позволяет выполнить пакет из другого проекта.
Чтобы запустить пакет из другого проекта можно воспользоваться одним из следующих способов:
- T-SQL
- Утилиты dtexec и dtexecUI
- Программный код на .Net
Остановимся на первом способе. В базе данных SSISDB имеются следующие процедуры по запуску пакетов, расположенных на сервере:
- [catalog].[create_execution] - создает контекст выполнения пакета, определяя параметры запускаемого пакета
- [catalog].[set_execution_parameter_value] - позволяет изменить значения переменных запускаемого пакета
- [catalog].[start_execution] - запускает процедуру выполнения пакета
По умолчанию пакеты на сервере выполняются в асинхронном режиме. Для того, чтобы изменить данное поведение, необходимо изменить значение переменной выполнения для пакета SYNCHRONIZED в значение true.
Отдельно стоит отметить, какие типы переменных существуют для пакета. В SSISDB они имеют собственные коды (object_type):
- 20: переменная уровня проекта
- 30: переменная уровня пакета
- 50: переменная выполнения
Реализуем процедуру, которая будет запускать пакет на сервере, инкапсулируя внутренние процедуры сервера.
Сперва создадим собственный табличный тип данных для хранения определения переменных пакета.
Сперва создадим собственный табличный тип данных для хранения определения переменных пакета.
CREATE TYPE [dbo].[PackageParamListType] AS TABLE( [ObjectType] [int] NULL CHECK ([ObjectType] in(20, 30, 50)), [ParameterName] [nvarchar](128) NULL, [ParameterValue] [sql_variant] NULL )
Ниже приведен код процедуры выполнения пакета:
CREATE PROCEDURE [dbo].[LaunchPackageExecutionInSSISCatalog] @PackageName NVARCHAR(255) , @ProjectFolder NVARCHAR(255) , @ProjectName NVARCHAR(255) , @EnviromentName NVARCHAR(255) = NULL , @ParameterList PackageParamListType READONLY AS BEGIN TRY /* Определяем значение окружения проекта, если оно не задано */ DECLARE @EnvironmentID AS INT; IF(@EnviromentName is not null) SELECT @EnvironmentID = e.reference_id FROM SSISDB.catalog.environment_references e INNER JOIN catalog.projects p on e.project_id = p.project_id WHERE e.[environment_name] = @EnviromentName AND p.name = @ProjectName DECLARE @ExecutionId BIGINT = 0; EXEC [SSISDB].[catalog].[create_execution] @package_name=@PackageName, @execution_id=@ExecutionId OUTPUT, @folder_name=@ProjectFolder, @project_name=@ProjectName, @reference_id = @EnvironmentID, @use32bitruntime=False; /* object_type list: 20: project level variables 30: package level variables 50: execution parameter Определяем параметр выполнения пакета SYNCHRONIZED Так же есть параметры: DUMP_ON_EVENT DUMP_EVENT_CODE LOGGING_LEVEL DUMP_ON_ERROR */ EXEC [SSISDB].[catalog].[set_execution_parameter_value] @ExecutionId, @object_type=50, @parameter_name=N'SYNCHRONIZED', @parameter_value=1; -- true /* Определяем пользовательские параметры выполнения пакета */ DECLARE @objectType int DECLARE @parameterName nvarchar(128) DECLARE @parameterValue sql_variant DECLARE @parameterId int DECLARE paramCursor CURSOR FOR SELECT ObjectType, ParameterName, ParameterValue FROM @ParameterList OPEN paramCursor FETCH NEXT FROM paramCursor INTO @objectType, @parameterName, @parameterValue WHILE @@FETCH_STATUS = 0 BEGIN SELECT @parameterId = params.parameter_id FROM internal.object_parameters params INNER JOIN internal.projects proj ON proj.project_id = params.project_id AND proj.object_version_lsn = params.project_version_lsn AND params.object_type = @objectType AND proj.name = @ProjectName AND object_name = @PackageName AND params.parameter_name = @parameterName EXEC [catalog].[set_execution_parameter_value] @ExecutionId, @object_type=@objectType, @parameter_name=@parameterName, @parameter_value=@parameterValue; FETCH NEXT FROM paramCursor INTO @objectType, @parameterName, @parameterValue END CLOSE paramCursor DEALLOCATE paramCursor /* Выполняем пакет в синхронном режиме */ EXEC [SSISDB].[catalog].[start_execution] @ExecutionId; /* Статусы выполнения пакетов: 1: created 2: running 3: cancelled 4: failed 5: pending 6: ended unexpectedly 7: succeeded 8: stopping 9: completed Если пакет выполнен неудачно выбрасываем исключение */ IF EXISTS( SELECT * FROM [SSISDB].[catalog].[executions] WITH(NOLOCK) WHERE [execution_id] = @ExecutionId AND [status] NOT IN (2, 7, 9)) BEGIN DECLARE @msg nvarchar(200) = N'Пакет ' + @PackageName + N' в проекте ' + @ProjectName + N' расположенный в папке ' + @ProjectFolder + N' выполнен неудачно'; RAISERROR (@msg, 16, 1) END END TRY BEGIN CATCH THROW; END CATCH;
Создадим тестовый SSIS проект с двумя пакетами, один из которых выполняется успешно, другой падает с ошибкой, определим для каждого пакета переменные и опубликуем проект на сервере. После публикации создадим тестовое окружение для данного проекта и привяжем его к переменным проекта.
Запустим оба пакета, не определяя для них никаких параметров
exec [dbo].[LaunchPackageExecutionInSSISCatalog] @PackageName = N'FailPackage.dtsx', @ProjectFolder = N'Test', @ProjectName = N'SampleProject', @EnviromentName = null exec [dbo].[LaunchPackageExecutionInSSISCatalog] @PackageName = N'SuccessPackage.dtsx', @ProjectFolder = N'Test', @ProjectName = N'SampleProject', @EnviromentName = nullДля первого пакета процедура вернула ошибку, что было ожидаемым результатом. Процедура выбрасывает ошибку специально, для того, чтобы при определении в теле пакета данная процедура вызвала событие onError и мы могли бы решить, что делать с этой ошибкой дальше.
Окружение настроено следующим образом:
Теперь запустим пакеты, задав значение переменной пакета и задав переменную окружения из которой пакет получит значения.
declare @var [dbo].[PackageParamListType]; insert into @var values(30, N'SuccessPackageVariable', 10) exec [dbo].[LaunchPackageExecutionInSSISCatalog] @PackageName = N'SuccessPackage.dtsx', @ProjectFolder = N'Test', @ProjectName = N'SampleProject', @EnviromentName = null, @ParameterList = @var exec [dbo].[LaunchPackageExecutionInSSISCatalog] @PackageName = N'SuccessPackage.dtsx', @ProjectFolder = N'Test', @ProjectName = N'SampleProject', @EnviromentName = N'SampleEnviroment'
Ну собственно и всё.
Для того, чтобы запустить пакет из другого пакета можно воспользоваться компонентом Exceute SQL Task и вставить в него вызов процедуры, аналогично тому, как это описано выше.