Repository: mrpaulandrew/procfwk
Branch: master
Commit: f51cb458ef7e
Files: 344
Total size: 2.6 MB
Directory structure:
gitextract_8_ebrzfj/
├── .gitattributes
├── .github/
│ ├── FUNDING.yml
│ └── ISSUE_TEMPLATE/
│ ├── bug-found.md
│ ├── feature-request.md
│ └── help---support-request.md
├── .gitignore
├── .vscode/
│ ├── extensions.json
│ ├── launch.json
│ ├── settings.json
│ └── tasks.json
├── ARM Templates/
│ ├── Data Factory/
│ │ ├── v1.0 Export.json
│ │ ├── v1.1 Export.json
│ │ ├── v1.2 Export.json
│ │ ├── v1.3 Export.json
│ │ ├── v1.4 Export.json
│ │ ├── v1.5 Export.json
│ │ ├── v1.6 Export.json
│ │ ├── v1.7 Export.json
│ │ ├── v1.8 Export.json
│ │ ├── v1.8.3 Export.json
│ │ ├── v1.8.5 Export.json
│ │ ├── v1.8.6 Export.json
│ │ ├── v1.9 Export.json
│ │ ├── v1.9.1 Export.json
│ │ ├── v1.9.2 Export.json
│ │ └── v2.0 Export.json
│ ├── Functions App/
│ │ └── v1.6 Export.json
│ ├── SQL Database/
│ │ └── v1.6 Export.json
│ └── Synapse/
│ └── v2.0 Export.json
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── DataFactory/
│ ├── dataset/
│ │ └── GetSetMetadata.json
│ ├── factory/
│ │ └── FrameworkFactory.json
│ ├── integrationRuntime/
│ │ └── AzureIR-UKSouth.json
│ ├── linkedService/
│ │ ├── FrameworkFunctions.json
│ │ ├── Keys.json
│ │ └── SupportDatabase.json
│ ├── pipeline/
│ │ ├── 01-Grandparent.json
│ │ ├── 02-Parent.json
│ │ ├── 03-Child.json
│ │ ├── 04-Infant.json
│ │ ├── Check For Running Pipeline.json
│ │ ├── Email Sender.json
│ │ ├── Intentional Error.json
│ │ ├── Throw Exception.json
│ │ ├── Wait 1.json
│ │ ├── Wait 10.json
│ │ ├── Wait 2.json
│ │ ├── Wait 3.json
│ │ ├── Wait 4.json
│ │ ├── Wait 5.json
│ │ ├── Wait 6.json
│ │ ├── Wait 7.json
│ │ ├── Wait 8.json
│ │ └── Wait 9.json
│ └── trigger/
│ └── FunctionalTestingTrigger.json
├── DeploymentTools/
│ ├── DataFactory/
│ │ ├── DeployProcFwkComponents.ps1
│ │ ├── DeployProcFwkComponents_Old.ps1
│ │ ├── Get Pipelines.ps1
│ │ ├── GlobalVars.ps1
│ │ ├── PopulatePipelinesInDb.ps1
│ │ ├── ProcFwkComponents.json
│ │ └── config-all.csv
│ ├── Deployment.targets
│ └── DeploymentTools.deployproj
├── FactoryTesting/
│ ├── FactoryTesting.csproj
│ ├── Helpers/
│ │ ├── CoverageHelper.cs
│ │ ├── DataFactoryHelper.cs
│ │ ├── DatabaseHelper.cs
│ │ ├── PipelineRunHelper.cs
│ │ └── SettingsHelper.cs
│ ├── Pipelines/
│ │ ├── 01-Grandparent/
│ │ │ ├── Given300WorkerPipelines.cs
│ │ │ ├── Given600WorkerPipelineConcurrentBatches.cs
│ │ │ ├── GivenOneWorkerPipeline.cs
│ │ │ └── GrandparentHelper.cs
│ │ ├── 02-Parent/
│ │ │ ├── Given20ConcurrentBatchesFor1000WorkerPipelines.cs
│ │ │ ├── GivenAlreadyRunning.cs
│ │ │ ├── GivenBatchExecutionsForConcurrentBatches.cs
│ │ │ ├── GivenBatchExecutionsForConcurrentBatchesAlreadyRunning.cs
│ │ │ ├── GivenBatchExecutionsForConcurrentBatchesWithSimpleFailureHandling.cs
│ │ │ ├── GivenBatchExecutionsForConcurrentBatchesWithSimpleFailureHandlingAndRestart.cs
│ │ │ ├── GivenBatchExecutionsForConcurrentBatchesWithSimpleFailureHandlingAndRestartOveride.cs
│ │ │ ├── GivenBatchExecutionsForSingleBatch.cs
│ │ │ ├── GivenCancelledWorkerAndRestart.cs
│ │ │ ├── GivenCancelledWorkerInOneExecutionStage.cs
│ │ │ ├── GivenCancelledWorkerThatBlocks.cs
│ │ │ ├── GivenCancelledWorkerThatDoesntBlock.cs
│ │ │ ├── GivenCleanUpForCancelledWorkerAndRestart.cs
│ │ │ ├── GivenCleanUpForSuccessfulWorkersAndRestart.cs
│ │ │ ├── GivenDependencyChainFailureHandling.cs
│ │ │ ├── GivenDependencyChainFailureHandlingAndRestart.cs
│ │ │ ├── GivenDisabledBatches.cs
│ │ │ ├── GivenDisabledPipelines.cs
│ │ │ ├── GivenDisabledStages.cs
│ │ │ ├── GivenNoErrorsAndSPNStoredInDatabase.cs
│ │ │ ├── GivenNoErrorsAndSPNStoredInKeyVault.cs
│ │ │ ├── GivenNoFailureHandling.cs
│ │ │ ├── GivenNoPipelineParameters.cs
│ │ │ ├── GivenOneExecutionStage.cs
│ │ │ ├── GivenSimpleFailureHandling.cs
│ │ │ ├── GivenSimpleFailureHandlingAndRestart.cs
│ │ │ ├── GivenSimpleFailureHandlingAndRestartOveride.cs
│ │ │ └── ParentHelper.cs
│ │ └── Utilities/
│ │ ├── GivenCheckForRunningPipeline.cs
│ │ ├── GivenEmailSender.cs
│ │ ├── GivenThrowException.cs
│ │ └── UtilitiesHelper.cs
│ ├── dev.runsettings
│ ├── multi.runsettings
│ └── test.runsettings
├── Functions/
│ ├── .vscode/
│ │ ├── extensions.json
│ │ ├── launch.json
│ │ ├── settings.json
│ │ └── tasks.json
│ ├── Functions/
│ │ ├── CancelPipeline.cs
│ │ ├── CheckPipelineStatus.cs
│ │ ├── ExecutePipeline.cs
│ │ ├── GetActivityErrors.cs
│ │ ├── SendEmail.cs
│ │ └── ValidatePipeline.cs
│ ├── Functions.csproj
│ ├── Helpers/
│ │ ├── BodyReader.cs
│ │ ├── InvalidRequestException.cs
│ │ ├── KeyVaultClient.cs
│ │ ├── PipelineRequest.cs
│ │ ├── PipelineRunRequest.cs
│ │ └── SMTPClient.cs
│ ├── Properties/
│ │ └── ServiceDependencies/
│ │ ├── FrameworkSupportFunctions - Zip Deploy/
│ │ │ └── profile.arm.json
│ │ └── FrameworkSupportFunctionsBig - Web Deploy/
│ │ └── profile.arm.json
│ ├── Services/
│ │ ├── AzureDataFactoryService.cs
│ │ ├── AzureSynapseService.cs
│ │ ├── PipelineService.cs
│ │ ├── PipelineServiceType.cs
│ │ └── Returns/
│ │ ├── PipelineDescription.cs
│ │ ├── PipelineErrorDetail.cs
│ │ └── PipelineRunStatus.cs
│ ├── host.json
│ └── template_local.settings.json
├── Images/
│ └── procfwk Designs.vsdx
├── LICENSE
├── MetadataDB/
│ ├── MetadataDB.refactorlog
│ ├── MetadataDB.sqlproj
│ ├── Scripts/
│ │ ├── Alter Database Scale.sql
│ │ ├── Handy Selects.sql
│ │ ├── LogData/
│ │ │ ├── ErrorLogBackup.sql
│ │ │ ├── ErrorLogRestore.sql
│ │ │ ├── ExecutionLogBackup.sql
│ │ │ └── ExecutionLogRestore.sql
│ │ ├── Metadata/
│ │ │ ├── AlertOutcomes.sql
│ │ │ ├── DeleteAll.sql
│ │ │ ├── DropLegacyObjects.sql
│ │ │ ├── DropLegacyTables.sql
│ │ │ ├── Orchestrators.sql
│ │ │ ├── PipelineDependencies.sql
│ │ │ ├── PipelineParams.sql
│ │ │ ├── Pipelines.sql
│ │ │ ├── Properties.sql
│ │ │ ├── RecipientAlertsLink.sql
│ │ │ ├── Recipients.sql
│ │ │ ├── ReplaceDataFactorys.sql
│ │ │ ├── Stages.sql
│ │ │ ├── TransferHelperObjects.sql
│ │ │ └── TransferReportingObjects.sql
│ │ ├── Script.PostDeployment.sql
│ │ ├── Script.PreDeployment.sql
│ │ └── Script.SetLocalAuthenticationDetails.sql
│ ├── Security/
│ │ ├── procfwk.sql
│ │ ├── procfwkHelpers.sql
│ │ ├── procfwkReporting.sql
│ │ ├── procfwkTesting.sql
│ │ └── procfwkuser Role.sql
│ ├── dbo/
│ │ ├── Stored Procedures/
│ │ │ ├── DemoModePrecursor.sql
│ │ │ ├── ExampleCustomExecutionPrecursor.sql
│ │ │ └── FailProcedure.sql
│ │ └── Tables/
│ │ └── ServicePrincipals.sql
│ ├── procfwk/
│ │ ├── Functions/
│ │ │ └── GetPropertyValueInternal.sql
│ │ ├── Stored Procedures/
│ │ │ ├── BatchWrapper.sql
│ │ │ ├── CheckForBlockedPipelines.sql
│ │ │ ├── CheckForEmailAlerts.sql
│ │ │ ├── CheckMetadataIntegrity.sql
│ │ │ ├── CheckPreviousExeuction.sql
│ │ │ ├── CreateNewExecution.sql
│ │ │ ├── ExecutePrecursorProcedure.sql
│ │ │ ├── ExecutionWrapper.sql
│ │ │ ├── GetEmailAlertParts.sql
│ │ │ ├── GetFrameworkOrchestratorDetails.sql
│ │ │ ├── GetPipelineParameters.sql
│ │ │ ├── GetPipelinesInStage.sql
│ │ │ ├── GetPropertyValue.sql
│ │ │ ├── GetStages.sql
│ │ │ ├── GetWorkerAuthDetails.sql
│ │ │ ├── GetWorkerDetailsWrapper.sql
│ │ │ ├── GetWorkerPipelineDetails.sql
│ │ │ ├── ResetExecution.sql
│ │ │ ├── SetErrorLogDetails.sql
│ │ │ ├── SetExecutionBlockDependants.sql
│ │ │ ├── SetLogActivityFailed.sql
│ │ │ ├── SetLogPipelineCancelled.sql
│ │ │ ├── SetLogPipelineChecking.sql
│ │ │ ├── SetLogPipelineFailed.sql
│ │ │ ├── SetLogPipelineLastStatusCheck.sql
│ │ │ ├── SetLogPipelineRunId.sql
│ │ │ ├── SetLogPipelineRunning.sql
│ │ │ ├── SetLogPipelineSuccess.sql
│ │ │ ├── SetLogPipelineUnknown.sql
│ │ │ ├── SetLogPipelineValidating.sql
│ │ │ ├── SetLogStagePreparing.sql
│ │ │ └── UpdateExecutionLog.sql
│ │ ├── Synonyms/
│ │ │ ├── AddPipelineDependant.sql
│ │ │ ├── AddProperty.sql
│ │ │ ├── AddRecipientPipelineAlerts.sql
│ │ │ ├── AddServicePrincipal.sql
│ │ │ ├── AddServicePrincipalUrls.sql
│ │ │ ├── AddServicePrincipalWrapper.sql
│ │ │ ├── AverageStageDuration.sql
│ │ │ ├── CheckForValidURL.sql
│ │ │ ├── CheckStageAndPiplineIntegrity.sql
│ │ │ ├── CompleteExecutionErrorLog.sql
│ │ │ ├── CompleteExecutionLog.sql
│ │ │ ├── CurrentExecutionSummary.sql
│ │ │ ├── DataFactoryDetails.sql
│ │ │ ├── DeleteRecipientAlerts.sql
│ │ │ ├── DeleteServicePrincipal.sql
│ │ │ ├── GetExecutionDetails.sql
│ │ │ ├── LastExecution.sql
│ │ │ ├── LastExecutionSummary.sql
│ │ │ ├── PipelineDependencyChains.sql
│ │ │ ├── PipelineProcesses.sql
│ │ │ ├── ProcessingStageDetails.sql
│ │ │ └── WorkerParallelismOverTime.sql
│ │ ├── Tables/
│ │ │ ├── AlertOutcomes.sql
│ │ │ ├── BatchExecution.sql
│ │ │ ├── BatchStageLink.sql
│ │ │ ├── Batches.sql
│ │ │ ├── CurrentExecution.sql
│ │ │ ├── ErrorLog.sql
│ │ │ ├── ExecutionLog.sql
│ │ │ ├── Orchestrators.sql
│ │ │ ├── PipelineAlertLink.sql
│ │ │ ├── PipelineAuthLink.sql
│ │ │ ├── PipelineDependencies.sql
│ │ │ ├── PipelineParameters.sql
│ │ │ ├── Pipelines.sql
│ │ │ ├── Properties.sql
│ │ │ ├── Recipients.sql
│ │ │ ├── Stages.sql
│ │ │ ├── Subscriptions.sql
│ │ │ └── Tenants.sql
│ │ └── Views/
│ │ ├── CurrentProperties.sql
│ │ ├── DataFactorys.sql
│ │ └── PipelineParameterDataSizes.sql
│ ├── procfwkHelpers/
│ │ ├── Functions/
│ │ │ └── CheckForValidURL.sql
│ │ ├── Stored Procedures/
│ │ │ ├── AddPipelineDependant.sql
│ │ │ ├── AddPipelineViaPowerShell.sql
│ │ │ ├── AddProperty.sql
│ │ │ ├── AddRecipientPipelineAlerts.sql
│ │ │ ├── AddServicePrincipal.sql
│ │ │ ├── AddServicePrincipalUrls.sql
│ │ │ ├── AddServicePrincipalWrapper.sql
│ │ │ ├── CheckStageAndPiplineIntegrity.sql
│ │ │ ├── DeleteMetadataWithIntegrity.sql
│ │ │ ├── DeleteMetadataWithoutIntegrity.sql
│ │ │ ├── DeleteRecipientAlerts.sql
│ │ │ ├── DeleteServicePrincipal.sql
│ │ │ ├── GetExecutionDetails.sql
│ │ │ ├── GetServicePrincipal.sql
│ │ │ ├── SetDefaultAlertOutcomes.sql
│ │ │ ├── SetDefaultBatchStageLink.sql
│ │ │ ├── SetDefaultBatches.sql
│ │ │ ├── SetDefaultOrchestrators.sql
│ │ │ ├── SetDefaultPipelineDependants.sql
│ │ │ ├── SetDefaultPipelineParameters.sql
│ │ │ ├── SetDefaultPipelines.sql
│ │ │ ├── SetDefaultProperties.sql
│ │ │ ├── SetDefaultRecipientPipelineAlerts.sql
│ │ │ ├── SetDefaultRecipients.sql
│ │ │ ├── SetDefaultStages.sql
│ │ │ ├── SetDefaultSubscription.sql
│ │ │ └── SetDefaultTenant.sql
│ │ └── Views/
│ │ └── PipelineDependencyChains.sql
│ ├── procfwkReporting/
│ │ └── Views/
│ │ ├── AverageStageDuration.sql
│ │ ├── CompleteExecutionErrorLog.sql
│ │ ├── CompleteExecutionLog.sql
│ │ ├── CurrentExecutionSummary.sql
│ │ ├── LastExecution.sql
│ │ ├── LastExecutionSummary.sql
│ │ └── WorkerParallelismOverTime.sql
│ └── procfwkTesting/
│ └── Stored Procedures/
│ ├── Add20BatchesFor1000Workers.sql
│ ├── Add300WorkerPipelineBatches.sql
│ ├── Add300WorkerPipelines.sql
│ ├── CleanUpMetadata.sql
│ ├── GetRunIdWhenAvailable.sql
│ └── ResetMetadata.sql
├── MetadataDBTests/
│ ├── MetadataDBTests.sqlproj
│ ├── Scripts/
│ │ ├── Script.PostDeployment.sql
│ │ └── Script.PreDeployment.sql
│ ├── _TestClasses/
│ │ ├── procfwk_GetPropertyValue.sql
│ │ └── procfwk_GetPropertyValueInternal.sql
│ ├── procfwk_GetPropertyValue/
│ │ ├── setup.sql
│ │ ├── test WHEN property does not exist THEN error raised.sql
│ │ ├── test WHEN property exists THEN property value returned.sql
│ │ ├── test WHEN property invalidated THEN error raised.sql
│ │ └── test WHEN property name is null THEN error raised.sql
│ ├── procfwk_GetPropertyValueInternal/
│ │ ├── test WHEN property does not exist THEN empty string returned.sql
│ │ ├── test WHEN property exists THEN property value returned.sql
│ │ └── test WHEN property name is null THEN empty string returned.sql
│ └── tSQLt.dacpac
├── Notebooks/
│ ├── Databricks - Throw Exception.scala
│ └── Metadata Guide and Handy Code Snippets.ipynb
├── ProcessingFramework.sln
├── README.md
├── Reporting/
│ ├── PowerBI/
│ │ ├── Executions Overview.pbit
│ │ └── Executions Overview.pbix
│ └── Scoping-Template-LDI-Blank.docx
└── Synapse/
├── dataflow/
│ └── MDF _Order_Count.json
├── dataset/
│ └── GetSetMetadata.json
├── factory/
│ └── FrameworkFactory.json
├── integrationRuntime/
│ └── AutoResolveIntegrationRuntime.json
├── linkedService/
│ ├── FrameworkFunctions.json
│ ├── Keys.json
│ ├── SupportDatabase.json
│ ├── covid-tracking.json
│ ├── procfwkforsynapse-WorkspaceDefaultSqlServer.json
│ └── procfwkforsynapse-WorkspaceDefaultStorage.json
├── notebook/
│ └── Getting Started with Delta Lake.json
├── pipeline/
│ ├── 01-Grandparent.json
│ ├── 02-Parent.json
│ ├── 03-Child.json
│ ├── 04-Infant.json
│ ├── Check For Running Pipeline.json
│ ├── Email Sender.json
│ ├── Intentional Error.json
│ ├── Throw Exception.json
│ ├── Wait 1.json
│ ├── Wait 10.json
│ ├── Wait 2.json
│ ├── Wait 3.json
│ ├── Wait 4.json
│ ├── Wait 5.json
│ ├── Wait 6.json
│ ├── Wait 7.json
│ ├── Wait 8.json
│ └── Wait 9.json
└── trigger/
└── FunctionalTestingTrigger.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
# Auto detect text files and perform LF normalization
* text=auto
================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms
github: [mrpaulandrew]
================================================
FILE: .github/ISSUE_TEMPLATE/bug-found.md
================================================
---
name: Bug Found
about: Tell me about the bug you've found in the procfwk please
title: ''
labels: bug
assignees: mrpaulandrew
---
**Describe the bug**
A clear and concise description of what the bug is.
**Affected services**
Which resource within the processing framework does this affect?
* Data Factory/Synapse
* SQL Database
* Functions
* All of them
* Other
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behaviour**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Additional context**
Add any other context about the problem here.
================================================
FILE: .github/ISSUE_TEMPLATE/feature-request.md
================================================
---
name: Feature Request
about: Tell me about your idea to enhance the procfwk please
title: ''
labels: enhancement
assignees: mrpaulandrew
---
**Share Your Idea**
All features considered.
================================================
FILE: .github/ISSUE_TEMPLATE/help---support-request.md
================================================
---
name: Help & Support Request
about: Tell me about the problem or error you are facing when using the procfwk
title: ''
labels: help wanted
assignees: mrpaulandrew
---
**Describe the error**
A clear and concise description of what the bug is.
**Error message**
An output of the error message presented.
**Affected services**
Which resource within the processing framework does this affect?
* Data Factory/Synapse
* SQL Database
* Functions
* All of them
* Other
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Screenshots**
If applicable, add screenshots to help explain your problem.
================================================
FILE: .gitignore
================================================
################################################################################
# This .gitignore file was automatically created by Microsoft(R) Visual Studio.
################################################################################
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
## https://stackoverflow.com/questions/30868544/gitignore-wont-ignore-vs-folder-for-visual-studio-2015-rc-on-windows7-8/39520183
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
*.jfm
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
/PipelineExecutor/local.settings.json
/Functions/local.settings.json
/docs
================================================
FILE: .vscode/extensions.json
================================================
{
"recommendations": [
"ms-azuretools.vscode-azurefunctions",
"ms-vscode.csharp"
]
}
================================================
FILE: .vscode/launch.json
================================================
{
"version": "0.2.0",
"configurations": [
{
"name": "Attach to .NET Functions",
"type": "coreclr",
"request": "attach",
"processId": "${command:azureFunctions.pickProcess}"
}
]
}
================================================
FILE: .vscode/settings.json
================================================
{
"azureFunctions.deploySubpath": "PipelineExecutor/bin/Release/netcoreapp3.1/publish",
"azureFunctions.projectLanguage": "C#",
"azureFunctions.projectRuntime": "~3",
"debug.internalConsoleOptions": "neverOpen",
"azureFunctions.preDeployTask": "publish"
}
================================================
FILE: .vscode/tasks.json
================================================
{
"version": "2.0.0",
"tasks": [
{
"label": "clean",
"command": "dotnet",
"args": [
"clean",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"type": "process",
"problemMatcher": "$msCompile",
"options": {
"cwd": "${workspaceFolder}/PipelineExecutor"
}
},
{
"label": "build",
"command": "dotnet",
"args": [
"build",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"type": "process",
"dependsOn": "clean",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": "$msCompile",
"options": {
"cwd": "${workspaceFolder}/PipelineExecutor"
}
},
{
"label": "clean release",
"command": "dotnet",
"args": [
"clean",
"--configuration",
"Release",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"type": "process",
"problemMatcher": "$msCompile",
"options": {
"cwd": "${workspaceFolder}/PipelineExecutor"
}
},
{
"label": "publish",
"command": "dotnet",
"args": [
"publish",
"--configuration",
"Release",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"type": "process",
"dependsOn": "clean release",
"problemMatcher": "$msCompile",
"options": {
"cwd": "${workspaceFolder}/PipelineExecutor"
}
},
{
"type": "func",
"dependsOn": "build",
"options": {
"cwd": "${workspaceFolder}/PipelineExecutor/bin/Debug/netcoreapp3.1"
},
"command": "host start",
"isBackground": true,
"problemMatcher": "$func-watch"
}
]
}
================================================
FILE: ARM Templates/Data Factory/v1.0 Export.json
================================================
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"factoryName": {
"type": "string",
"metadata": "Data Factory name"
},
"Keys_properties_typeProperties_baseUrl": {
"type": "string"
},
"SupportDatabase_properties_typeProperties_connectionString_secretName": {
"type": "string"
}
},
"variables": {
"factoryId": "[concat('Microsoft.DataFactory/factories/', parameters('factoryName'))]"
},
"resources": [
{
"name": "[concat(parameters('factoryName'), '/BootStrap')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"activities": [
{
"name": "Get Stages",
"type": "Lookup",
"dependsOn": [
{
"activity": "Create New Execution",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetProcessStages]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@activity('Create New Execution').output.firstRow.ExecutionId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Stages",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Stages",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Stages').output.value",
"type": "Expression"
},
"isSequential": true,
"activities": [
{
"name": "Stage Executor",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Log Stage Start",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "Executor",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"StageId": {
"value": "@item().StageId",
"type": "Expression"
},
"ExecutionId": {
"value": "@activity('Create New Execution').output.firstRow.ExecutionId",
"type": "Expression"
}
}
}
},
{
"name": "Log Stage Start",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogStageStart]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@activity('Create New Execution').output.firstRow.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Create New Execution",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[CreateNewExecution]",
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Update Execution Log",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Stages",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[UpdateExecutionLog]"
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
],
"folder": {
"name": "Framework"
},
"annotations": []
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]",
"[concat(variables('factoryId'), '/pipelines/Executor')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Child 1')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"activities": [
{
"name": "Wait1",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": 1
}
}
],
"folder": {
"name": "Child Pipelines"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Child 2')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"activities": [
{
"name": "Wait1",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": 1
}
}
],
"folder": {
"name": "Child Pipelines"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Child 3')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"activities": [
{
"name": "Wait1",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": 1
}
}
],
"folder": {
"name": "Child Pipelines"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Child 4')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"activities": [
{
"name": "Wait1",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": 1
}
}
],
"folder": {
"name": "Child Pipelines"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Child 5')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"activities": [
{
"name": "Wait1",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": 1
}
}
],
"folder": {
"name": "Child Pipelines"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Child 6')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"activities": [
{
"name": "Wait1",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": 1
}
}
],
"folder": {
"name": "Child Pipelines"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Executor')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"activities": [
{
"name": "Get Pipelines",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelinesInStage]",
"storedProcedureParameters": {
"StageId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Pipelines",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Pipelines",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Pipelines').output.value",
"type": "Expression"
},
"activities": [
{
"name": "Execute Pipeline",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Set Body",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Log Pipeline Running",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "ExecutePipeline",
"method": "POST",
"headers": {},
"body": {
"value": "@variables('FunctionBody')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "PipelineExecutor",
"type": "LinkedServiceReference"
}
},
{
"name": "Set Body",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Pipeline Params",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "FunctionBody",
"value": {
"value": "@concat('\n{\n\t\"tenantId\": \"1234-1234-1234-1234-1234\",\n\t\"applicationId\": \"1234-1234-1234-1234-1234\",\n\t\"authenticationKey\": \"Passw0rd123!\",\n\t\"subscriptionId\": \"1234-1234-1234-1234-1234\",\n\t\"resourceGroup\": \"Demos\",\n\t\"factoryName\": \"FunFactory\",\n\t\"pipelineName\": \"',item().PipelineName,'\"',activity('Get Pipeline Params').output.firstRow.Params,'\n}')",
"type": "Expression"
}
}
},
{
"name": "Get Pipeline Params",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelineParameters]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Pipeline Running",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Pipeline Success",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Pipeline",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineSuccess]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Pipeline Failure",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Pipeline",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
}
],
"parameters": {
"StageId": {
"type": "int"
},
"ExecutionId": {
"type": "string"
}
},
"variables": {
"FunctionBody": {
"type": "String"
}
},
"folder": {
"name": "Framework"
},
"annotations": []
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/PipelineExecutor')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Grandparent')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"activities": [
{
"name": "Framework Processing",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "BootStrap",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {}
}
}
],
"annotations": []
},
"dependsOn": [
"[concat(variables('factoryId'), '/pipelines/BootStrap')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/GetSetMetadata')]",
"type": "Microsoft.DataFactory/factories/datasets",
"apiVersion": "2018-06-01",
"properties": {
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
},
"annotations": [],
"type": "AzureSqlTable",
"schema": [],
"typeProperties": {}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Keys')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"annotations": [],
"type": "AzureKeyVault",
"typeProperties": {
"baseUrl": "[parameters('Keys_properties_typeProperties_baseUrl')]"
}
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/PipelineExecutor')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"annotations": [],
"type": "AzureFunction",
"typeProperties": {
"functionAppUrl": "https://pipelineexecutor.azurewebsites.net",
"functionKey": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "ExecutorFunctionAppKey"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/SupportDatabase')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"annotations": [],
"type": "AzureSqlDatabase",
"typeProperties": {
"connectionString": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "[parameters('SupportDatabase_properties_typeProperties_connectionString_secretName')]"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
}
]
}
================================================
FILE: ARM Templates/Data Factory/v1.1 Export.json
================================================
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"factoryName": {
"type": "string",
"metadata": "Data Factory name",
"defaultValue": ""
},
"Keys_properties_typeProperties_baseUrl": {
"type": "string",
"defaultValue": ""
},
"SupportDatabase_properties_typeProperties_connectionString_secretName": {
"type": "string",
"defaultValue": ""
}
},
"variables": {
"factoryId": "[concat('Microsoft.DataFactory/factories/', parameters('factoryName'))]"
},
"resources": [
{
"name": "[concat(parameters('factoryName'), '/BootStrap')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"activities": [
{
"name": "Get Stages",
"type": "Lookup",
"dependsOn": [
{
"activity": "Create New Execution",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetProcessStages]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@activity('Create New Execution').output.firstRow.ExecutionId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Stages",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Stages",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Tenant Id",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Subscription Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Stages').output.value",
"type": "Expression"
},
"isSequential": true,
"activities": [
{
"name": "Stage Executor",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Log Stage Start",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "Executor",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"StageId": {
"value": "@item().StageId",
"type": "Expression"
},
"ExecutionId": {
"value": "@activity('Create New Execution').output.firstRow.ExecutionId",
"type": "Expression"
},
"TenantId": {
"value": "@activity('Get Tenant Id').output.firstRow.PropertyValue",
"type": "Expression"
},
"SubscriptionId": {
"value": "@activity('Get Subscription Id').output.firstRow.PropertyValue",
"type": "Expression"
}
}
}
},
{
"name": "Log Stage Start",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogStageStart]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@activity('Create New Execution').output.firstRow.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Create New Execution",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[CreateNewExecution]",
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Update Execution Log",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Stages",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[UpdateExecutionLog]"
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Tenant Id",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "TenantId"
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": true
}
},
{
"name": "Get Subscription Id",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "SubscriptionId"
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
}
],
"folder": {
"name": "Framework"
},
"annotations": []
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]",
"[concat(variables('factoryId'), '/pipelines/Executor')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Child 1')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"activities": [
{
"name": "Wait1",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": 1
}
}
],
"folder": {
"name": "Child Pipelines"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Child 2')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"activities": [
{
"name": "Wait1",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": 1
}
}
],
"folder": {
"name": "Child Pipelines"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Child 3')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"activities": [
{
"name": "Wait1",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": 1
}
}
],
"folder": {
"name": "Child Pipelines"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Child 4')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"activities": [
{
"name": "Wait1",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": 1
}
}
],
"folder": {
"name": "Child Pipelines"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Child 5')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"activities": [
{
"name": "Wait1",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": 1
}
}
],
"folder": {
"name": "Child Pipelines"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Child 6')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"activities": [
{
"name": "Wait1",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": 1
}
}
],
"folder": {
"name": "Child Pipelines"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Executor')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"activities": [
{
"name": "Get Pipelines",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelinesInStage]",
"storedProcedureParameters": {
"StageId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Pipelines",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Pipelines",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Pipelines').output.value",
"type": "Expression"
},
"activities": [
{
"name": "Execute Pipeline",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Log Pipeline Running",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Pipeline Params",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get SPN Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "ExecutePipeline",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n\t\"tenantId\": \"',pipeline().parameters.TenantId,'\",\n\t\"applicationId\": \"',activity('Get SPN Details').output.firstRow.Id,'\",\n\t\"authenticationKey\": \"',activity('Get SPN Details').output.firstRow.Secret,'\",\n\t\"subscriptionId\": \"',pipeline().parameters.SubscriptionId,'\",\n\t\"resourceGroup\": \"',item().ResourceGroupName,'\",\n\t\"factoryName\": \"',item().DataFactoryName,'\",\n\t\"pipelineName\": \"',item().PipelineName,'\"',activity('Get Pipeline Params').output.firstRow.Params,'\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "PipelineExecutor",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Pipeline Params",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelineParameters]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Pipeline Running",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Pipeline Success",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Pipeline",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineSuccess]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Pipeline Failure",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Pipeline",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get SPN Details",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetServicePrincipal]",
"storedProcedureParameters": {
"DataFactory": {
"type": "String",
"value": {
"value": "@item().DataFactoryName",
"type": "Expression"
}
},
"PipelineName": {
"type": "String",
"value": {
"value": "@item().PipelineName",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
}
]
}
}
],
"parameters": {
"StageId": {
"type": "int"
},
"ExecutionId": {
"type": "string"
},
"TenantId": {
"type": "string"
},
"SubscriptionId": {
"type": "string"
}
},
"variables": {
"FunctionBody": {
"type": "String"
}
},
"folder": {
"name": "Framework"
},
"annotations": []
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/PipelineExecutor')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Grandparent')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"activities": [
{
"name": "Framework Processing",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "BootStrap",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {}
}
}
],
"annotations": []
},
"dependsOn": [
"[concat(variables('factoryId'), '/pipelines/BootStrap')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/GetSetMetadata')]",
"type": "Microsoft.DataFactory/factories/datasets",
"apiVersion": "2018-06-01",
"properties": {
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
},
"annotations": [],
"type": "AzureSqlTable",
"schema": [],
"typeProperties": {}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Keys')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"annotations": [],
"type": "AzureKeyVault",
"typeProperties": {
"baseUrl": "[parameters('Keys_properties_typeProperties_baseUrl')]"
}
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/PipelineExecutor')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"annotations": [],
"type": "AzureFunction",
"typeProperties": {
"functionAppUrl": "https://pipelineexecutor.azurewebsites.net",
"functionKey": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "ExecutorFunctionAppKey"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/SupportDatabase')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"annotations": [],
"type": "AzureSqlDatabase",
"typeProperties": {
"connectionString": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "[parameters('SupportDatabase_properties_typeProperties_connectionString_secretName')]"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
}
]
}
================================================
FILE: ARM Templates/Data Factory/v1.2 Export.json
================================================
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"factoryName": {
"type": "string",
"metadata": "Data Factory name",
"defaultValue": ""
},
"Keys_properties_typeProperties_baseUrl": {
"type": "string",
"defaultValue": ""
},
"SupportDatabase_properties_typeProperties_connectionString_secretName": {
"type": "string",
"defaultValue": ""
}
},
"variables": {
"factoryId": "[concat('Microsoft.DataFactory/factories/', parameters('factoryName'))]"
},
"resources": [
{
"name": "[concat(parameters('factoryName'), '/01 Grandparent')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"activities": [
{
"name": "Framework Processing",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "02 Parent",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {}
}
}
],
"folder": {
"name": "_ProcFwk"
},
"annotations": []
},
"dependsOn": [
"[concat(variables('factoryId'), '/pipelines/02 Parent')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/02 Parent')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk parent pipeline used to bootstrap the orchestration framework in perform the first level ForEach calls in sequence for the metadata stages.",
"activities": [
{
"name": "Get Stages",
"description": "Returns a distinct list of execution stages within the framework metadata.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Execution Wrapper",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetStages]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Stages",
"description": "Top level ForEach to sequentially call all processing stages within the framework metadata. Items for iteration passed from the Get Stages lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Stages",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Tenant Id",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Subscription Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Stages').output.value",
"type": "Expression"
},
"isSequential": true,
"activities": [
{
"name": "Stage Executor",
"description": "Call to the framework generic child pipeline for a given execution stage.",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Log Stage Preparing",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "03 Child",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"StageId": {
"value": "@item().StageId",
"type": "Expression"
},
"ExecutionId": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
},
"TenantId": {
"value": "@activity('Get Tenant Id').output.firstRow.PropertyValue",
"type": "Expression"
},
"SubscriptionId": {
"value": "@activity('Get Subscription Id').output.firstRow.PropertyValue",
"type": "Expression"
}
}
}
},
{
"name": "Log Stage Preparing",
"description": "Update the current execution table flagging all pipelines within the stage as preparing.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Check for Blockers",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogStagePreparing]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check for Blockers",
"description": "Used to double check and stop the next execution stage if failures and blockers have be incurred. Without this step processing would continue regardless of upstream failures.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[CheckForBlockedPipelines]",
"storedProcedureParameters": {
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Execution Wrapper",
"description": "Wrapper to reset and restart processing or create a completely new execution instance of the framework metadata.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[ExecutionWrapper]",
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Archive Execution Log",
"description": "After a successful execution run the current execution metadata is moved to the long term logging table by this stored procedure call.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Stages",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[UpdateExecutionLog]"
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Tenant Id",
"description": "Returning the Azure Tenant Id from the metadata properties table.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "TenantId"
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": true
}
},
{
"name": "Get Subscription Id",
"description": "Returning the Azure Subscription Id from the metadata properties table.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "SubscriptionId"
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
}
],
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]",
"[concat(variables('factoryId'), '/pipelines/03 Child')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/03 Child')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk child pipeline used to execute processing pipelines within a given execution stage. This pipeline will be called multi times in parallel.",
"activities": [
{
"name": "Get Pipelines",
"description": "Returns all pipelines from the metadata to be executed within a given processing stage.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelinesInStage]",
"storedProcedureParameters": {
"StageId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Pipelines",
"description": "Second level ForEach to run in parallel all pipelines within the stage. Items for iteration passed from the Get Pipelines lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Pipelines",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Pipelines').output.value",
"type": "Expression"
},
"activities": [
{
"name": "Execute Pipeline",
"description": "The lowest level executor with the metadata framework to call existing processing pipelines within Data Factory. The function called will block processing and wait for an outcome.",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Log Pipeline Running",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Pipeline Params",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get SPN Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "ExecutePipeline",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n\t\"tenantId\": \"',pipeline().parameters.TenantId,'\",\n\t\"applicationId\": \"',activity('Get SPN Details').output.firstRow.Id,'\",\n\t\"authenticationKey\": \"',activity('Get SPN Details').output.firstRow.Secret,'\",\n\t\"subscriptionId\": \"',pipeline().parameters.SubscriptionId,'\",\n\t\"resourceGroup\": \"',item().ResourceGroupName,'\",\n\t\"factoryName\": \"',item().DataFactoryName,'\",\n\t\"pipelineName\": \"',item().PipelineName,'\"',activity('Get Pipeline Params').output.firstRow.Params,'\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "PipelineExecutor",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Pipeline Params",
"description": "Returns any parameters from metadata required for the processing pipeline being called. The output can be an empty string if no parameters are required.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelineParameters]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Pipeline Running",
"description": "Sets the current pipeline with a status of running within the current execution database table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get SPN Details",
"description": "Return the SPN ID and Secret for the processing pipeline being executed. Called at this level as each pipeline can have a different SPN.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetServicePrincipal]",
"storedProcedureParameters": {
"DataFactory": {
"type": "String",
"value": {
"value": "@item().DataFactoryName",
"type": "Expression"
}
},
"PipelineName": {
"type": "String",
"value": {
"value": "@item().PipelineName",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Handle Function Output",
"description": "Receives the outcome from the function execution for a given processing pipeline and updates the current execution table with different pipelines status values depending on the result (case).",
"type": "Switch",
"dependsOn": [
{
"activity": "Execute Pipeline",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"on": {
"value": "@activity('Execute Pipeline').output.Status",
"type": "Expression"
},
"cases": [
{
"value": "Failed",
"activities": [
{
"name": "Log Pipeline Failure",
"description": "Updates the current execution table with a pipeline status of failed if the function outcome is failed. Also blocks pipelines in the downstream execution stage.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@activity('Execute Pipeline').output.RunIdUsed",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Succeeded",
"activities": [
{
"name": "Log Pipeline Success",
"description": "Updates the current execution table with a pipeline status of success if the function outcome is succeeded.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineSuccess]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId\n",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
],
"defaultActivities": [
{
"name": "Log Pipeline Unknown",
"description": "Updates the current execution table with a pipeline status of unknown if the function returns an unexpected outcome.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineUnknown]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Log Activity Failure",
"description": "Handle true failures from calling out to the Azure Function and update the current execution table accordingly so a restart can occur.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Pipeline",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@pipeline().RunId",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
}
],
"parameters": {
"StageId": {
"type": "int"
},
"ExecutionId": {
"type": "string"
},
"TenantId": {
"type": "string"
},
"SubscriptionId": {
"type": "string"
}
},
"variables": {
"FunctionBody": {
"type": "String"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/PipelineExecutor')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Intention Error')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Call Fail Procedure",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[dbo].[FailProcedure]"
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
],
"folder": {
"name": "Process Pipelines"
},
"annotations": []
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Wait 1')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait1",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "Process Pipelines"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 10')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait10",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "Process Pipelines"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 2')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait2",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "Process Pipelines"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 3')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait3",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "Process Pipelines"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 4')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait4",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "Process Pipelines"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 5')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait5",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "Process Pipelines"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 6')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait6",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "Process Pipelines"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 7')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait7",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "Process Pipelines"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 8')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait8",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "Process Pipelines"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 9')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait9",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "Process Pipelines"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/GetSetMetadata')]",
"type": "Microsoft.DataFactory/factories/datasets",
"apiVersion": "2018-06-01",
"properties": {
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
},
"annotations": [
"ADF.procfwk"
],
"type": "AzureSqlTable",
"schema": [],
"typeProperties": {}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Keys')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Connection to Key Vault for all other ADF linked service credentials required to run the processing framework.",
"annotations": [
"ADF.procfwk"
],
"type": "AzureKeyVault",
"typeProperties": {
"baseUrl": "[parameters('Keys_properties_typeProperties_baseUrl')]"
}
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/PipelineExecutor')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Connection to the Function App from ADF for calling the processing pipeline function within the orchestration framework.",
"annotations": [
"ADF.procfwk"
],
"type": "AzureFunction",
"typeProperties": {
"functionAppUrl": "https://pipelineexecutor.azurewebsites.net",
"functionKey": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "ExecutorFunctionAppKey"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/SupportDatabase')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Connection between ADF and processing framework metadata SQLDB.",
"annotations": [
"ADF.procfwk"
],
"type": "AzureSqlDatabase",
"typeProperties": {
"connectionString": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "[parameters('SupportDatabase_properties_typeProperties_connectionString_secretName')]"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
}
]
}
================================================
FILE: ARM Templates/Data Factory/v1.3 Export.json
================================================
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"factoryName": {
"type": "string",
"metadata": "Data Factory name",
"defaultValue": ""
},
"Keys_properties_typeProperties_baseUrl": {
"type": "string",
"defaultValue": ""
},
"SupportDatabase_properties_typeProperties_connectionString_secretName": {
"type": "string",
"defaultValue": ""
}
},
"variables": {
"factoryId": "[concat('Microsoft.DataFactory/factories/', parameters('factoryName'))]"
},
"resources": [
{
"name": "[concat(parameters('factoryName'), '/01-Grandparent')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk grandparent pipeline used optionally to bootstrap any wider processes in your Data Factory that then calls the processing framework.",
"activities": [
{
"name": "Framework Processing",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Set Random Waits",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "02-Parent",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {}
}
},
{
"name": "Set Random Waits",
"description": "For functional testing only.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[dbo].[SetRandomWaitValues]"
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
],
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/pipelines/02-Parent')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/02-Parent')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk parent pipeline used to bootstrap the orchestration framework in perform the first level ForEach calls in sequence for the metadata stages.",
"activities": [
{
"name": "Get Stages",
"description": "Returns a distinct list of execution stages within the framework metadata.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Execution Wrapper",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetStages]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Stages",
"description": "Top level ForEach to sequentially call all processing stages within the framework metadata. Items for iteration passed from the Get Stages lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Stages",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Tenant Id",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Subscription Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Stages').output.value",
"type": "Expression"
},
"isSequential": true,
"activities": [
{
"name": "Stage Executor",
"description": "Call to the framework generic child pipeline for a given execution stage.",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Log Stage Preparing",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "03-Child",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"StageId": {
"value": "@item().StageId",
"type": "Expression"
},
"ExecutionId": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
},
"TenantId": {
"value": "@activity('Get Tenant Id').output.firstRow.PropertyValue",
"type": "Expression"
},
"SubscriptionId": {
"value": "@activity('Get Subscription Id').output.firstRow.PropertyValue",
"type": "Expression"
}
}
}
},
{
"name": "Log Stage Preparing",
"description": "Update the current execution table flagging all pipelines within the stage as preparing.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Check for Blockers",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogStagePreparing]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check for Blockers",
"description": "Used to double check and stop the next execution stage if failures and blockers have be incurred. Without this step processing would continue regardless of upstream failures.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[CheckForBlockedPipelines]",
"storedProcedureParameters": {
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Execution Wrapper",
"description": "Wrapper to reset and restart processing or create a completely new execution instance of the framework metadata.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Metadata Integrity Checks",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[ExecutionWrapper]",
"storedProcedureParameters": {
"CallingDataFactory": {
"type": "String",
"value": {
"value": "@pipeline().DataFactory",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Archive Execution Log",
"description": "After a successful execution run the current execution metadata is moved to the long term logging table by this stored procedure call.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Stages",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[UpdateExecutionLog]"
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Tenant Id",
"description": "Returning the Azure Tenant Id from the metadata properties table.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Metadata Integrity Checks",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "TenantId"
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": true
}
},
{
"name": "Get Subscription Id",
"description": "Returning the Azure Subscription Id from the metadata properties table.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Metadata Integrity Checks",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "SubscriptionId"
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Metadata Integrity Checks",
"description": "Performs a series of checks on all metadata held in the framework SQLDB. This is intended to raise errors before an execution run even starts.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[CheckMetadataIntegrity]",
"storedProcedureParameters": {
"DebugMode": {
"value": "false",
"type": "Boolean"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
],
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]",
"[concat(variables('factoryId'), '/pipelines/03-Child')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/03-Child')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk child pipeline used to execute processing pipelines within a given execution stage. This pipeline will be called multi times in parallel.",
"activities": [
{
"name": "Get Pipelines",
"description": "Returns all pipelines from the metadata to be executed within a given processing stage.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelinesInStage]",
"storedProcedureParameters": {
"StageId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Pipelines",
"description": "Second level ForEach to run in parallel all pipelines within the stage. Items for iteration passed from the Get Pipelines lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Pipelines",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Pipelines').output.value",
"type": "Expression"
},
"activities": [
{
"name": "Execute Pipeline",
"description": "The lowest level executor with the metadata framework to call existing processing pipelines within Data Factory. The function called will block processing and wait for an outcome.",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Log Pipeline Running",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Pipeline Params",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get SPN Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "ExecutePipeline",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n\t\"tenantId\": \"',pipeline().parameters.TenantId,'\",\n\t\"applicationId\": \"',activity('Get SPN Details').output.firstRow.Id,'\",\n\t\"authenticationKey\": \"',activity('Get SPN Details').output.firstRow.Secret,'\",\n\t\"subscriptionId\": \"',pipeline().parameters.SubscriptionId,'\",\n\t\"resourceGroup\": \"',item().ResourceGroupName,'\",\n\t\"factoryName\": \"',item().DataFactoryName,'\",\n\t\"pipelineName\": \"',item().PipelineName,'\"',activity('Get Pipeline Params').output.firstRow.Params,'\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "PipelineExecutor",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Pipeline Params",
"description": "Returns any parameters from metadata required for the processing pipeline being called. The output can be an empty string if no parameters are required.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelineParameters]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Pipeline Running",
"description": "Sets the current pipeline with a status of running within the current execution database table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get SPN Details",
"description": "Return the SPN ID and Secret for the processing pipeline being executed. Called at this level as each pipeline can have a different SPN.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetServicePrincipal]",
"storedProcedureParameters": {
"DataFactory": {
"type": "String",
"value": {
"value": "@item().DataFactoryName",
"type": "Expression"
}
},
"PipelineName": {
"type": "String",
"value": {
"value": "@item().PipelineName",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Handle Function Output",
"description": "Receives the outcome from the function execution for a given processing pipeline and updates the current execution table with different pipelines status values depending on the result (case).",
"type": "Switch",
"dependsOn": [
{
"activity": "Execute Pipeline",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"on": {
"value": "@activity('Execute Pipeline').output.Status",
"type": "Expression"
},
"cases": [
{
"value": "Failed",
"activities": [
{
"name": "Log Pipeline Failure",
"description": "Updates the current execution table with a pipeline status of failed if the function outcome is failed. Also blocks pipelines in the downstream execution stage.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@activity('Execute Pipeline').output.RunIdUsed",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Succeeded",
"activities": [
{
"name": "Log Pipeline Success",
"description": "Updates the current execution table with a pipeline status of success if the function outcome is succeeded.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineSuccess]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId\n",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
],
"defaultActivities": [
{
"name": "Log Pipeline Unknown",
"description": "Updates the current execution table with a pipeline status of unknown if the function returns an unexpected outcome.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineUnknown]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Log Activity Failure",
"description": "Handle true failures from calling out to the Azure Function and update the current execution table accordingly so a restart can occur.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Pipeline",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@pipeline().RunId",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
}
],
"parameters": {
"StageId": {
"type": "int"
},
"ExecutionId": {
"type": "string"
},
"TenantId": {
"type": "string"
},
"SubscriptionId": {
"type": "string"
}
},
"variables": {
"FunctionBody": {
"type": "String"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/PipelineExecutor')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Intention Error')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Call Fail Procedure",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[dbo].[FailProcedure]"
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
],
"folder": {
"name": "Processes"
},
"annotations": []
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Wait 1')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait1",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "Processes"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 10')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait10",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "Processes"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 2')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait2",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "Processes"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 3')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait3",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "Processes"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 4')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait4",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "Processes"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 5')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait5",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "Processes"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 6')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait6",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "Processes"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 7')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait7",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "Processes"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 8')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait8",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "Processes"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 9')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait9",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "Processes"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/GetSetMetadata')]",
"type": "Microsoft.DataFactory/factories/datasets",
"apiVersion": "2018-06-01",
"properties": {
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
},
"annotations": [
"ADF.procfwk"
],
"type": "AzureSqlTable",
"schema": [],
"typeProperties": {}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Keys')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Connection to Key Vault for all other ADF linked service credentials required to run the processing framework.",
"annotations": [
"ADF.procfwk"
],
"type": "AzureKeyVault",
"typeProperties": {
"baseUrl": "[parameters('Keys_properties_typeProperties_baseUrl')]"
}
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/PipelineExecutor')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Connection to the Function App from ADF for calling the processing pipeline function within the orchestration framework.",
"annotations": [
"ADF.procfwk"
],
"type": "AzureFunction",
"typeProperties": {
"functionAppUrl": "https://pipelineexecutor.azurewebsites.net",
"functionKey": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "ExecutorFunctionAppKey"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/SupportDatabase')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Connection between ADF and processing framework metadata SQLDB.",
"annotations": [
"ADF.procfwk"
],
"type": "AzureSqlDatabase",
"typeProperties": {
"connectionString": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "[parameters('SupportDatabase_properties_typeProperties_connectionString_secretName')]"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/FunctionalTestingTrigger')]",
"type": "Microsoft.DataFactory/factories/triggers",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used internally to run the processing framework hourly.",
"annotations": [
"ADF.procfwk"
],
"runtimeState": "Stopped",
"pipelines": [
{
"pipelineReference": {
"referenceName": "01-Grandparent",
"type": "PipelineReference"
},
"parameters": {}
}
],
"type": "ScheduleTrigger",
"typeProperties": {
"recurrence": {
"frequency": "Hour",
"interval": 1,
"startTime": "2020-04-06T15:00:00.000Z",
"timeZone": "UTC"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/pipelines/01-Grandparent')]"
]
}
]
}
================================================
FILE: ARM Templates/Data Factory/v1.4 Export.json
================================================
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"factoryName": {
"type": "string",
"metadata": "Data Factory name",
"defaultValue": ""
},
"Keys_properties_typeProperties_baseUrl": {
"type": "string",
"defaultValue": ""
},
"SupportDatabase_properties_typeProperties_connectionString_secretName": {
"type": "string",
"defaultValue": ""
}
},
"variables": {
"factoryId": "[concat('Microsoft.DataFactory/factories/', parameters('factoryName'))]"
},
"resources": [
{
"name": "[concat(parameters('factoryName'), '/01-Grandparent')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk grandparent pipeline used optionally to bootstrap any wider processes in your Data Factory that then calls the processing framework.",
"activities": [
{
"name": "Framework Processing",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Set Random Waits",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "02-Parent",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {}
}
},
{
"name": "Set Random Waits",
"description": "For functional testing only.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[dbo].[SetRandomWaitValues]"
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
],
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/pipelines/02-Parent')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/02-Parent')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk parent pipeline used to bootstrap the orchestration framework in perform the first level ForEach calls in sequence for the metadata stages.",
"activities": [
{
"name": "Get Stages",
"description": "Returns a distinct list of execution stages within the framework metadata.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Execution Wrapper",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetStages]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Stages",
"description": "Top level ForEach to sequentially call all processing stages within the framework metadata. Items for iteration passed from the Get Stages lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Stages",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Tenant Id",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Subscription Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Stages').output.value",
"type": "Expression"
},
"isSequential": true,
"activities": [
{
"name": "Stage Executor",
"description": "Call to the framework generic child pipeline for a given execution stage.",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Log Stage Preparing",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "03-Child",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"StageId": {
"value": "@item().StageId",
"type": "Expression"
},
"ExecutionId": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
},
"TenantId": {
"value": "@activity('Get Tenant Id').output.firstRow.PropertyValue",
"type": "Expression"
},
"SubscriptionId": {
"value": "@activity('Get Subscription Id').output.firstRow.PropertyValue",
"type": "Expression"
}
}
}
},
{
"name": "Log Stage Preparing",
"description": "Update the current execution table flagging all pipelines within the stage as preparing.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Check for Blockers",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogStagePreparing]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check for Blockers",
"description": "Used to double check and stop the next execution stage if failures and blockers have be incurred. Without this step processing would continue regardless of upstream failures.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[CheckForBlockedPipelines]",
"storedProcedureParameters": {
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Execution Wrapper",
"description": "Wrapper to reset and restart processing or create a completely new execution instance of the framework metadata.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Metadata Integrity Checks",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[ExecutionWrapper]",
"storedProcedureParameters": {
"CallingDataFactory": {
"type": "String",
"value": {
"value": "@pipeline().DataFactory",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Archive Execution Log",
"description": "After a successful execution run the current execution metadata is moved to the long term logging table by this stored procedure call.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Stages",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[UpdateExecutionLog]"
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Tenant Id",
"description": "Returning the Azure Tenant Id from the metadata properties table.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Metadata Integrity Checks",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "TenantId"
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": true
}
},
{
"name": "Get Subscription Id",
"description": "Returning the Azure Subscription Id from the metadata properties table.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Metadata Integrity Checks",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "SubscriptionId"
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Metadata Integrity Checks",
"description": "Performs a series of checks on all metadata held in the framework SQLDB. This is intended to raise errors before an execution run even starts.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[CheckMetadataIntegrity]",
"storedProcedureParameters": {
"DebugMode": {
"value": "false",
"type": "Boolean"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
],
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]",
"[concat(variables('factoryId'), '/pipelines/03-Child')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/03-Child')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk child pipeline used to execute Worker pipelines within a given execution stage. This pipeline will be called once for each stage, then execute all Workers in parallel.",
"activities": [
{
"name": "Get Pipelines",
"description": "Returns all pipelines from the metadata to be executed within a given processing stage.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelinesInStage]",
"storedProcedureParameters": {
"StageId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Pipelines",
"description": "Second level ForEach to run in parallel all pipelines within the stage. Items for iteration passed from the Get Pipelines lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Pipelines",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Pipelines').output.value",
"type": "Expression"
},
"isSequential": false,
"activities": [
{
"name": "Execute Pipeline",
"description": "The lowest level executor with the metadata framework to call existing processing pipelines within Data Factory. The function called will block processing and wait for an outcome.",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Log Pipeline Running",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Pipeline Params",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get SPN Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "ExecutePipelineV2",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n\t\"tenantId\": \"',pipeline().parameters.TenantId,'\",\n\t\"applicationId\": \"',activity('Get SPN Details').output.firstRow.Id,'\",\n\t\"authenticationKey\": \"',activity('Get SPN Details').output.firstRow.Secret,'\",\n\t\"subscriptionId\": \"',pipeline().parameters.SubscriptionId,'\",\n\t\"resourceGroup\": \"',item().ResourceGroupName,'\",\n\t\"factoryName\": \"',item().DataFactoryName,'\",\n\t\"pipelineName\": \"',item().PipelineName,'\"',activity('Get Pipeline Params').output.firstRow.Params,'\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "PipelineExecutor",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Pipeline Params",
"description": "Returns any parameters from metadata required for the processing pipeline being called. The output can be an empty string if no parameters are required.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelineParameters]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Pipeline Running",
"description": "Sets the current pipeline with a status of running within the current execution database table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get SPN Details",
"description": "Return the SPN ID and Secret for the processing pipeline being executed. Called at this level as each pipeline can have a different SPN.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetServicePrincipal]",
"storedProcedureParameters": {
"DataFactory": {
"type": "String",
"value": {
"value": "@item().DataFactoryName",
"type": "Expression"
}
},
"PipelineName": {
"type": "String",
"value": {
"value": "@item().PipelineName",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Activity Failure",
"description": "Handle true failures from calling out to the Azure Function and update the current execution table accordingly so a restart can occur.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Pipeline",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@pipeline().RunId",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Running Pipeline Handler",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Execute Pipeline",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "04-Infant",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"tenantId": {
"value": "@pipeline().parameters.TenantId",
"type": "Expression"
},
"applicationId": {
"value": "@activity('Get SPN Details').output.firstRow.Id",
"type": "Expression"
},
"authenticationKey": {
"value": "@activity('Get SPN Details').output.firstRow.Secret",
"type": "Expression"
},
"subscriptionId": {
"value": "@pipeline().parameters.SubscriptionId",
"type": "Expression"
},
"resourceGroup": {
"value": "@item().ResourceGroupName",
"type": "Expression"
},
"factoryName": {
"value": "@item().DataFactoryName",
"type": "Expression"
},
"pipelineName": {
"value": "@item().PipelineName",
"type": "Expression"
},
"runId": {
"value": "@activity('Execute Pipeline').output.RunId",
"type": "Expression"
},
"executionId": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"stageId": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"pipelineId": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
}
}
]
}
}
],
"parameters": {
"StageId": {
"type": "int"
},
"ExecutionId": {
"type": "string"
},
"TenantId": {
"type": "string"
},
"SubscriptionId": {
"type": "string"
}
},
"variables": {
"FunctionBody": {
"type": "String"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/PipelineExecutor')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]",
"[concat(variables('factoryId'), '/pipelines/04-Infant')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/04-Infant')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk infant pipeline used to check when the processing pipeline called by the Child completes and passes the resulting status back to the metadata database.",
"activities": [
{
"name": "Wait Until Pipeline Completes",
"description": "Loops until the pipeline called completes.\n\nSimple status:\n- Running = new iteration.\n- Done = break.",
"type": "Until",
"dependsOn": [
{
"activity": "Get Wait Duration",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@equals('Done',activity('Get Pipeline Status').output.SimpleStatus)",
"type": "Expression"
},
"activities": [
{
"name": "Get Pipeline Status",
"description": "Checks the status of a given processing pipeline and provides the value for the downstream framework activities to act upon.",
"type": "AzureFunctionActivity",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "CheckPipelineStatus",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',pipeline().parameters.TenantId,'\",\n \"applicationId\": \"',pipeline().parameters.applicationId,'\",\n \"authenticationKey\": \"',pipeline().parameters.authenticationKey,'\",\n \"subscriptionId\": \"',pipeline().parameters.subscriptionId,'\",\n \"resourceGroup\": \"',pipeline().parameters.resourceGroup,'\",\n \"factoryName\": \"',pipeline().parameters.factoryName,'\",\n \"pipelineName\": \"',pipeline().parameters.pipelineName,'\",\n \"runId\": \"',pipeline().parameters.runId,'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "PipelineExecutor",
"type": "LinkedServiceReference"
}
},
{
"name": "Wait If Running",
"description": "True = Do nothing.\nFalse = Wait.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@equals('Done',activity('Get Pipeline Status').output.SimpleStatus)",
"type": "Expression"
},
"ifFalseActivities": [
{
"name": "Wait for Pipeline",
"description": "The processing pipeline is still running so Wait before checking its status again.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@activity('Get Wait Duration').output.firstRow.PropertyValue",
"type": "Expression"
}
}
}
]
}
},
{
"name": "Wait to Retry Function",
"type": "Wait",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Failed"
]
}
],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@activity('Get Wait Duration').output.firstRow.PropertyValue",
"type": "Expression"
}
}
},
{
"name": "Set Last Update",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineLastStatusCheck]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
],
"timeout": "7.00:00:00"
}
},
{
"name": "Pipeline Result",
"description": "Receives the outcome from the function execution for a given processing pipeline and updates the current execution table with different pipelines status values depending on the result (case).",
"type": "Switch",
"dependsOn": [
{
"activity": "Wait Until Pipeline Completes",
"dependencyConditions": [
"Completed"
]
}
],
"userProperties": [],
"typeProperties": {
"on": {
"value": "@activity('Get Pipeline Status').output.Status",
"type": "Expression"
},
"cases": [
{
"value": "Succeeded",
"activities": [
{
"name": "Pipeline Status Succeeded",
"description": "Updates the current execution table with a pipeline status of success if the function outcome is succeeded.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineSuccess]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Failed",
"activities": [
{
"name": "Pipeline Status Failed",
"description": "Updates the current execution table with a pipeline status of failed if the function outcome is failed. Also blocks pipelines in the downstream execution stage.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@activity('Get Pipeline Status').output.RunId",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
],
"defaultActivities": [
{
"name": "Pipeline Status Unknown",
"description": "Updates the current execution table with a pipeline status of unknown if the function returns an unexpected outcome.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineUnknown]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Get Wait Duration",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "PipelineStatusCheckDuration"
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
}
],
"parameters": {
"tenantId": {
"type": "string"
},
"applicationId": {
"type": "string"
},
"authenticationKey": {
"type": "string"
},
"subscriptionId": {
"type": "string"
},
"resourceGroup": {
"type": "string"
},
"factoryName": {
"type": "string"
},
"pipelineName": {
"type": "string"
},
"runId": {
"type": "string"
},
"executionId": {
"type": "string"
},
"stageId": {
"type": "int"
},
"pipelineId": {
"type": "int"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/PipelineExecutor')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Intention Error')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Call Fail Procedure",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[dbo].[FailProcedure]"
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
],
"folder": {
"name": "Processes"
},
"annotations": []
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Wait 1')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait1",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "Processes"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 10')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait10",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "Processes"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 2')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait2",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "Processes"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 3')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait3",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "Processes"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 4')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait4",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "Processes"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 5')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait5",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "Processes"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 6')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait6",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "Processes"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 7')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait7",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "Processes"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 8')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait8",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "Processes"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 9')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait9",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "Processes"
},
"annotations": []
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/GetSetMetadata')]",
"type": "Microsoft.DataFactory/factories/datasets",
"apiVersion": "2018-06-01",
"properties": {
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
},
"annotations": [
"ADF.procfwk"
],
"type": "AzureSqlTable",
"schema": [],
"typeProperties": {}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Keys')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Connection to Key Vault for all other ADF linked service credentials required to run the processing framework.",
"annotations": [
"ADF.procfwk"
],
"type": "AzureKeyVault",
"typeProperties": {
"baseUrl": "[parameters('Keys_properties_typeProperties_baseUrl')]"
}
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/PipelineExecutor')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Connection to the Function App from ADF for calling the processing pipeline function within the orchestration framework.",
"annotations": [
"ADF.procfwk"
],
"type": "AzureFunction",
"typeProperties": {
"functionAppUrl": "https://pipelineexecutor.azurewebsites.net",
"functionKey": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "ExecutorFunctionAppKey"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/SupportDatabase')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Connection between ADF and processing framework metadata SQLDB.",
"annotations": [
"ADF.procfwk"
],
"type": "AzureSqlDatabase",
"typeProperties": {
"connectionString": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "[parameters('SupportDatabase_properties_typeProperties_connectionString_secretName')]"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/FunctionalTestingTrigger')]",
"type": "Microsoft.DataFactory/factories/triggers",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used for functional testing of the framework in a dedicated environment.",
"annotations": [
"ADF.procfwk"
],
"runtimeState": "Stopped",
"pipelines": [
{
"pipelineReference": {
"referenceName": "01-Grandparent",
"type": "PipelineReference"
},
"parameters": {}
}
],
"type": "ScheduleTrigger",
"typeProperties": {
"recurrence": {
"frequency": "Hour",
"interval": 1,
"startTime": "2020-04-06T15:00:00.000Z",
"timeZone": "UTC"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/pipelines/01-Grandparent')]"
]
}
]
}
================================================
FILE: ARM Templates/Data Factory/v1.5 Export.json
================================================
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"factoryName": {
"type": "string",
"metadata": "Data Factory name",
"defaultValue": ""
},
"Keys_properties_typeProperties_baseUrl": {
"type": "string",
"defaultValue": ""
},
"SupportDatabase_properties_typeProperties_connectionString_secretName": {
"type": "string",
"defaultValue": ""
}
},
"variables": {
"factoryId": "[concat('Microsoft.DataFactory/factories/', parameters('factoryName'))]"
},
"resources": [
{
"name": "[concat(parameters('factoryName'), '/01-Grandparent')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk grandparent pipeline used optionally to bootstrap any wider processes in your Data Factory that then calls the processing framework.",
"activities": [
{
"name": "Framework Processing",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Set Random Waits",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "02-Parent",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {}
}
},
{
"name": "Set Random Waits",
"description": "For functional testing only.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[dbo].[SetRandomWaitValues]"
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
],
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/pipelines/02-Parent')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/02-Parent')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk parent pipeline used to bootstrap the orchestration framework in perform the first level ForEach calls in sequence for the metadata stages.",
"activities": [
{
"name": "Get Stages",
"description": "Returns a distinct list of execution stages within the framework metadata.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Execution Wrapper",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetStages]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Stages",
"description": "Top level ForEach to sequentially call all processing stages within the framework metadata. Items for iteration passed from the Get Stages lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Stages",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Tenant Id",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Subscription Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Stages').output.value",
"type": "Expression"
},
"isSequential": true,
"activities": [
{
"name": "Stage Executor",
"description": "Call to the framework generic child pipeline for a given execution stage.",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Log Stage Preparing",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "03-Child",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"StageId": {
"value": "@item().StageId",
"type": "Expression"
},
"ExecutionId": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
},
"TenantId": {
"value": "@activity('Get Tenant Id').output.firstRow.PropertyValue",
"type": "Expression"
},
"SubscriptionId": {
"value": "@activity('Get Subscription Id').output.firstRow.PropertyValue",
"type": "Expression"
}
}
}
},
{
"name": "Log Stage Preparing",
"description": "Update the current execution table flagging all pipelines within the stage as preparing.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Check for Blockers",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogStagePreparing]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check for Blockers",
"description": "Used to double check and stop the next execution stage if failures and blockers have be incurred. Without this step processing would continue regardless of upstream failures.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[CheckForBlockedPipelines]",
"storedProcedureParameters": {
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Execution Wrapper",
"description": "Wrapper to reset and restart processing or create a completely new execution instance of the framework metadata.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Metadata Integrity Checks",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[ExecutionWrapper]",
"storedProcedureParameters": {
"CallingDataFactory": {
"type": "String",
"value": {
"value": "@pipeline().DataFactory",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Archive Execution Log",
"description": "After a successful execution run the current execution metadata is moved to the long term logging table by this stored procedure call.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Stages",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[UpdateExecutionLog]"
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Tenant Id",
"description": "Returning the Azure Tenant Id from the metadata properties table.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Metadata Integrity Checks",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "TenantId"
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": true
}
},
{
"name": "Get Subscription Id",
"description": "Returning the Azure Subscription Id from the metadata properties table.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Metadata Integrity Checks",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "SubscriptionId"
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Metadata Integrity Checks",
"description": "Performs a series of checks on all metadata held in the framework SQLDB. This is intended to raise errors before an execution run even starts.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[CheckMetadataIntegrity]",
"storedProcedureParameters": {
"DebugMode": {
"value": "false",
"type": "Boolean"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
],
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]",
"[concat(variables('factoryId'), '/pipelines/03-Child')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/03-Child')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk child pipeline used to execute Worker pipelines within a given execution stage. This pipeline will be called once for each stage, then execute all Workers in parallel.",
"activities": [
{
"name": "Get Pipelines",
"description": "Returns all pipelines from the metadata to be executed within a given processing stage.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelinesInStage]",
"storedProcedureParameters": {
"StageId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Pipelines",
"description": "Second level ForEach to run in parallel all pipelines within the stage. Items for iteration passed from the Get Pipelines lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Pipelines",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Pipelines').output.value",
"type": "Expression"
},
"isSequential": false,
"activities": [
{
"name": "Execute Pipeline",
"description": "The lowest level executor with the metadata framework to call existing processing pipelines within Data Factory. The function called will block processing and wait for an outcome.",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Log Pipeline Running",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Pipeline Params",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get SPN Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "ExecutePipelineV2",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n\t\"tenantId\": \"',pipeline().parameters.TenantId,'\",\n\t\"applicationId\": \"',activity('Get SPN Details').output.firstRow.Id,'\",\n\t\"authenticationKey\": \"',activity('Get SPN Details').output.firstRow.Secret,'\",\n\t\"subscriptionId\": \"',pipeline().parameters.SubscriptionId,'\",\n\t\"resourceGroup\": \"',item().ResourceGroupName,'\",\n\t\"factoryName\": \"',item().DataFactoryName,'\",\n\t\"pipelineName\": \"',item().PipelineName,'\"',activity('Get Pipeline Params').output.firstRow.Params,'\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "PipelineExecutor",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Pipeline Params",
"description": "Returns any parameters from metadata required for the processing pipeline being called. The output can be an empty string if no parameters are required.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelineParameters]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Pipeline Running",
"description": "Sets the current pipeline with a status of running within the current execution database table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get SPN Details",
"description": "Return the SPN ID and Secret for the processing pipeline being executed. Called at this level as each pipeline can have a different SPN.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetServicePrincipal]",
"storedProcedureParameters": {
"DataFactory": {
"type": "String",
"value": {
"value": "@item().DataFactoryName",
"type": "Expression"
}
},
"PipelineName": {
"type": "String",
"value": {
"value": "@item().PipelineName",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Activity Failure",
"description": "Handle true failures from calling out to the Azure Function and update the current execution table accordingly so a restart can occur.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Pipeline",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@pipeline().RunId",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Running Pipeline Handler",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Execute Pipeline",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "04-Infant",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"tenantId": {
"value": "@pipeline().parameters.TenantId",
"type": "Expression"
},
"applicationId": {
"value": "@activity('Get SPN Details').output.firstRow.Id",
"type": "Expression"
},
"authenticationKey": {
"value": "@activity('Get SPN Details').output.firstRow.Secret",
"type": "Expression"
},
"subscriptionId": {
"value": "@pipeline().parameters.SubscriptionId",
"type": "Expression"
},
"resourceGroup": {
"value": "@item().ResourceGroupName",
"type": "Expression"
},
"factoryName": {
"value": "@item().DataFactoryName",
"type": "Expression"
},
"pipelineName": {
"value": "@item().PipelineName",
"type": "Expression"
},
"runId": {
"value": "@activity('Execute Pipeline').output.RunId",
"type": "Expression"
},
"executionId": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"stageId": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"pipelineId": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
}
},
{
"name": "Set Run Id",
"description": "Provide the actual ADF run ID back to the current execution table for long term logging and alignment between the metadata other Azure monitoring tools.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Pipeline",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunId]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@activity('Execute Pipeline').output.RunId",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
}
],
"parameters": {
"StageId": {
"type": "int"
},
"ExecutionId": {
"type": "string"
},
"TenantId": {
"type": "string"
},
"SubscriptionId": {
"type": "string"
}
},
"variables": {
"FunctionBody": {
"type": "String"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/PipelineExecutor')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]",
"[concat(variables('factoryId'), '/pipelines/04-Infant')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/04-Infant')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk infant pipeline used to check when the processing pipeline called by the Child completes and passes the resulting status back to the metadata database.",
"activities": [
{
"name": "Wait Until Pipeline Completes",
"description": "Loops until the pipeline called completes.\n\nSimple status:\n- Running = new iteration.\n- Done = break.",
"type": "Until",
"dependsOn": [
{
"activity": "Get Wait Duration",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@equals('Done',activity('Get Pipeline Status').output.SimpleStatus)",
"type": "Expression"
},
"activities": [
{
"name": "Get Pipeline Status",
"description": "Checks the status of a given processing pipeline and provides the value for the downstream framework activities to act upon.",
"type": "AzureFunctionActivity",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "CheckPipelineStatus",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',pipeline().parameters.TenantId,'\",\n \"applicationId\": \"',pipeline().parameters.applicationId,'\",\n \"authenticationKey\": \"',pipeline().parameters.authenticationKey,'\",\n \"subscriptionId\": \"',pipeline().parameters.subscriptionId,'\",\n \"resourceGroup\": \"',pipeline().parameters.resourceGroup,'\",\n \"factoryName\": \"',pipeline().parameters.factoryName,'\",\n \"pipelineName\": \"',pipeline().parameters.pipelineName,'\",\n \"runId\": \"',pipeline().parameters.runId,'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "PipelineExecutor",
"type": "LinkedServiceReference"
}
},
{
"name": "Wait If Running",
"description": "True = Do nothing.\nFalse = Wait.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@equals('Done',activity('Get Pipeline Status').output.SimpleStatus)",
"type": "Expression"
},
"ifFalseActivities": [
{
"name": "Wait for Pipeline",
"description": "The processing pipeline is still running so Wait before checking its status again.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@activity('Get Wait Duration').output.firstRow.PropertyValue",
"type": "Expression"
}
}
}
]
}
},
{
"name": "Wait to Retry Function",
"type": "Wait",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Failed"
]
}
],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@activity('Get Wait Duration').output.firstRow.PropertyValue",
"type": "Expression"
}
}
},
{
"name": "Set Last Update",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineLastStatusCheck]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
],
"timeout": "7.00:00:00"
}
},
{
"name": "Pipeline Result",
"description": "Receives the outcome from the function execution for a given processing pipeline and updates the current execution table with different pipelines status values depending on the result (case).",
"type": "Switch",
"dependsOn": [
{
"activity": "Wait Until Pipeline Completes",
"dependencyConditions": [
"Completed"
]
}
],
"userProperties": [],
"typeProperties": {
"on": {
"value": "@activity('Get Pipeline Status').output.Status",
"type": "Expression"
},
"cases": [
{
"value": "Succeeded",
"activities": [
{
"name": "Pipeline Status Succeeded",
"description": "Updates the current execution table with a pipeline status of success if the function outcome is succeeded.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineSuccess]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Failed",
"activities": [
{
"name": "Pipeline Status Failed",
"description": "Updates the current execution table with a pipeline status of failed if the function outcome is failed. Also blocks pipelines in the downstream execution stage.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@activity('Get Pipeline Status').output.RunId",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
],
"defaultActivities": [
{
"name": "Pipeline Status Unknown",
"description": "Updates the current execution table with a pipeline status of unknown if the function returns an unexpected outcome.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineUnknown]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Get Wait Duration",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "PipelineStatusCheckDuration"
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
}
],
"parameters": {
"tenantId": {
"type": "string"
},
"applicationId": {
"type": "string"
},
"authenticationKey": {
"type": "string"
},
"subscriptionId": {
"type": "string"
},
"resourceGroup": {
"type": "string"
},
"factoryName": {
"type": "string"
},
"pipelineName": {
"type": "string"
},
"runId": {
"type": "string"
},
"executionId": {
"type": "string"
},
"stageId": {
"type": "int"
},
"pipelineId": {
"type": "int"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/PipelineExecutor')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Intentional Error')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Call Fail Procedure",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Wait1",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[dbo].[FailProcedure]",
"storedProcedureParameters": {
"RaiseError": {
"value": {
"value": "@pipeline().parameters.RaiseErrors",
"type": "Expression"
},
"type": "String"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Wait1",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": 10
}
},
{
"name": "Call Fail Notebook",
"type": "DatabricksNotebook",
"dependsOn": [
{
"activity": "Wait1",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"notebookPath": "/Playground/Throw Exception",
"baseParameters": {
"RaiseError": {
"value": "@pipeline().parameters.RaiseErrors",
"type": "Expression"
}
}
},
"linkedServiceName": {
"referenceName": "BricksOfData",
"type": "LinkedServiceReference"
}
}
],
"parameters": {
"RaiseErrors": {
"type": "string",
"defaultValue": "false"
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]",
"[concat(variables('factoryId'), '/linkedServices/BricksOfData')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Wait 1')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait1",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 10')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait10",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 2')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait2",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 3')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait3",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 4')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait4",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 5')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait5",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 6')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait6",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 7')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait7",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 8')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait8",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 9')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait9",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/GetSetMetadata')]",
"type": "Microsoft.DataFactory/factories/datasets",
"apiVersion": "2018-06-01",
"properties": {
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
},
"annotations": [
"ADF.procfwk"
],
"type": "AzureSqlTable",
"schema": [],
"typeProperties": {}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/BricksOfData')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"annotations": [],
"type": "AzureDatabricks",
"typeProperties": {
"domain": "https://northeurope.azuredatabricks.net",
"accessToken": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "BricksOfDataToken",
"secretVersion": ""
},
"existingClusterId": "0422-090117-slots899"
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Keys')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Connection to Key Vault for all other ADF linked service credentials required to run the processing framework.",
"annotations": [
"ADF.procfwk"
],
"type": "AzureKeyVault",
"typeProperties": {
"baseUrl": "[parameters('Keys_properties_typeProperties_baseUrl')]"
}
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/PipelineExecutor')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Connection to the Function App from ADF for calling the processing pipeline function within the orchestration framework.",
"annotations": [
"ADF.procfwk"
],
"type": "AzureFunction",
"typeProperties": {
"functionAppUrl": "https://pipelineexecutor.azurewebsites.net",
"functionKey": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "ExecutorFunctionAppKey"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/SupportDatabase')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Connection between ADF and processing framework metadata SQLDB.",
"annotations": [
"ADF.procfwk"
],
"type": "AzureSqlDatabase",
"typeProperties": {
"connectionString": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "[parameters('SupportDatabase_properties_typeProperties_connectionString_secretName')]"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/FunctionalTestingTrigger')]",
"type": "Microsoft.DataFactory/factories/triggers",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used for functional testing of the framework in a dedicated environment.",
"annotations": [
"ADF.procfwk"
],
"runtimeState": "Stopped",
"pipelines": [
{
"pipelineReference": {
"referenceName": "01-Grandparent",
"type": "PipelineReference"
},
"parameters": {}
}
],
"type": "ScheduleTrigger",
"typeProperties": {
"recurrence": {
"frequency": "Hour",
"interval": 2,
"startTime": "2020-04-06T15:00:00.000Z",
"timeZone": "UTC"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/pipelines/01-Grandparent')]"
]
}
]
}
================================================
FILE: ARM Templates/Data Factory/v1.6 Export.json
================================================
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"factoryName": {
"type": "string",
"metadata": "Data Factory name",
"defaultValue": ""
},
"Keys_properties_typeProperties_baseUrl": {
"type": "string",
"defaultValue": ""
},
"SupportDatabase_properties_typeProperties_connectionString_secretName": {
"type": "string",
"defaultValue": ""
}
},
"variables": {
"factoryId": "[concat('Microsoft.DataFactory/factories/', parameters('factoryName'))]"
},
"resources": [
{
"name": "[concat(parameters('factoryName'), '/01-Grandparent')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk grandparent pipeline used optionally to bootstrap any wider processes in your Data Factory that then calls the processing framework.",
"activities": [
{
"name": "Framework Processing",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Set Random Waits",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "02-Parent",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {}
}
},
{
"name": "Set Random Waits",
"description": "For functional testing only.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[dbo].[SetRandomWaitValues]"
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
],
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/pipelines/02-Parent')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/02-Parent')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk parent pipeline used to bootstrap the orchestration framework in perform the first level ForEach calls in sequence for the metadata stages.",
"activities": [
{
"name": "Get Stages",
"description": "Returns a distinct list of execution stages within the framework metadata.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Execution Wrapper",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetStages]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Stages",
"description": "Top level ForEach to sequentially call all processing stages within the framework metadata. Items for iteration passed from the Get Stages lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Stages",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Tenant Id",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Subscription Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Stages').output.value",
"type": "Expression"
},
"isSequential": true,
"activities": [
{
"name": "Stage Executor",
"description": "Call to the framework generic child pipeline for a given execution stage.",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Log Stage Preparing",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "03-Child",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"StageId": {
"value": "@item().StageId",
"type": "Expression"
},
"ExecutionId": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
},
"TenantId": {
"value": "@activity('Get Tenant Id').output.firstRow.PropertyValue",
"type": "Expression"
},
"SubscriptionId": {
"value": "@activity('Get Subscription Id').output.firstRow.PropertyValue",
"type": "Expression"
}
}
}
},
{
"name": "Log Stage Preparing",
"description": "Update the current execution table flagging all pipelines within the stage as preparing.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Check for Blockers",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogStagePreparing]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check for Blockers",
"description": "Used to double check and stop the next execution stage if failures and blockers have be incurred. Without this step processing would continue regardless of upstream failures.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[CheckForBlockedPipelines]",
"storedProcedureParameters": {
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Execution Wrapper",
"description": "Wrapper to reset and restart processing or create a completely new execution instance of the framework metadata.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Metadata Integrity Checks",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[ExecutionWrapper]",
"storedProcedureParameters": {
"CallingDataFactory": {
"type": "String",
"value": {
"value": "@pipeline().DataFactory",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Archive Execution Log",
"description": "After a successful execution run the current execution metadata is moved to the long term logging table by this stored procedure call.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Stages",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[UpdateExecutionLog]"
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Tenant Id",
"description": "Returning the Azure Tenant Id from the metadata properties table.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Metadata Integrity Checks",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "TenantId"
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": true
}
},
{
"name": "Get Subscription Id",
"description": "Returning the Azure Subscription Id from the metadata properties table.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Metadata Integrity Checks",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "SubscriptionId"
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Metadata Integrity Checks",
"description": "Performs a series of checks on all metadata held in the framework SQLDB. This is intended to raise errors before an execution run even starts.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[CheckMetadataIntegrity]",
"storedProcedureParameters": {
"DebugMode": {
"value": "false",
"type": "Boolean"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
],
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]",
"[concat(variables('factoryId'), '/pipelines/03-Child')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/03-Child')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk child pipeline used to execute Worker pipelines within a given execution stage. This pipeline will be called once for each stage, then execute all Workers in parallel.",
"activities": [
{
"name": "Get Pipelines",
"description": "Returns all pipelines from the metadata to be executed within a given processing stage.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelinesInStage]",
"storedProcedureParameters": {
"StageId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Pipelines",
"description": "Second level ForEach to run in parallel all pipelines within the stage. Items for iteration passed from the Get Pipelines lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Pipelines",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Pipelines').output.value",
"type": "Expression"
},
"isSequential": false,
"activities": [
{
"name": "Execute Pipeline",
"description": "The lowest level executor with the metadata framework to call existing processing pipelines within Data Factory. The function called will block processing and wait for an outcome.",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Log Pipeline Running",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Pipeline Params",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get SPN Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "ExecutePipeline",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n\t\"tenantId\": \"',pipeline().parameters.TenantId,'\",\n\t\"applicationId\": \"',activity('Get SPN Details').output.firstRow.Id,'\",\n\t\"authenticationKey\": \"',activity('Get SPN Details').output.firstRow.Secret,'\",\n\t\"subscriptionId\": \"',pipeline().parameters.SubscriptionId,'\",\n\t\"resourceGroup\": \"',item().ResourceGroupName,'\",\n\t\"factoryName\": \"',item().DataFactoryName,'\",\n\t\"pipelineName\": \"',item().PipelineName,'\"',activity('Get Pipeline Params').output.firstRow.Params,'\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Pipeline Params",
"description": "Returns any parameters from metadata required for the processing pipeline being called. The output can be an empty string if no parameters are required.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelineParameters]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Pipeline Running",
"description": "Sets the current pipeline with a status of running within the current execution database table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get SPN Details",
"description": "Return the SPN ID and Secret for the processing pipeline being executed. Called at this level as each pipeline can have a different SPN.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetServicePrincipal]",
"storedProcedureParameters": {
"DataFactory": {
"type": "String",
"value": {
"value": "@item().DataFactoryName",
"type": "Expression"
}
},
"PipelineName": {
"type": "String",
"value": {
"value": "@item().PipelineName",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Activity Failure",
"description": "Handle true failures from calling out to the Azure Function and update the current execution table accordingly so a restart can occur.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Pipeline",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Running Pipeline Handler",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Execute Pipeline",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "04-Infant",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"tenantId": {
"value": "@pipeline().parameters.TenantId",
"type": "Expression"
},
"applicationId": {
"value": "@activity('Get SPN Details').output.firstRow.Id",
"type": "Expression"
},
"authenticationKey": {
"value": "@activity('Get SPN Details').output.firstRow.Secret",
"type": "Expression"
},
"subscriptionId": {
"value": "@pipeline().parameters.SubscriptionId",
"type": "Expression"
},
"resourceGroup": {
"value": "@item().ResourceGroupName",
"type": "Expression"
},
"factoryName": {
"value": "@item().DataFactoryName",
"type": "Expression"
},
"pipelineName": {
"value": "@item().PipelineName",
"type": "Expression"
},
"runId": {
"value": "@activity('Execute Pipeline').output.RunId",
"type": "Expression"
},
"executionId": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"stageId": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"pipelineId": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
}
},
{
"name": "Set Run Id",
"description": "Provide the actual ADF run ID back to the current execution table for long term logging and alignment between the metadata other Azure monitoring tools.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Pipeline",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunId]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@activity('Execute Pipeline').output.RunId",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
}
],
"parameters": {
"StageId": {
"type": "int"
},
"ExecutionId": {
"type": "string"
},
"TenantId": {
"type": "string"
},
"SubscriptionId": {
"type": "string"
}
},
"variables": {
"FunctionBody": {
"type": "String"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/FrameworkFunctions')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]",
"[concat(variables('factoryId'), '/pipelines/04-Infant')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/04-Infant')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk infant pipeline used to check when the processing pipeline called by the Child completes and passes the resulting status back to the metadata database.",
"activities": [
{
"name": "Wait Until Pipeline Completes",
"description": "Loops until the pipeline called completes.\n\nSimple status:\n- Running = new iteration.\n- Done = break.",
"type": "Until",
"dependsOn": [
{
"activity": "Get Wait Duration",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@equals('Done',activity('Get Pipeline Status').output.SimpleStatus)",
"type": "Expression"
},
"activities": [
{
"name": "Get Pipeline Status",
"description": "Checks the status of a given processing pipeline and provides the value for the downstream framework activities to act upon.",
"type": "AzureFunctionActivity",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "CheckPipelineStatus",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',pipeline().parameters.TenantId,'\",\n \"applicationId\": \"',pipeline().parameters.applicationId,'\",\n \"authenticationKey\": \"',pipeline().parameters.authenticationKey,'\",\n \"subscriptionId\": \"',pipeline().parameters.subscriptionId,'\",\n \"resourceGroup\": \"',pipeline().parameters.resourceGroup,'\",\n \"factoryName\": \"',pipeline().parameters.factoryName,'\",\n \"pipelineName\": \"',pipeline().parameters.pipelineName,'\",\n \"runId\": \"',pipeline().parameters.runId,'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Wait If Running",
"description": "True = Do nothing.\nFalse = Wait.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@equals('Done',activity('Get Pipeline Status').output.SimpleStatus)",
"type": "Expression"
},
"ifFalseActivities": [
{
"name": "Wait for Pipeline",
"description": "The processing pipeline is still running so Wait before checking its status again.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@activity('Get Wait Duration').output.firstRow.PropertyValue",
"type": "Expression"
}
}
}
]
}
},
{
"name": "Wait to Retry Function",
"type": "Wait",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Failed"
]
}
],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@activity('Get Wait Duration').output.firstRow.PropertyValue",
"type": "Expression"
}
}
},
{
"name": "Set Last Update",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineLastStatusCheck]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
],
"timeout": "7.00:00:00"
}
},
{
"name": "Pipeline Result",
"description": "Receives the outcome from the function execution for a given processing pipeline and updates the current execution table with different pipelines status values depending on the result (case).",
"type": "Switch",
"dependsOn": [
{
"activity": "Wait Until Pipeline Completes",
"dependencyConditions": [
"Completed"
]
}
],
"userProperties": [],
"typeProperties": {
"on": {
"value": "@activity('Get Pipeline Status').output.Status",
"type": "Expression"
},
"cases": [
{
"value": "Succeeded",
"activities": [
{
"name": "Pipeline Status Succeeded",
"description": "Updates the current execution table with a pipeline status of success if the function outcome is succeeded.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineSuccess]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Failed",
"activities": [
{
"name": "Pipeline Status Failed",
"description": "Updates the current execution table with a pipeline status of failed if the function outcome is failed. Also blocks pipelines in the downstream execution stage.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@activity('Get Pipeline Status').output.RunId",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Error Details",
"description": "Get the activity error details for the run ID of the worker pipeline called. Returns an array of all errors.",
"type": "AzureFunctionActivity",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "GetActivityErrors",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',pipeline().parameters.TenantId,'\",\n \"applicationId\": \"',pipeline().parameters.applicationId,'\",\n \"authenticationKey\": \"',pipeline().parameters.authenticationKey,'\",\n \"subscriptionId\": \"',pipeline().parameters.subscriptionId,'\",\n \"resourceGroup\": \"',pipeline().parameters.resourceGroup,'\",\n \"factoryName\": \"',pipeline().parameters.factoryName,'\",\n \"pipelineName\": \"',pipeline().parameters.pipelineName,'\",\n \"runId\": \"',pipeline().parameters.runId,'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Error Details",
"description": "Parses pipeline error details and persists them to the metadata database error log table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Error Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetErrorLogDetails]",
"storedProcedureParameters": {
"JsonErrorDetails": {
"value": {
"value": "@string(activity('Get Error Details').output)",
"type": "Expression"
},
"type": "String"
},
"LocalExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
],
"defaultActivities": [
{
"name": "Pipeline Status Unknown",
"description": "Updates the current execution table with a pipeline status of unknown if the function returns an unexpected outcome.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineUnknown]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Get Wait Duration",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "PipelineStatusCheckDuration"
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
}
],
"parameters": {
"tenantId": {
"type": "string"
},
"applicationId": {
"type": "string"
},
"authenticationKey": {
"type": "string"
},
"subscriptionId": {
"type": "string"
},
"resourceGroup": {
"type": "string"
},
"factoryName": {
"type": "string"
},
"pipelineName": {
"type": "string"
},
"runId": {
"type": "string"
},
"executionId": {
"type": "string"
},
"stageId": {
"type": "int"
},
"pipelineId": {
"type": "int"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/FrameworkFunctions')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Intentional Error')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Call Fail Procedure",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Wait1",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[dbo].[FailProcedure]",
"storedProcedureParameters": {
"RaiseError": {
"value": {
"value": "@pipeline().parameters.RaiseErrors",
"type": "Expression"
},
"type": "String"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Wait1",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
},
{
"name": "Call Fail Notebook",
"type": "DatabricksNotebook",
"dependsOn": [
{
"activity": "Wait1",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"notebookPath": "/Playground/Throw Exception",
"baseParameters": {
"RaiseError": {
"value": "@pipeline().parameters.RaiseErrors",
"type": "Expression"
}
}
},
"linkedServiceName": {
"referenceName": "BricksOfData",
"type": "LinkedServiceReference"
}
}
],
"parameters": {
"RaiseErrors": {
"type": "string",
"defaultValue": "false"
},
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]",
"[concat(variables('factoryId'), '/linkedServices/BricksOfData')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Wait 1')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait1",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 10')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait10",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 2')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait2",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 3')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait3",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 4')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait4",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 5')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait5",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 6')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait6",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 7')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait7",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 8')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait8",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 9')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait9",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 90
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/GetSetMetadata')]",
"type": "Microsoft.DataFactory/factories/datasets",
"apiVersion": "2018-06-01",
"properties": {
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
},
"annotations": [
"ADF.procfwk"
],
"type": "AzureSqlTable",
"schema": [],
"typeProperties": {}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/BricksOfData')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"annotations": [],
"type": "AzureDatabricks",
"typeProperties": {
"domain": "https://northeurope.azuredatabricks.net",
"accessToken": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "BricksOfDataToken",
"secretVersion": ""
},
"existingClusterId": "0422-090117-slots899"
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/FrameworkFunctions')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"annotations": [
"ADF.procfwk"
],
"type": "AzureFunction",
"typeProperties": {
"functionAppUrl": "https://frameworksupportfunctions.azurewebsites.net",
"functionKey": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "FrameworkFunctionsKey"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Keys')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Connection to Key Vault for all other ADF linked service credentials required to run the processing framework.",
"annotations": [
"ADF.procfwk"
],
"type": "AzureKeyVault",
"typeProperties": {
"baseUrl": "[parameters('Keys_properties_typeProperties_baseUrl')]"
}
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/SupportDatabase')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Connection between ADF and processing framework metadata SQLDB.",
"annotations": [
"ADF.procfwk"
],
"type": "AzureSqlDatabase",
"typeProperties": {
"connectionString": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "[parameters('SupportDatabase_properties_typeProperties_connectionString_secretName')]"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/FunctionalTestingTrigger')]",
"type": "Microsoft.DataFactory/factories/triggers",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used for functional testing of the framework in a dedicated environment.",
"annotations": [
"ADF.procfwk"
],
"runtimeState": "Stopped",
"pipelines": [
{
"pipelineReference": {
"referenceName": "01-Grandparent",
"type": "PipelineReference"
},
"parameters": {}
}
],
"type": "ScheduleTrigger",
"typeProperties": {
"recurrence": {
"frequency": "Hour",
"interval": 2,
"startTime": "2020-04-06T15:00:00.000Z",
"timeZone": "UTC"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/pipelines/01-Grandparent')]"
]
}
]
}
================================================
FILE: ARM Templates/Data Factory/v1.7 Export.json
================================================
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"factoryName": {
"type": "string",
"metadata": "Data Factory name",
"defaultValue": ""
},
"Keys_properties_typeProperties_baseUrl": {
"type": "string",
"defaultValue": ""
},
"SupportDatabase_properties_typeProperties_connectionString_secretName": {
"type": "string",
"defaultValue": ""
}
},
"variables": {
"factoryId": "[concat('Microsoft.DataFactory/factories/', parameters('factoryName'))]"
},
"resources": [
{
"name": "[concat(parameters('factoryName'), '/01-Grandparent')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk grandparent pipeline used optionally to bootstrap any wider processes in your Data Factory that then calls the processing framework.",
"activities": [
{
"name": "Framework Processing",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Set Random Waits",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "02-Parent",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {}
}
},
{
"name": "Set Random Waits",
"description": "For functional testing only.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[dbo].[SetRandomWaitValues]"
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
],
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/pipelines/02-Parent')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/02-Parent')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk parent pipeline used to bootstrap the orchestration framework in perform the first level ForEach calls in sequence for the metadata stages.",
"activities": [
{
"name": "Get Stages",
"description": "Returns a distinct list of execution stages within the framework metadata.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Execution Wrapper",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetStages]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Stages",
"description": "Top level ForEach to sequentially call all processing stages within the framework metadata. Items for iteration passed from the Get Stages lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Stages",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Tenant Id",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Subscription Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Stages').output.value",
"type": "Expression"
},
"isSequential": true,
"activities": [
{
"name": "Stage Executor",
"description": "Call to the framework generic child pipeline for a given execution stage.",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Log Stage Preparing",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "03-Child",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"StageId": {
"value": "@item().StageId",
"type": "Expression"
},
"ExecutionId": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
},
"TenantId": {
"value": "@activity('Get Tenant Id').output.firstRow.PropertyValue",
"type": "Expression"
},
"SubscriptionId": {
"value": "@activity('Get Subscription Id').output.firstRow.PropertyValue",
"type": "Expression"
}
}
}
},
{
"name": "Log Stage Preparing",
"description": "Update the current execution table flagging all pipelines within the stage as preparing.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Check for Blockers",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogStagePreparing]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check for Blockers",
"description": "Used to double check and stop the next execution stage if failures and blockers have be incurred. Without this step processing would continue regardless of upstream failures.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[CheckForBlockedPipelines]",
"storedProcedureParameters": {
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Execution Wrapper",
"description": "Wrapper to reset and restart processing or create a completely new execution instance of the framework metadata.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Metadata Integrity Checks",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[ExecutionWrapper]",
"storedProcedureParameters": {
"CallingDataFactory": {
"type": "String",
"value": {
"value": "@pipeline().DataFactory",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Archive Execution Log",
"description": "After a successful execution run the current execution metadata is moved to the long term logging table by this stored procedure call.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Stages",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[UpdateExecutionLog]"
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Tenant Id",
"description": "Returning the Azure Tenant Id from the metadata properties table.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Metadata Integrity Checks",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "TenantId"
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": true
}
},
{
"name": "Get Subscription Id",
"description": "Returning the Azure Subscription Id from the metadata properties table.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Metadata Integrity Checks",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "SubscriptionId"
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Metadata Integrity Checks",
"description": "Performs a series of checks on all metadata held in the framework SQLDB. This is intended to raise errors before an execution run even starts.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[CheckMetadataIntegrity]",
"storedProcedureParameters": {
"DebugMode": {
"value": "false",
"type": "Boolean"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
],
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]",
"[concat(variables('factoryId'), '/pipelines/03-Child')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/03-Child')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk child pipeline used to execute Worker pipelines within a given execution stage. This pipeline will be called once for each stage, then execute all Workers in parallel.",
"activities": [
{
"name": "Get Pipelines",
"description": "Returns all pipelines from the metadata to be executed within a given processing stage.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelinesInStage]",
"storedProcedureParameters": {
"StageId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Pipelines",
"description": "Second level ForEach to run in parallel all pipelines within the stage. Items for iteration passed from the Get Pipelines lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Pipelines",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Pipelines').output.value",
"type": "Expression"
},
"isSequential": false,
"batchCount": 40,
"activities": [
{
"name": "Execute Pipeline",
"description": "The lowest level executor with the metadata framework to call existing processing pipelines within Data Factory. The function called will block processing and wait for an outcome.",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Log Pipeline Running",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Pipeline Params",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get SPN Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "ExecutePipeline",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n\t\"tenantId\": \"',pipeline().parameters.TenantId,'\",\n\t\"applicationId\": \"',activity('Get SPN Details').output.firstRow.Id,'\",\n\t\"authenticationKey\": \"',activity('Get SPN Details').output.firstRow.Secret,'\",\n\t\"subscriptionId\": \"',pipeline().parameters.SubscriptionId,'\",\n\t\"resourceGroup\": \"',item().ResourceGroupName,'\",\n\t\"factoryName\": \"',item().DataFactoryName,'\",\n\t\"pipelineName\": \"',item().PipelineName,'\"',activity('Get Pipeline Params').output.firstRow.Params,'\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Pipeline Params",
"description": "Returns any parameters from metadata required for the processing pipeline being called. The output can be an empty string if no parameters are required.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelineParameters]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Pipeline Running",
"description": "Sets the current pipeline with a status of running within the current execution database table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get SPN Details",
"description": "Return the SPN ID and Secret for the processing pipeline being executed. Called at this level as each pipeline can have a different SPN.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetServicePrincipal]",
"storedProcedureParameters": {
"DataFactory": {
"type": "String",
"value": {
"value": "@item().DataFactoryName",
"type": "Expression"
}
},
"PipelineName": {
"type": "String",
"value": {
"value": "@item().PipelineName",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Activity Failure",
"description": "Handle true failures from calling out to the Azure Function and update the current execution table accordingly so a restart can occur.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Pipeline",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
},
"CallingActivity": {
"value": "ExecutePipeline",
"type": "String"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Running Pipeline Handler",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Execute Pipeline",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "04-Infant",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"tenantId": {
"value": "@pipeline().parameters.TenantId",
"type": "Expression"
},
"applicationId": {
"value": "@activity('Get SPN Details').output.firstRow.Id",
"type": "Expression"
},
"authenticationKey": {
"value": "@activity('Get SPN Details').output.firstRow.Secret",
"type": "Expression"
},
"subscriptionId": {
"value": "@pipeline().parameters.SubscriptionId",
"type": "Expression"
},
"resourceGroup": {
"value": "@item().ResourceGroupName",
"type": "Expression"
},
"factoryName": {
"value": "@item().DataFactoryName",
"type": "Expression"
},
"pipelineName": {
"value": "@item().PipelineName",
"type": "Expression"
},
"runId": {
"value": "@activity('Execute Pipeline').output.RunId",
"type": "Expression"
},
"executionId": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"stageId": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"pipelineId": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
}
},
{
"name": "Set Run Id",
"description": "Provide the actual ADF run ID back to the current execution table for long term logging and alignment between the metadata other Azure monitoring tools.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Pipeline",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunId]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@activity('Execute Pipeline').output.RunId",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check For Alerts",
"description": "Checks the properties tables and if any recipients in the database require alerts sending for the current pipeline ID.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[CheckForEmailAlerts]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": true
}
},
{
"name": "Send Alerts",
"description": "True = alerts need sending.\nFalse = do nothing.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Set Run Id",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Check For Alerts",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Running Pipeline Handler",
"dependencyConditions": [
"Completed"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@activity('Check For Alerts').output.firstRow.SendAlerts",
"type": "Expression"
},
"ifTrueActivities": [
{
"name": "Get Email Parts",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetEmailAlertParts]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": true
}
},
{
"name": "Send Email",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Get Email Parts",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "SendEmail",
"method": "POST",
"headers": {},
"body": {
"value": "@activity('Get Email Parts').output.firstRow",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
}
]
}
}
]
}
}
],
"parameters": {
"StageId": {
"type": "int"
},
"ExecutionId": {
"type": "string"
},
"TenantId": {
"type": "string"
},
"SubscriptionId": {
"type": "string"
}
},
"variables": {
"FunctionBody": {
"type": "String"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/FrameworkFunctions')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]",
"[concat(variables('factoryId'), '/pipelines/04-Infant')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/04-Infant')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk infant pipeline used to check when the processing pipeline called by the Child completes and passes the resulting status back to the metadata database.",
"activities": [
{
"name": "Wait Until Pipeline Completes",
"description": "Loops until the pipeline called completes.\n\nSimple status:\n- Running = new iteration.\n- Done = break.",
"type": "Until",
"dependsOn": [
{
"activity": "Get Wait Duration",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@equals('Done',activity('Get Pipeline Status').output.SimpleStatus)",
"type": "Expression"
},
"activities": [
{
"name": "Get Pipeline Status",
"description": "Checks the status of a given processing pipeline and provides the value for the downstream framework activities to act upon.",
"type": "AzureFunctionActivity",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "CheckPipelineStatus",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',pipeline().parameters.TenantId,'\",\n \"applicationId\": \"',pipeline().parameters.applicationId,'\",\n \"authenticationKey\": \"',pipeline().parameters.authenticationKey,'\",\n \"subscriptionId\": \"',pipeline().parameters.subscriptionId,'\",\n \"resourceGroup\": \"',pipeline().parameters.resourceGroup,'\",\n \"factoryName\": \"',pipeline().parameters.factoryName,'\",\n \"pipelineName\": \"',pipeline().parameters.pipelineName,'\",\n \"runId\": \"',pipeline().parameters.runId,'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Wait If Running",
"description": "True = Do nothing.\nFalse = Wait.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@equals('Done',activity('Get Pipeline Status').output.SimpleStatus)",
"type": "Expression"
},
"ifFalseActivities": [
{
"name": "Wait for Pipeline",
"description": "The processing pipeline is still running so Wait before checking its status again.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@activity('Get Wait Duration').output.firstRow.PropertyValue",
"type": "Expression"
}
}
}
]
}
},
{
"name": "Set Last Update",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineLastStatusCheck]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Activity Failure",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"CallingActivity": {
"value": "GetPipelineStatus",
"type": "String"
},
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
],
"timeout": "7.00:00:00"
}
},
{
"name": "Pipeline Result",
"description": "Receives the outcome from the function execution for a given processing pipeline and updates the current execution table with different pipelines status values depending on the result (case).",
"type": "Switch",
"dependsOn": [
{
"activity": "Wait Until Pipeline Completes",
"dependencyConditions": [
"Completed"
]
}
],
"userProperties": [],
"typeProperties": {
"on": {
"value": "@activity('Get Pipeline Status').output.Status",
"type": "Expression"
},
"cases": [
{
"value": "Succeeded",
"activities": [
{
"name": "Pipeline Status Succeeded",
"description": "Updates the current execution table with a pipeline status of success if the function outcome is succeeded.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineSuccess]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Failed",
"activities": [
{
"name": "Pipeline Status Failed",
"description": "Updates the current execution table with a pipeline status of failed if the function outcome is failed. Also blocks pipelines in the downstream execution stage.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@activity('Get Pipeline Status').output.RunId",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Error Details",
"description": "Get the activity error details for the run ID of the worker pipeline called. Returns an array of all errors.",
"type": "AzureFunctionActivity",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "GetActivityErrors",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',pipeline().parameters.TenantId,'\",\n \"applicationId\": \"',pipeline().parameters.applicationId,'\",\n \"authenticationKey\": \"',pipeline().parameters.authenticationKey,'\",\n \"subscriptionId\": \"',pipeline().parameters.subscriptionId,'\",\n \"resourceGroup\": \"',pipeline().parameters.resourceGroup,'\",\n \"factoryName\": \"',pipeline().parameters.factoryName,'\",\n \"pipelineName\": \"',pipeline().parameters.pipelineName,'\",\n \"runId\": \"',pipeline().parameters.runId,'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Error Details",
"description": "Parses pipeline error details and persists them to the metadata database error log table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Error Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetErrorLogDetails]",
"storedProcedureParameters": {
"JsonErrorDetails": {
"value": {
"value": "@string(activity('Get Error Details').output)",
"type": "Expression"
},
"type": "String"
},
"LocalExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
],
"defaultActivities": [
{
"name": "Pipeline Status Unknown",
"description": "Updates the current execution table with a pipeline status of unknown if the function returns an unexpected outcome.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineUnknown]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Get Wait Duration",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "PipelineStatusCheckDuration"
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
}
],
"parameters": {
"tenantId": {
"type": "string"
},
"applicationId": {
"type": "string"
},
"authenticationKey": {
"type": "string"
},
"subscriptionId": {
"type": "string"
},
"resourceGroup": {
"type": "string"
},
"factoryName": {
"type": "string"
},
"pipelineName": {
"type": "string"
},
"runId": {
"type": "string"
},
"executionId": {
"type": "string"
},
"stageId": {
"type": "int"
},
"pipelineId": {
"type": "int"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/FrameworkFunctions')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Intentional Error')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait1",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
},
{
"name": "Raise Errors or Not",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Wait1",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@equals(pipeline().parameters.RaiseErrors,'true')",
"type": "Expression"
},
"ifTrueActivities": [
{
"name": "Call Fail Procedure",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[dbo].[FailProcedure]",
"storedProcedureParameters": {
"RaiseError": {
"value": {
"value": "@pipeline().parameters.RaiseErrors",
"type": "Expression"
},
"type": "String"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Call Fail Notebook",
"type": "DatabricksNotebook",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"notebookPath": "/Playground/Throw Exception",
"baseParameters": {
"RaiseError": {
"value": "@pipeline().parameters.RaiseErrors",
"type": "Expression"
}
}
},
"linkedServiceName": {
"referenceName": "BricksOfData",
"type": "LinkedServiceReference"
}
}
]
}
}
],
"parameters": {
"RaiseErrors": {
"type": "string",
"defaultValue": "false"
},
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]",
"[concat(variables('factoryId'), '/linkedServices/BricksOfData')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Wait 1')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait1",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 10')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait10",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 2')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait2",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 3')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait3",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 4')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait4",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 5')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait5",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 6')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait6",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 7')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait7",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 8')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait8",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 9')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait9",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 90
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/GetSetMetadata')]",
"type": "Microsoft.DataFactory/factories/datasets",
"apiVersion": "2018-06-01",
"properties": {
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
},
"annotations": [
"ADF.procfwk"
],
"type": "AzureSqlTable",
"schema": [],
"typeProperties": {}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/BricksOfData')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"annotations": [],
"type": "AzureDatabricks",
"typeProperties": {
"domain": "https://northeurope.azuredatabricks.net",
"accessToken": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "BricksOfDataToken",
"secretVersion": ""
},
"existingClusterId": "0422-090117-slots899"
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/FrameworkFunctions')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"annotations": [
"ADF.procfwk"
],
"type": "AzureFunction",
"typeProperties": {
"functionAppUrl": "https://frameworksupportfunctions.azurewebsites.net",
"functionKey": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "FrameworkFunctionsKey"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Keys')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Connection to Key Vault for all other ADF linked service credentials required to run the processing framework.",
"annotations": [
"ADF.procfwk"
],
"type": "AzureKeyVault",
"typeProperties": {
"baseUrl": "[parameters('Keys_properties_typeProperties_baseUrl')]"
}
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/SupportDatabase')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Connection between ADF and processing framework metadata SQLDB.",
"annotations": [
"ADF.procfwk"
],
"type": "AzureSqlDatabase",
"typeProperties": {
"connectionString": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "[parameters('SupportDatabase_properties_typeProperties_connectionString_secretName')]"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/FunctionalTestingTrigger')]",
"type": "Microsoft.DataFactory/factories/triggers",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used for functional testing of the framework in a dedicated environment.",
"annotations": [
"ADF.procfwk"
],
"runtimeState": "Stopped",
"pipelines": [
{
"pipelineReference": {
"referenceName": "01-Grandparent",
"type": "PipelineReference"
},
"parameters": {}
}
],
"type": "ScheduleTrigger",
"typeProperties": {
"recurrence": {
"frequency": "Hour",
"interval": 2,
"startTime": "2020-04-06T15:00:00.000Z",
"timeZone": "UTC"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/pipelines/01-Grandparent')]"
]
}
]
}
================================================
FILE: ARM Templates/Data Factory/v1.8 Export.json
================================================
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"factoryName": {
"type": "string",
"metadata": "Data Factory name",
"defaultValue": ""
},
"FrameworkFunctions_properties_typeProperties_functionAppUrl": {
"type": "string",
"defaultValue": ""
},
"Keys_properties_typeProperties_baseUrl": {
"type": "string",
"defaultValue": ""
},
"SupportDatabase_properties_typeProperties_connectionString_secretName": {
"type": "string",
"defaultValue": ""
}
},
"variables": {
"factoryId": "[concat('Microsoft.DataFactory/factories/', parameters('factoryName'))]"
},
"resources": [
{
"name": "[concat(parameters('factoryName'), '/01-Grandparent')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk grandparent pipeline used optionally to bootstrap any wider processes in your Data Factory that then calls the processing framework.",
"activities": [
{
"name": "Framework Processing",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Set Random Waits",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "02-Parent",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {}
}
},
{
"name": "Set Random Waits",
"description": "For functional testing only.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[dbo].[SetRandomWaitValues]"
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
],
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/pipelines/02-Parent')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/02-Parent')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk parent pipeline used to bootstrap the orchestration framework in perform the first level ForEach calls in sequence for the metadata stages.",
"activities": [
{
"name": "Get Stages",
"description": "Returns a distinct list of execution stages within the framework metadata.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Execution Wrapper",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetStages]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Stages",
"description": "Top level ForEach to sequentially call all processing stages within the framework metadata. Items for iteration passed from the Get Stages lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Stages",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Tenant Id",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Subscription Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Stages').output.value",
"type": "Expression"
},
"isSequential": true,
"activities": [
{
"name": "Stage Executor",
"description": "Call to the framework generic child pipeline for a given execution stage.",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Log Stage Preparing",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "03-Child",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"StageId": {
"value": "@item().StageId",
"type": "Expression"
},
"ExecutionId": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
},
"TenantId": {
"value": "@activity('Get Tenant Id').output.firstRow.PropertyValue",
"type": "Expression"
},
"SubscriptionId": {
"value": "@activity('Get Subscription Id').output.firstRow.PropertyValue",
"type": "Expression"
}
}
}
},
{
"name": "Log Stage Preparing",
"description": "Update the current execution table flagging all pipelines within the stage as preparing.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Check and Update Blockers",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogStagePreparing]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check and Update Blockers",
"description": "Used to double check and stop the next execution stage if failures and blockers have be incurred. This also depends on the failure handling property value which defines the stored procedure behaviour.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[CheckForBlockedPipelines]",
"storedProcedureParameters": {
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Execution Wrapper",
"description": "Wrapper to reset and restart processing or create a completely new execution instance of the framework metadata.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Clean Up Previous Run",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[ExecutionWrapper]",
"storedProcedureParameters": {
"CallingDataFactory": {
"type": "String",
"value": {
"value": "@pipeline().DataFactory",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Check Outcome and Update Logs",
"description": "After a successful execution run the current execution metadata is moved to the long term logging table by this stored procedure call. Otherwise an error will be raised.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Stages",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[UpdateExecutionLog]"
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Tenant Id",
"description": "Returning the Azure Tenant Id from the metadata properties table.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Metadata Integrity Checks",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "TenantId"
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": true
}
},
{
"name": "Get Subscription Id",
"description": "Returning the Azure Subscription Id from the metadata properties table.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Metadata Integrity Checks",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "SubscriptionId"
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Metadata Integrity Checks",
"description": "Performs a series of checks on all metadata held in the framework SQLDB. This is intended to raise errors before an execution run even starts.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[CheckMetadataIntegrity]",
"storedProcedureParameters": {
"DebugMode": {
"type": "Boolean",
"value": "false"
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Clean Up Previous Run",
"description": "Handle Worker pipelines that are reported as Running when the parent pipeline is called again. Get what the actual status of those pipelines is.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Metadata Integrity Checks",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Metadata Integrity Checks').output.value",
"type": "Expression"
},
"isSequential": false,
"activities": [
{
"name": "Get SPN Details",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetServicePrincipal]",
"storedProcedureParameters": {
"DataFactory": {
"type": "String",
"value": {
"value": "@item().DataFactoryName",
"type": "Expression"
}
},
"PipelineName": {
"type": "String",
"value": {
"value": "@item().PipelineName",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Pipeline Checking",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineChecking]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Pipeline Status",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Get SPN Details",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Log Pipeline Checking",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "CheckPipelineStatus",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',item().TenantId,'\",\n \"applicationId\": \"',activity('Get SPN Details').output.firstRow.Id,'\",\n \"authenticationKey\": \"',activity('Get SPN Details').output.firstRow.Secret,'\",\n \"subscriptionId\": \"',item().SubscriptionId,'\",\n \"resourceGroup\": \"',item().ResourceGroupName,'\",\n \"factoryName\": \"',item().DataFactoryName,'\",\n \"pipelineName\": \"',item().PipelineName,'\",\n \"runId\": \"',item().AdfPipelineRunId,'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Set Pipeline Status",
"type": "Switch",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"on": {
"value": "@activity('Get Pipeline Status').output.Status",
"type": "Expression"
},
"cases": [
{
"value": "Failed",
"activities": [
{
"name": "Pipeline Status Failed",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": null,
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Succeeded",
"activities": [
{
"name": "Pipeline Status Succeeded",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineSuccess]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Queued",
"activities": [
{
"name": "Pipeline Status Queued - Running",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "InProgress",
"activities": [
{
"name": "Pipeline Status InProgress - Running",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
],
"defaultActivities": [
{
"name": "Pipeline Status Unknown",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineUnknown]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Set Last Check DateTime",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineLastStatusCheck]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
}
],
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]",
"[concat(variables('factoryId'), '/pipelines/03-Child')]",
"[concat(variables('factoryId'), '/linkedServices/FrameworkFunctions')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/03-Child')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk child pipeline used to execute Worker pipelines within a given execution stage. This pipeline will be called once for each stage, then execute all Workers in parallel.",
"activities": [
{
"name": "Get Pipelines",
"description": "Returns all pipelines from the metadata to be executed within a given processing stage.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelinesInStage]",
"storedProcedureParameters": {
"StageId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Pipelines",
"description": "Second level ForEach to run in parallel all pipelines within the stage. Items for iteration passed from the Get Pipelines lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Pipelines",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Pipelines').output.value",
"type": "Expression"
},
"isSequential": false,
"batchCount": 40,
"activities": [
{
"name": "Execute Pipeline",
"description": "The lowest level executor with the metadata framework to call existing processing pipelines within Data Factory. The function called will block processing and wait for an outcome.",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Log Pipeline Running",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Pipeline Params",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get SPN Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "ExecutePipeline",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n\t\"tenantId\": \"',pipeline().parameters.TenantId,'\",\n\t\"applicationId\": \"',activity('Get SPN Details').output.firstRow.Id,'\",\n\t\"authenticationKey\": \"',activity('Get SPN Details').output.firstRow.Secret,'\",\n\t\"subscriptionId\": \"',pipeline().parameters.SubscriptionId,'\",\n\t\"resourceGroup\": \"',item().ResourceGroupName,'\",\n\t\"factoryName\": \"',item().DataFactoryName,'\",\n\t\"pipelineName\": \"',item().PipelineName,'\"',activity('Get Pipeline Params').output.firstRow.Params,'\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Pipeline Params",
"description": "Returns any parameters from metadata required for the processing pipeline being called. The output can be an empty string if no parameters are required.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelineParameters]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Pipeline Running",
"description": "Sets the current pipeline with a status of running within the current execution database table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get SPN Details",
"description": "Return the SPN ID and Secret for the processing pipeline being executed. Called at this level as each pipeline can have a different SPN.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetServicePrincipal]",
"storedProcedureParameters": {
"DataFactory": {
"type": "String",
"value": {
"value": "@item().DataFactoryName",
"type": "Expression"
}
},
"PipelineName": {
"type": "String",
"value": {
"value": "@item().PipelineName",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Activity Failure",
"description": "Handle true failures from calling out to the Azure Function and update the current execution table accordingly so a restart can occur.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Pipeline",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
},
"CallingActivity": {
"value": "ExecutePipeline",
"type": "String"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Running Pipeline Handler",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Execute Pipeline",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "04-Infant",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"tenantId": {
"value": "@pipeline().parameters.TenantId",
"type": "Expression"
},
"applicationId": {
"value": "@activity('Get SPN Details').output.firstRow.Id",
"type": "Expression"
},
"authenticationKey": {
"value": "@activity('Get SPN Details').output.firstRow.Secret",
"type": "Expression"
},
"subscriptionId": {
"value": "@pipeline().parameters.SubscriptionId",
"type": "Expression"
},
"resourceGroup": {
"value": "@item().ResourceGroupName",
"type": "Expression"
},
"factoryName": {
"value": "@item().DataFactoryName",
"type": "Expression"
},
"pipelineName": {
"value": "@item().PipelineName",
"type": "Expression"
},
"runId": {
"value": "@activity('Execute Pipeline').output.RunId",
"type": "Expression"
},
"executionId": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"stageId": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"pipelineId": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
}
},
{
"name": "Set Run Id",
"description": "Provide the actual ADF run ID back to the current execution table for long term logging and alignment between the metadata other Azure monitoring tools.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Pipeline",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunId]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@activity('Execute Pipeline').output.RunId",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check For Alerts",
"description": "Checks the properties tables and if any recipients in the database require alerts sending for the current pipeline ID.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[CheckForEmailAlerts]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": true
}
},
{
"name": "Send Alerts",
"description": "True = alerts need sending.\nFalse = do nothing.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Set Run Id",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Check For Alerts",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Running Pipeline Handler",
"dependencyConditions": [
"Completed"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@activity('Check For Alerts').output.firstRow.SendAlerts",
"type": "Expression"
},
"ifTrueActivities": [
{
"name": "Get Email Parts",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetEmailAlertParts]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": true
}
},
{
"name": "Send Email",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Get Email Parts",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "SendEmail",
"method": "POST",
"headers": {},
"body": {
"value": "@activity('Get Email Parts').output.firstRow",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
}
]
}
}
]
}
}
],
"parameters": {
"StageId": {
"type": "int"
},
"ExecutionId": {
"type": "string"
},
"TenantId": {
"type": "string"
},
"SubscriptionId": {
"type": "string"
}
},
"variables": {
"FunctionBody": {
"type": "String"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/FrameworkFunctions')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]",
"[concat(variables('factoryId'), '/pipelines/04-Infant')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/04-Infant')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk infant pipeline used to check when the processing pipeline called by the Child completes and passes the resulting status back to the metadata database.",
"activities": [
{
"name": "Wait Until Pipeline Completes",
"description": "Loops until the pipeline called completes.\n\nSimple status:\n- Running = new iteration.\n- Done = break.",
"type": "Until",
"dependsOn": [
{
"activity": "Get Wait Duration",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@equals('Done',activity('Get Pipeline Status').output.SimpleStatus)",
"type": "Expression"
},
"activities": [
{
"name": "Get Pipeline Status",
"description": "Checks the status of a given processing pipeline and provides the value for the downstream framework activities to act upon.",
"type": "AzureFunctionActivity",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "CheckPipelineStatus",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',pipeline().parameters.TenantId,'\",\n \"applicationId\": \"',pipeline().parameters.applicationId,'\",\n \"authenticationKey\": \"',pipeline().parameters.authenticationKey,'\",\n \"subscriptionId\": \"',pipeline().parameters.subscriptionId,'\",\n \"resourceGroup\": \"',pipeline().parameters.resourceGroup,'\",\n \"factoryName\": \"',pipeline().parameters.factoryName,'\",\n \"pipelineName\": \"',pipeline().parameters.pipelineName,'\",\n \"runId\": \"',pipeline().parameters.runId,'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Wait If Running",
"description": "True = Do nothing.\nFalse = Wait.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@equals('Done',activity('Get Pipeline Status').output.SimpleStatus)",
"type": "Expression"
},
"ifFalseActivities": [
{
"name": "Wait for Pipeline",
"description": "The processing pipeline is still running so Wait before checking its status again.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@activity('Get Wait Duration').output.firstRow.PropertyValue",
"type": "Expression"
}
}
}
]
}
},
{
"name": "Set Last Check DateTime",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineLastStatusCheck]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Activity Failure",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"CallingActivity": {
"value": "GetPipelineStatus",
"type": "String"
},
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
],
"timeout": "7.00:00:00"
}
},
{
"name": "Set Pipeline Result",
"description": "Receives the outcome from the function execution for a given processing pipeline and updates the current execution table with different pipelines status values depending on the result (case).",
"type": "Switch",
"dependsOn": [
{
"activity": "Wait Until Pipeline Completes",
"dependencyConditions": [
"Completed"
]
}
],
"userProperties": [],
"typeProperties": {
"on": {
"value": "@activity('Get Pipeline Status').output.Status",
"type": "Expression"
},
"cases": [
{
"value": "Succeeded",
"activities": [
{
"name": "Pipeline Status Succeeded",
"description": "Updates the current execution table with a pipeline status of success if the function outcome is succeeded.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineSuccess]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Failed",
"activities": [
{
"name": "Pipeline Status Failed",
"description": "Updates the current execution table with a pipeline status of failed if the function outcome is failed. Also blocks pipelines in the downstream execution stage.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@activity('Get Pipeline Status').output.RunId",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Error Details",
"description": "Get the activity error details for the run ID of the worker pipeline called. Returns an array of all errors.",
"type": "AzureFunctionActivity",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "GetActivityErrors",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',pipeline().parameters.TenantId,'\",\n \"applicationId\": \"',pipeline().parameters.applicationId,'\",\n \"authenticationKey\": \"',pipeline().parameters.authenticationKey,'\",\n \"subscriptionId\": \"',pipeline().parameters.subscriptionId,'\",\n \"resourceGroup\": \"',pipeline().parameters.resourceGroup,'\",\n \"factoryName\": \"',pipeline().parameters.factoryName,'\",\n \"pipelineName\": \"',pipeline().parameters.pipelineName,'\",\n \"runId\": \"',pipeline().parameters.runId,'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Error Details",
"description": "Parses pipeline error details and persists them to the metadata database error log table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Error Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetErrorLogDetails]",
"storedProcedureParameters": {
"JsonErrorDetails": {
"value": {
"value": "@string(activity('Get Error Details').output)",
"type": "Expression"
},
"type": "String"
},
"LocalExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
],
"defaultActivities": [
{
"name": "Pipeline Status Unknown",
"description": "Updates the current execution table with a pipeline status of unknown if the function returns an unexpected outcome.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineUnknown]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Get Wait Duration",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "PipelineStatusCheckDuration"
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
}
],
"parameters": {
"tenantId": {
"type": "string"
},
"applicationId": {
"type": "string"
},
"authenticationKey": {
"type": "string"
},
"subscriptionId": {
"type": "string"
},
"resourceGroup": {
"type": "string"
},
"factoryName": {
"type": "string"
},
"pipelineName": {
"type": "string"
},
"runId": {
"type": "string"
},
"executionId": {
"type": "string"
},
"stageId": {
"type": "int"
},
"pipelineId": {
"type": "int"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/FrameworkFunctions')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Intentional Error')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait1",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
},
{
"name": "Raise Errors or Not",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Wait1",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@equals(pipeline().parameters.RaiseErrors,'true')",
"type": "Expression"
},
"ifTrueActivities": [
{
"name": "Call Fail Procedure",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[dbo].[FailProcedure]",
"storedProcedureParameters": {
"RaiseError": {
"value": {
"value": "@pipeline().parameters.RaiseErrors",
"type": "Expression"
},
"type": "String"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
}
],
"parameters": {
"RaiseErrors": {
"type": "string",
"defaultValue": "false"
},
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Wait 1')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait1",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 10')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait10",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 2')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait2",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 3')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait3",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 4')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait4",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 5')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait5",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 6')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait6",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 7')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait7",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 8')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait8",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int"
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 9')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait9",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 15
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/GetSetMetadata')]",
"type": "Microsoft.DataFactory/factories/datasets",
"apiVersion": "2018-06-01",
"properties": {
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
},
"annotations": [
"ADF.procfwk"
],
"type": "AzureSqlTable",
"schema": [],
"typeProperties": {}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/FrameworkFunctions')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"annotations": [
"ADF.procfwk"
],
"type": "AzureFunction",
"typeProperties": {
"functionAppUrl": "[parameters('FrameworkFunctions_properties_typeProperties_functionAppUrl')]",
"functionKey": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "FrameworkFunctionsKey"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Keys')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Connection to Key Vault for all other ADF linked service credentials required to run the processing framework.",
"annotations": [
"ADF.procfwk"
],
"type": "AzureKeyVault",
"typeProperties": {
"baseUrl": "[parameters('Keys_properties_typeProperties_baseUrl')]"
}
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/SupportDatabase')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Connection between ADF and processing framework metadata SQLDB.",
"annotations": [
"ADF.procfwk"
],
"type": "AzureSqlDatabase",
"typeProperties": {
"connectionString": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "[parameters('SupportDatabase_properties_typeProperties_connectionString_secretName')]"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/FunctionalTestingTrigger')]",
"type": "Microsoft.DataFactory/factories/triggers",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used for functional testing of the framework in a dedicated environment.",
"annotations": [
"ADF.procfwk"
],
"runtimeState": "Stopped",
"pipelines": [
{
"pipelineReference": {
"referenceName": "01-Grandparent",
"type": "PipelineReference"
},
"parameters": {}
}
],
"type": "ScheduleTrigger",
"typeProperties": {
"recurrence": {
"frequency": "Hour",
"interval": 2,
"startTime": "2020-04-06T15:00:00.000Z",
"timeZone": "UTC"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/pipelines/01-Grandparent')]"
]
}
]
}
================================================
FILE: ARM Templates/Data Factory/v1.8.3 Export.json
================================================
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"factoryName": {
"type": "string",
"metadata": "Data Factory name",
"defaultValue": "FrameworkFactory"
},
"FrameworkFunctions_properties_typeProperties_functionAppUrl": {
"type": "string",
"defaultValue": ""
},
"Keys_properties_typeProperties_baseUrl": {
"type": "string",
"defaultValue": ""
},
"SupportDatabase_properties_typeProperties_connectionString_secretName": {
"type": "string",
"defaultValue": ""
}
},
"variables": {
"factoryId": "[concat('Microsoft.DataFactory/factories/', parameters('factoryName'))]"
},
"resources": [
{
"name": "[concat(parameters('factoryName'), '/01-Grandparent')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk grandparent pipeline used optionally to bootstrap any wider processes in your Data Factory that then calls the processing framework.",
"activities": [
{
"name": "Framework Processing",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Set Random Waits",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "02-Parent",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {}
}
},
{
"name": "Set Random Waits",
"description": "For functional testing only.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[dbo].[SetRandomWaitValues]"
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
],
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/pipelines/02-Parent')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/02-Parent')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk parent pipeline used to bootstrap the orchestration framework in perform the first level ForEach calls in sequence for the metadata stages.",
"activities": [
{
"name": "Get Stages",
"description": "Returns a distinct list of execution stages within the framework metadata.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Execution Wrapper",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetStages]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Stages",
"description": "Top level ForEach to sequentially call all processing stages within the framework metadata. Items for iteration passed from the Get Stages lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Stages",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Tenant Id",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Subscription Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Stages').output.value",
"type": "Expression"
},
"isSequential": true,
"activities": [
{
"name": "Stage Executor",
"description": "Call to the framework generic child pipeline for a given execution stage.",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Log Stage Preparing",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "03-Child",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"StageId": {
"value": "@item().StageId",
"type": "Expression"
},
"ExecutionId": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
},
"TenantId": {
"value": "@activity('Get Tenant Id').output.firstRow.PropertyValue",
"type": "Expression"
},
"SubscriptionId": {
"value": "@activity('Get Subscription Id').output.firstRow.PropertyValue",
"type": "Expression"
}
}
}
},
{
"name": "Log Stage Preparing",
"description": "Update the current execution table flagging all pipelines within the stage as preparing.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Check and Update Blockers",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogStagePreparing]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check and Update Blockers",
"description": "Used to double check and stop the next execution stage if failures and blockers have be incurred. This also depends on the failure handling property value which defines the stored procedure behaviour.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[CheckForBlockedPipelines]",
"storedProcedureParameters": {
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Execution Wrapper",
"description": "Wrapper to reset and restart processing or create a completely new execution instance of the framework metadata.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Clean Up Previous Run",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[ExecutionWrapper]",
"storedProcedureParameters": {
"CallingDataFactory": {
"type": "String",
"value": {
"value": "@pipeline().DataFactory",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Check Outcome and Update Logs",
"description": "After a successful execution run the current execution metadata is moved to the long term logging table by this stored procedure call. Otherwise an error will be raised.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Stages",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[UpdateExecutionLog]"
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Tenant Id",
"description": "Returning the Azure Tenant Id from the metadata properties table.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Metadata Integrity Checks",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "TenantId"
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": true
}
},
{
"name": "Get Subscription Id",
"description": "Returning the Azure Subscription Id from the metadata properties table.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Metadata Integrity Checks",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "SubscriptionId"
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Metadata Integrity Checks",
"description": "Performs a series of checks on all metadata held in the framework SQLDB. This is intended to raise errors before an execution run even starts.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[CheckMetadataIntegrity]",
"storedProcedureParameters": {
"DebugMode": {
"type": "Boolean",
"value": "false"
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Clean Up Previous Run",
"description": "Handle Worker pipelines that are reported as Running when the parent pipeline is called again. Get what the actual status of those pipelines is.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Metadata Integrity Checks",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Metadata Integrity Checks').output.value",
"type": "Expression"
},
"isSequential": false,
"activities": [
{
"name": "Get SPN Details",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetServicePrincipal]",
"storedProcedureParameters": {
"DataFactory": {
"type": "String",
"value": {
"value": "@item().DataFactoryName",
"type": "Expression"
}
},
"PipelineName": {
"type": "String",
"value": {
"value": "@item().PipelineName",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Pipeline Checking",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineChecking]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Pipeline Status",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Get SPN Details",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Log Pipeline Checking",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "CheckPipelineStatus",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',item().TenantId,'\",\n \"applicationId\": \"',activity('Get SPN Details').output.firstRow.Id,'\",\n \"authenticationKey\": \"',activity('Get SPN Details').output.firstRow.Secret,'\",\n \"subscriptionId\": \"',item().SubscriptionId,'\",\n \"resourceGroup\": \"',item().ResourceGroupName,'\",\n \"factoryName\": \"',item().DataFactoryName,'\",\n \"pipelineName\": \"',item().PipelineName,'\",\n \"runId\": \"',item().AdfPipelineRunId,'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Set Pipeline Status",
"type": "Switch",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"on": {
"value": "@activity('Get Pipeline Status').output.Status",
"type": "Expression"
},
"cases": [
{
"value": "Failed",
"activities": [
{
"name": "Pipeline Status Failed",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": null,
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Succeeded",
"activities": [
{
"name": "Pipeline Status Succeeded",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineSuccess]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Queued",
"activities": [
{
"name": "Pipeline Status Queued - Running",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "InProgress",
"activities": [
{
"name": "Pipeline Status InProgress - Running",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Cancelled",
"activities": [
{
"name": "Pipeline Status Cancelled",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineCancelled]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
],
"defaultActivities": [
{
"name": "Pipeline Status Unknown",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineUnknown]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Set Last Check DateTime",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineLastStatusCheck]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
}
],
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]",
"[concat(variables('factoryId'), '/pipelines/03-Child')]",
"[concat(variables('factoryId'), '/linkedServices/FrameworkFunctions')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/03-Child')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk child pipeline used to execute Worker pipelines within a given execution stage. This pipeline will be called once for each stage, then execute all Workers in parallel.",
"activities": [
{
"name": "Get Pipelines",
"description": "Returns all pipelines from the metadata to be executed within a given processing stage.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelinesInStage]",
"storedProcedureParameters": {
"StageId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Pipelines",
"description": "Second level ForEach to run in parallel all pipelines within the stage. Items for iteration passed from the Get Pipelines lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Pipelines",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Pipelines').output.value",
"type": "Expression"
},
"isSequential": false,
"batchCount": 40,
"activities": [
{
"name": "Execute Pipeline",
"description": "The lowest level executor with the metadata framework to call existing processing pipelines within Data Factory. The function called will block processing and wait for an outcome.",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Log Pipeline Running",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Pipeline Params",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get SPN Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "ExecutePipeline",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n\t\"tenantId\": \"',pipeline().parameters.TenantId,'\",\n\t\"applicationId\": \"',activity('Get SPN Details').output.firstRow.Id,'\",\n\t\"authenticationKey\": \"',activity('Get SPN Details').output.firstRow.Secret,'\",\n\t\"subscriptionId\": \"',pipeline().parameters.SubscriptionId,'\",\n\t\"resourceGroup\": \"',item().ResourceGroupName,'\",\n\t\"factoryName\": \"',item().DataFactoryName,'\",\n\t\"pipelineName\": \"',item().PipelineName,'\"',activity('Get Pipeline Params').output.firstRow.Params,'\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Pipeline Params",
"description": "Returns any parameters from metadata required for the processing pipeline being called. The output can be an empty string if no parameters are required.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelineParameters]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Pipeline Running",
"description": "Sets the current pipeline with a status of running within the current execution database table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get SPN Details",
"description": "Return the SPN ID and Secret for the processing pipeline being executed. Called at this level as each pipeline can have a different SPN.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetServicePrincipal]",
"storedProcedureParameters": {
"DataFactory": {
"type": "String",
"value": {
"value": "@item().DataFactoryName",
"type": "Expression"
}
},
"PipelineName": {
"type": "String",
"value": {
"value": "@item().PipelineName",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Activity Failure",
"description": "Handle true failures from calling out to the Azure Function and update the current execution table accordingly so a restart can occur.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Pipeline",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
},
"CallingActivity": {
"value": "ExecutePipeline",
"type": "String"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Running Pipeline Handler",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Execute Pipeline",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "04-Infant",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"tenantId": {
"value": "@pipeline().parameters.TenantId",
"type": "Expression"
},
"applicationId": {
"value": "@activity('Get SPN Details').output.firstRow.Id",
"type": "Expression"
},
"authenticationKey": {
"value": "@activity('Get SPN Details').output.firstRow.Secret",
"type": "Expression"
},
"subscriptionId": {
"value": "@pipeline().parameters.SubscriptionId",
"type": "Expression"
},
"resourceGroup": {
"value": "@item().ResourceGroupName",
"type": "Expression"
},
"factoryName": {
"value": "@item().DataFactoryName",
"type": "Expression"
},
"pipelineName": {
"value": "@item().PipelineName",
"type": "Expression"
},
"runId": {
"value": "@activity('Execute Pipeline').output.RunId",
"type": "Expression"
},
"executionId": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"stageId": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"pipelineId": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
}
},
{
"name": "Set Run Id",
"description": "Provide the actual ADF run ID back to the current execution table for long term logging and alignment between the metadata other Azure monitoring tools.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Pipeline",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunId]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@activity('Execute Pipeline').output.RunId",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check For Alerts",
"description": "Checks the properties tables and if any recipients in the database require alerts sending for the current pipeline ID.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Set Run Id",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Running Pipeline Handler",
"dependencyConditions": [
"Completed"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[CheckForEmailAlerts]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": true
}
},
{
"name": "Send Alerts",
"description": "True = alerts need sending.\nFalse = do nothing.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Check For Alerts",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@activity('Check For Alerts').output.firstRow.SendAlerts",
"type": "Expression"
},
"ifTrueActivities": [
{
"name": "Get Email Parts",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetEmailAlertParts]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": true
}
},
{
"name": "Send Email",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Get Email Parts",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "SendEmail",
"method": "POST",
"headers": {},
"body": {
"value": "@activity('Get Email Parts').output.firstRow",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
}
]
}
}
]
}
}
],
"parameters": {
"StageId": {
"type": "int"
},
"ExecutionId": {
"type": "string"
},
"TenantId": {
"type": "string"
},
"SubscriptionId": {
"type": "string"
}
},
"variables": {
"FunctionBody": {
"type": "String"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/FrameworkFunctions')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]",
"[concat(variables('factoryId'), '/pipelines/04-Infant')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/04-Infant')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk infant pipeline used to check when the processing pipeline called by the Child completes and passes the resulting status back to the metadata database.",
"activities": [
{
"name": "Wait Until Pipeline Completes",
"description": "Loops until the pipeline called completes.\n\nSimple status:\n- Running = new iteration.\n- Done = break.",
"type": "Until",
"dependsOn": [
{
"activity": "Get Wait Duration",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@equals('Done',activity('Get Pipeline Status').output.SimpleStatus)",
"type": "Expression"
},
"activities": [
{
"name": "Get Pipeline Status",
"description": "Checks the status of a given processing pipeline and provides the value for the downstream framework activities to act upon.",
"type": "AzureFunctionActivity",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "CheckPipelineStatus",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',pipeline().parameters.TenantId,'\",\n \"applicationId\": \"',pipeline().parameters.applicationId,'\",\n \"authenticationKey\": \"',pipeline().parameters.authenticationKey,'\",\n \"subscriptionId\": \"',pipeline().parameters.subscriptionId,'\",\n \"resourceGroup\": \"',pipeline().parameters.resourceGroup,'\",\n \"factoryName\": \"',pipeline().parameters.factoryName,'\",\n \"pipelineName\": \"',pipeline().parameters.pipelineName,'\",\n \"runId\": \"',pipeline().parameters.runId,'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Wait If Running",
"description": "True = Do nothing.\nFalse = Wait.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@equals('Done',activity('Get Pipeline Status').output.SimpleStatus)",
"type": "Expression"
},
"ifFalseActivities": [
{
"name": "Wait for Pipeline",
"description": "The processing pipeline is still running so Wait before checking its status again.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@activity('Get Wait Duration').output.firstRow.PropertyValue",
"type": "Expression"
}
}
}
]
}
},
{
"name": "Set Last Check DateTime",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineLastStatusCheck]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Activity Failure",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"CallingActivity": {
"value": "GetPipelineStatus",
"type": "String"
},
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
],
"timeout": "7.00:00:00"
}
},
{
"name": "Set Pipeline Result",
"description": "Receives the outcome from the function execution for a given processing pipeline and updates the current execution table with different pipelines status values depending on the result (case).",
"type": "Switch",
"dependsOn": [
{
"activity": "Wait Until Pipeline Completes",
"dependencyConditions": [
"Completed"
]
}
],
"userProperties": [],
"typeProperties": {
"on": {
"value": "@activity('Get Pipeline Status').output.Status",
"type": "Expression"
},
"cases": [
{
"value": "Succeeded",
"activities": [
{
"name": "Pipeline Status Succeeded",
"description": "Updates the current execution table with a pipeline status of success if the function outcome is succeeded.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineSuccess]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Failed",
"activities": [
{
"name": "Pipeline Status Failed",
"description": "Updates the current execution table with a pipeline status of failed if the function outcome is failed. Also blocks pipelines in the downstream execution stage.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@activity('Get Pipeline Status').output.RunId",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Error Details",
"description": "Get the activity error details for the run ID of the worker pipeline called. Returns an array of all errors.",
"type": "AzureFunctionActivity",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "GetActivityErrors",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',pipeline().parameters.TenantId,'\",\n \"applicationId\": \"',pipeline().parameters.applicationId,'\",\n \"authenticationKey\": \"',pipeline().parameters.authenticationKey,'\",\n \"subscriptionId\": \"',pipeline().parameters.subscriptionId,'\",\n \"resourceGroup\": \"',pipeline().parameters.resourceGroup,'\",\n \"factoryName\": \"',pipeline().parameters.factoryName,'\",\n \"pipelineName\": \"',pipeline().parameters.pipelineName,'\",\n \"runId\": \"',pipeline().parameters.runId,'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Error Details",
"description": "Parses pipeline error details and persists them to the metadata database error log table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Error Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetErrorLogDetails]",
"storedProcedureParameters": {
"JsonErrorDetails": {
"value": {
"value": "@string(activity('Get Error Details').output)",
"type": "Expression"
},
"type": "String"
},
"LocalExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Cancelled",
"activities": [
{
"name": "Pipeline Status Cancelled",
"description": "Updates the current execution table with a pipeline status of unknown if the function returns an unexpected outcome.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineCancelled]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
],
"defaultActivities": [
{
"name": "Pipeline Status Unknown",
"description": "Updates the current execution table with a pipeline status of unknown if the function returns an unexpected outcome.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineUnknown]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Get Wait Duration",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "PipelineStatusCheckDuration"
}
},
"queryTimeout": "02:00:00"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
}
],
"parameters": {
"tenantId": {
"type": "string"
},
"applicationId": {
"type": "string"
},
"authenticationKey": {
"type": "string"
},
"subscriptionId": {
"type": "string"
},
"resourceGroup": {
"type": "string"
},
"factoryName": {
"type": "string"
},
"pipelineName": {
"type": "string"
},
"runId": {
"type": "string"
},
"executionId": {
"type": "string"
},
"stageId": {
"type": "int"
},
"pipelineId": {
"type": "int"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/FrameworkFunctions')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Intentional Error')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait1",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
},
{
"name": "Raise Errors or Not",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Wait1",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@equals(pipeline().parameters.RaiseErrors,'true')",
"type": "Expression"
},
"ifTrueActivities": [
{
"name": "Call Fail Procedure",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[dbo].[FailProcedure]",
"storedProcedureParameters": {
"RaiseError": {
"value": {
"value": "@pipeline().parameters.RaiseErrors",
"type": "Expression"
},
"type": "String"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
}
],
"parameters": {
"RaiseErrors": {
"type": "string",
"defaultValue": "false"
},
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Wait 1')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait1",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 10')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait10",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 2')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait2",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 3')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait3",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 4')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait4",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 5')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait5",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 6')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait6",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 7')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait7",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 8')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait8",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 9')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait9",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 15
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/GetSetMetadata')]",
"type": "Microsoft.DataFactory/factories/datasets",
"apiVersion": "2018-06-01",
"properties": {
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
},
"annotations": [
"ADF.procfwk"
],
"type": "AzureSqlTable",
"schema": [],
"typeProperties": {}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/FrameworkFunctions')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"annotations": [
"ADF.procfwk"
],
"type": "AzureFunction",
"typeProperties": {
"functionAppUrl": "[parameters('FrameworkFunctions_properties_typeProperties_functionAppUrl')]",
"functionKey": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "FrameworkFunctionsKey"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Keys')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Connection to Key Vault for all other ADF linked service credentials required to run the processing framework.",
"annotations": [
"ADF.procfwk"
],
"type": "AzureKeyVault",
"typeProperties": {
"baseUrl": "[parameters('Keys_properties_typeProperties_baseUrl')]"
}
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/SupportDatabase')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Connection between ADF and processing framework metadata SQLDB.",
"annotations": [
"ADF.procfwk"
],
"type": "AzureSqlDatabase",
"typeProperties": {
"connectionString": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "[parameters('SupportDatabase_properties_typeProperties_connectionString_secretName')]"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/FunctionalTestingTrigger')]",
"type": "Microsoft.DataFactory/factories/triggers",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used for functional testing of the framework in a dedicated environment.",
"annotations": [
"ADF.procfwk"
],
"runtimeState": "Stopped",
"pipelines": [
{
"pipelineReference": {
"referenceName": "01-Grandparent",
"type": "PipelineReference"
},
"parameters": {}
}
],
"type": "ScheduleTrigger",
"typeProperties": {
"recurrence": {
"frequency": "Hour",
"interval": 2,
"startTime": "2020-04-06T15:00:00.000Z",
"timeZone": "UTC"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/pipelines/01-Grandparent')]"
]
}
]
}
================================================
FILE: ARM Templates/Data Factory/v1.8.5 Export.json
================================================
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"factoryName": {
"type": "string",
"metadata": "Data Factory name",
"defaultValue": ""
},
"Keys_properties_typeProperties_baseUrl": {
"type": "string",
"defaultValue": ""
},
"FrameworkFunctions_properties_typeProperties_functionAppUrl": {
"type": "string",
"defaultValue": ""
},
"SupportDatabase_properties_typeProperties_connectionString_secretName": {
"type": "string",
"defaultValue": ""
}
},
"variables": {
"factoryId": "[concat('Microsoft.DataFactory/factories/', parameters('factoryName'))]"
},
"resources": [
{
"name": "[concat(parameters('factoryName'), '/GetSetMetadata')]",
"type": "Microsoft.DataFactory/factories/datasets",
"apiVersion": "2018-06-01",
"properties": {
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
},
"annotations": [
"ADF.procfwk"
],
"type": "AzureSqlTable",
"schema": [],
"typeProperties": {}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/FunctionalTestingTrigger')]",
"type": "Microsoft.DataFactory/factories/triggers",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used for functional testing of the framework in a dedicated environment.",
"annotations": [
"ADF.procfwk"
],
"runtimeState": "Stopped",
"pipelines": [
{
"pipelineReference": {
"referenceName": "01-Grandparent",
"type": "PipelineReference"
},
"parameters": {}
}
],
"type": "ScheduleTrigger",
"typeProperties": {
"recurrence": {
"frequency": "Hour",
"interval": 2,
"startTime": "2020-04-06T15:00:00Z",
"timeZone": "UTC"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/pipelines/01-Grandparent')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Keys')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Connection to Key Vault for all other ADF linked service credentials required to run the processing framework.",
"annotations": [
"ADF.procfwk"
],
"type": "AzureKeyVault",
"typeProperties": {
"baseUrl": "[parameters('Keys_properties_typeProperties_baseUrl')]"
}
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/FrameworkFunctions')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"annotations": [
"ADF.procfwk"
],
"type": "AzureFunction",
"typeProperties": {
"functionAppUrl": "[parameters('FrameworkFunctions_properties_typeProperties_functionAppUrl')]",
"functionKey": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "FrameworkFunctionsKey"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/SupportDatabase')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Connection between ADF and processing framework metadata SQLDB.",
"annotations": [
"ADF.procfwk"
],
"type": "AzureSqlDatabase",
"typeProperties": {
"connectionString": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "[parameters('SupportDatabase_properties_typeProperties_connectionString_secretName')]"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/04-Infant')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk infant pipeline used to check when the processing pipeline called by the Child completes and passes the resulting status back to the metadata database.",
"activities": [
{
"name": "Wait Until Pipeline Completes",
"description": "Loops until the pipeline called completes.\n\nSimple status:\n- Running = new iteration.\n- Done = break.",
"type": "Until",
"dependsOn": [
{
"activity": "Get Wait Duration",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@equals('Done',activity('Get Pipeline Status').output.SimpleStatus)",
"type": "Expression"
},
"activities": [
{
"name": "Get Pipeline Status",
"description": "Checks the status of a given processing pipeline and provides the value for the downstream framework activities to act upon.",
"type": "AzureFunctionActivity",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "CheckPipelineStatus",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',pipeline().parameters.TenantId,'\",\n \"applicationId\": \"',pipeline().parameters.applicationId,'\",\n \"authenticationKey\": \"',pipeline().parameters.authenticationKey,'\",\n \"subscriptionId\": \"',pipeline().parameters.subscriptionId,'\",\n \"resourceGroup\": \"',pipeline().parameters.resourceGroup,'\",\n \"factoryName\": \"',pipeline().parameters.factoryName,'\",\n \"pipelineName\": \"',pipeline().parameters.pipelineName,'\",\n \"runId\": \"',pipeline().parameters.runId,'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Wait If Running",
"description": "True = Do nothing.\nFalse = Wait.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@equals('Done',activity('Get Pipeline Status').output.SimpleStatus)",
"type": "Expression"
},
"ifFalseActivities": [
{
"name": "Wait for Pipeline",
"description": "The processing pipeline is still running so Wait before checking its status again.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@activity('Get Wait Duration').output.firstRow.PropertyValue",
"type": "Expression"
}
}
}
]
}
},
{
"name": "Set Last Check DateTime",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineLastStatusCheck]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Activity Failure",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"CallingActivity": {
"value": "GetPipelineStatus",
"type": "String"
},
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
],
"timeout": "7.00:00:00"
}
},
{
"name": "Set Pipeline Result",
"description": "Receives the outcome from the function execution for a given processing pipeline and updates the current execution table with different pipelines status values depending on the result (case).",
"type": "Switch",
"dependsOn": [
{
"activity": "Wait Until Pipeline Completes",
"dependencyConditions": [
"Completed"
]
}
],
"userProperties": [],
"typeProperties": {
"on": {
"value": "@activity('Get Pipeline Status').output.Status",
"type": "Expression"
},
"cases": [
{
"value": "Succeeded",
"activities": [
{
"name": "Pipeline Status Succeeded",
"description": "Updates the current execution table with a pipeline status of success if the function outcome is succeeded.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineSuccess]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Failed",
"activities": [
{
"name": "Pipeline Status Failed",
"description": "Updates the current execution table with a pipeline status of failed if the function outcome is failed. Also blocks pipelines in the downstream execution stage.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@activity('Get Pipeline Status').output.RunId",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Error Details",
"description": "Get the activity error details for the run ID of the worker pipeline called. Returns an array of all errors.",
"type": "AzureFunctionActivity",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "GetActivityErrors",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',pipeline().parameters.TenantId,'\",\n \"applicationId\": \"',pipeline().parameters.applicationId,'\",\n \"authenticationKey\": \"',pipeline().parameters.authenticationKey,'\",\n \"subscriptionId\": \"',pipeline().parameters.subscriptionId,'\",\n \"resourceGroup\": \"',pipeline().parameters.resourceGroup,'\",\n \"factoryName\": \"',pipeline().parameters.factoryName,'\",\n \"pipelineName\": \"',pipeline().parameters.pipelineName,'\",\n \"runId\": \"',pipeline().parameters.runId,'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Error Details",
"description": "Parses pipeline error details and persists them to the metadata database error log table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Error Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetErrorLogDetails]",
"storedProcedureParameters": {
"JsonErrorDetails": {
"value": {
"value": "@string(activity('Get Error Details').output)",
"type": "Expression"
},
"type": "String"
},
"LocalExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Cancelled",
"activities": [
{
"name": "Pipeline Status Cancelled",
"description": "Updates the current execution table with a pipeline status of unknown if the function returns an unexpected outcome.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineCancelled]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
],
"defaultActivities": [
{
"name": "Pipeline Status Unknown",
"description": "Updates the current execution table with a pipeline status of unknown if the function returns an unexpected outcome.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineUnknown]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Get Wait Duration",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "PipelineStatusCheckDuration"
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
}
],
"parameters": {
"tenantId": {
"type": "string"
},
"applicationId": {
"type": "string"
},
"authenticationKey": {
"type": "string"
},
"subscriptionId": {
"type": "string"
},
"resourceGroup": {
"type": "string"
},
"factoryName": {
"type": "string"
},
"pipelineName": {
"type": "string"
},
"runId": {
"type": "string"
},
"executionId": {
"type": "string"
},
"stageId": {
"type": "int"
},
"pipelineId": {
"type": "int"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
],
"lastPublishTime": "2020-08-17T11:35:19Z"
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/FrameworkFunctions')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/03-Child')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk child pipeline used to execute Worker pipelines within a given execution stage. This pipeline will be called once for each stage, then execute all Workers in parallel.",
"activities": [
{
"name": "Get Pipelines",
"description": "Returns all pipelines from the metadata to be executed within a given processing stage.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelinesInStage]",
"storedProcedureParameters": {
"StageId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Pipelines",
"description": "Second level ForEach to run in parallel all pipelines within the stage. Items for iteration passed from the Get Pipelines lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Pipelines",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Pipelines').output.value",
"type": "Expression"
},
"isSequential": false,
"batchCount": 40,
"activities": [
{
"name": "Execute Pipeline",
"description": "The lowest level executor with the metadata framework to call existing processing pipelines within Data Factory. The function called will block processing and wait for an outcome.",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Log Pipeline Running",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Pipeline Params",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get SPN Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "ExecutePipeline",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n\t\"tenantId\": \"',pipeline().parameters.TenantId,'\",\n\t\"applicationId\": \"',activity('Get SPN Details').output.firstRow.Id,'\",\n\t\"authenticationKey\": \"',activity('Get SPN Details').output.firstRow.Secret,'\",\n\t\"subscriptionId\": \"',pipeline().parameters.SubscriptionId,'\",\n\t\"resourceGroup\": \"',item().ResourceGroupName,'\",\n\t\"factoryName\": \"',item().DataFactoryName,'\",\n\t\"pipelineName\": \"',item().PipelineName,'\"',activity('Get Pipeline Params').output.firstRow.Params,'\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Pipeline Params",
"description": "Returns any parameters from metadata required for the processing pipeline being called. The output can be an empty string if no parameters are required.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelineParameters]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Pipeline Running",
"description": "Sets the current pipeline with a status of running within the current execution database table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get SPN Details",
"description": "Return the SPN ID and Secret for the processing pipeline being executed. Called at this level as each pipeline can have a different SPN.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetServicePrincipal]",
"storedProcedureParameters": {
"DataFactory": {
"type": "String",
"value": {
"value": "@item().DataFactoryName",
"type": "Expression"
}
},
"PipelineName": {
"type": "String",
"value": {
"value": "@item().PipelineName",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Activity Failure",
"description": "Handle true failures from calling out to the Azure Function and update the current execution table accordingly so a restart can occur.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Pipeline",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
},
"CallingActivity": {
"value": "ExecutePipeline",
"type": "String"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Running Pipeline Handler",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Execute Pipeline",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "04-Infant",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"tenantId": {
"value": "@pipeline().parameters.TenantId",
"type": "Expression"
},
"applicationId": {
"value": "@activity('Get SPN Details').output.firstRow.Id",
"type": "Expression"
},
"authenticationKey": {
"value": "@activity('Get SPN Details').output.firstRow.Secret",
"type": "Expression"
},
"subscriptionId": {
"value": "@pipeline().parameters.SubscriptionId",
"type": "Expression"
},
"resourceGroup": {
"value": "@item().ResourceGroupName",
"type": "Expression"
},
"factoryName": {
"value": "@item().DataFactoryName",
"type": "Expression"
},
"pipelineName": {
"value": "@item().PipelineName",
"type": "Expression"
},
"runId": {
"value": "@activity('Execute Pipeline').output.RunId",
"type": "Expression"
},
"executionId": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"stageId": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"pipelineId": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
}
},
{
"name": "Set Run Id",
"description": "Provide the actual ADF run ID back to the current execution table for long term logging and alignment between the metadata other Azure monitoring tools.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Pipeline",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunId]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@activity('Execute Pipeline').output.RunId",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check For Alerts",
"description": "Checks the properties tables and if any recipients in the database require alerts sending for the current pipeline ID.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Set Run Id",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Running Pipeline Handler",
"dependencyConditions": [
"Completed"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[CheckForEmailAlerts]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": true
}
},
{
"name": "Send Alerts",
"description": "True = alerts need sending.\nFalse = do nothing.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Check For Alerts",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@activity('Check For Alerts').output.firstRow.SendAlerts",
"type": "Expression"
},
"ifTrueActivities": [
{
"name": "Get Email Parts",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetEmailAlertParts]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": true
}
},
{
"name": "Send Email",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Get Email Parts",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "SendEmail",
"method": "POST",
"headers": {},
"body": {
"value": "@activity('Get Email Parts').output.firstRow",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
}
]
}
}
]
}
}
],
"parameters": {
"StageId": {
"type": "int"
},
"ExecutionId": {
"type": "string"
},
"TenantId": {
"type": "string"
},
"SubscriptionId": {
"type": "string"
}
},
"variables": {
"FunctionBody": {
"type": "String"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
],
"lastPublishTime": "2020-08-17T11:35:20Z"
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/FrameworkFunctions')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]",
"[concat(variables('factoryId'), '/pipelines/04-Infant')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/02-Parent')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk parent pipeline used to bootstrap the orchestration framework in perform the first level ForEach calls in sequence for the metadata stages.",
"activities": [
{
"name": "Get Stages",
"description": "Returns a distinct list of execution stages within the framework metadata.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Execution Wrapper",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetStages]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Stages",
"description": "Top level ForEach to sequentially call all processing stages within the framework metadata. Items for iteration passed from the Get Stages lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Stages",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Tenant Id",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Subscription Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Stages').output.value",
"type": "Expression"
},
"isSequential": true,
"activities": [
{
"name": "Stage Executor",
"description": "Call to the framework generic child pipeline for a given execution stage.",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Log Stage Preparing",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "03-Child",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"StageId": {
"value": "@item().StageId",
"type": "Expression"
},
"ExecutionId": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
},
"TenantId": {
"value": "@activity('Get Tenant Id').output.firstRow.PropertyValue",
"type": "Expression"
},
"SubscriptionId": {
"value": "@activity('Get Subscription Id').output.firstRow.PropertyValue",
"type": "Expression"
}
}
}
},
{
"name": "Log Stage Preparing",
"description": "Update the current execution table flagging all pipelines within the stage as preparing.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Check and Update Blockers",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogStagePreparing]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check and Update Blockers",
"description": "Used to double check and stop the next execution stage if failures and blockers have be incurred. This also depends on the failure handling property value which defines the stored procedure behaviour.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[CheckForBlockedPipelines]",
"storedProcedureParameters": {
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Execution Wrapper",
"description": "Wrapper to reset and restart processing or create a completely new execution instance of the framework metadata.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Clean Up Previous Run",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[ExecutionWrapper]",
"storedProcedureParameters": {
"CallingDataFactory": {
"type": "String",
"value": {
"value": "@pipeline().DataFactory",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Check Outcome and Update Logs",
"description": "After a successful execution run the current execution metadata is moved to the long term logging table by this stored procedure call. Otherwise an error will be raised.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Stages",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[UpdateExecutionLog]",
"storedProcedureParameters": {
"PerformErrorCheck": {
"value": {
"value": "@bool(1)",
"type": "Expression"
},
"type": "Boolean"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Tenant Id",
"description": "Returning the Azure Tenant Id from the metadata properties table.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Metadata Integrity Checks",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "TenantId"
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": true
}
},
{
"name": "Get Subscription Id",
"description": "Returning the Azure Subscription Id from the metadata properties table.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Metadata Integrity Checks",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "SubscriptionId"
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Metadata Integrity Checks",
"description": "Performs a series of checks on all metadata held in the framework SQLDB. This is intended to raise errors before an execution run even starts.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Execute Precursor",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[CheckMetadataIntegrity]",
"storedProcedureParameters": {
"DebugMode": {
"type": "Boolean",
"value": "false"
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Clean Up Previous Run",
"description": "Handle Worker pipelines that are reported as Running when the parent pipeline is called again. Get what the actual status of those pipelines is.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Metadata Integrity Checks",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Metadata Integrity Checks').output.value",
"type": "Expression"
},
"isSequential": false,
"activities": [
{
"name": "Get SPN Details",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetServicePrincipal]",
"storedProcedureParameters": {
"DataFactory": {
"type": "String",
"value": {
"value": "@item().DataFactoryName",
"type": "Expression"
}
},
"PipelineName": {
"type": "String",
"value": {
"value": "@item().PipelineName",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Pipeline Checking",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineChecking]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Pipeline Status",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Get SPN Details",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Log Pipeline Checking",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "CheckPipelineStatus",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',item().TenantId,'\",\n \"applicationId\": \"',activity('Get SPN Details').output.firstRow.Id,'\",\n \"authenticationKey\": \"',activity('Get SPN Details').output.firstRow.Secret,'\",\n \"subscriptionId\": \"',item().SubscriptionId,'\",\n \"resourceGroup\": \"',item().ResourceGroupName,'\",\n \"factoryName\": \"',item().DataFactoryName,'\",\n \"pipelineName\": \"',item().PipelineName,'\",\n \"runId\": \"',item().AdfPipelineRunId,'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Set Pipeline Status",
"type": "Switch",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"on": {
"value": "@activity('Get Pipeline Status').output.Status",
"type": "Expression"
},
"cases": [
{
"value": "Failed",
"activities": [
{
"name": "Pipeline Status Failed",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": null,
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Succeeded",
"activities": [
{
"name": "Pipeline Status Succeeded",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineSuccess]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Queued",
"activities": [
{
"name": "Pipeline Status Queued - Running",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "InProgress",
"activities": [
{
"name": "Pipeline Status InProgress - Running",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Cancelled",
"activities": [
{
"name": "Pipeline Status Cancelled",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineCancelled]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
],
"defaultActivities": [
{
"name": "Pipeline Status Unknown",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineUnknown]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Set Last Check DateTime",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineLastStatusCheck]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Execute Precursor",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[ExecutePrecursorProcedure]"
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
],
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
],
"lastPublishTime": "2020-08-17T11:35:21Z"
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]",
"[concat(variables('factoryId'), '/pipelines/03-Child')]",
"[concat(variables('factoryId'), '/linkedServices/FrameworkFunctions')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/01-Grandparent')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk grandparent pipeline used optionally to bootstrap any wider processes in your Data Factory that then calls the processing framework.",
"activities": [
{
"name": "Framework Processing",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "02-Parent",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {}
}
}
],
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
],
"lastPublishTime": "2020-08-17T11:35:22Z"
},
"dependsOn": [
"[concat(variables('factoryId'), '/pipelines/02-Parent')]"
]
}
]
}
================================================
FILE: ARM Templates/Data Factory/v1.8.6 Export.json
================================================
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"factoryName": {
"type": "string",
"metadata": "Data Factory name",
"defaultValue": ""
},
"FrameworkFunctions_properties_typeProperties_functionAppUrl": {
"type": "string",
"defaultValue": ""
},
"Keys_properties_typeProperties_baseUrl": {
"type": "string",
"defaultValue": ""
},
"SupportDatabase_properties_typeProperties_connectionString_secretName": {
"type": "string",
"defaultValue": ""
}
},
"variables": {
"factoryId": "[concat('Microsoft.DataFactory/factories/', parameters('factoryName'))]"
},
"resources": [
{
"name": "[concat(parameters('factoryName'), '/01-Grandparent')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk grandparent pipeline used optionally to bootstrap any wider processes in your Data Factory that then calls the processing framework.",
"activities": [
{
"name": "Framework Processing",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "02-Parent",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {}
}
}
],
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk",
"Grandparent"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/pipelines/02-Parent')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/02-Parent')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk parent pipeline used to bootstrap the orchestration framework in perform the first level ForEach calls in sequence for the metadata stages.",
"activities": [
{
"name": "Get Stages",
"description": "Returns a distinct list of execution stages within the framework metadata.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Set Execution Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetStages]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@variables('ExecutionId')",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Stages",
"description": "Top level ForEach to sequentially call all processing stages within the framework metadata. Items for iteration passed from the Get Stages lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Stages",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Tenant Id",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Subscription Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Stages').output.value",
"type": "Expression"
},
"isSequential": true,
"activities": [
{
"name": "Stage Executor",
"description": "Call to the framework generic child pipeline for a given execution stage.",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Log Stage Preparing",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "03-Child",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"StageId": {
"value": "@item().StageId",
"type": "Expression"
},
"ExecutionId": {
"value": "@variables('ExecutionId')",
"type": "Expression"
},
"TenantId": {
"value": "@activity('Get Tenant Id').output.firstRow.PropertyValue",
"type": "Expression"
},
"SubscriptionId": {
"value": "@activity('Get Subscription Id').output.firstRow.PropertyValue",
"type": "Expression"
}
}
}
},
{
"name": "Log Stage Preparing",
"description": "Update the current execution table flagging all pipelines within the stage as preparing.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Check and Update Blockers",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogStagePreparing]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@variables('ExecutionId')",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check and Update Blockers",
"description": "Used to double check and stop the next execution stage if failures and blockers have be incurred. This also depends on the failure handling property value which defines the stored procedure behaviour.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[CheckForBlockedPipelines]",
"storedProcedureParameters": {
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Execution Wrapper",
"description": "Wrapper to reset and restart processing or create a completely new execution instance of the framework metadata.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Clean Up Previous Run",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[ExecutionWrapper]",
"storedProcedureParameters": {
"CallingDataFactory": {
"type": "String",
"value": {
"value": "@pipeline().DataFactory",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Check Outcome and Update Logs",
"description": "After a successful execution run the current execution metadata is moved to the long term logging table by this stored procedure call. Otherwise an error will be raised.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Stages",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[UpdateExecutionLog]",
"storedProcedureParameters": {
"PerformErrorCheck": {
"value": {
"value": "@bool(1)",
"type": "Expression"
},
"type": "Boolean"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Tenant Id",
"description": "Returning the Azure Tenant Id from the metadata properties table.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Metadata Integrity Checks",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "TenantId"
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": true
}
},
{
"name": "Get Subscription Id",
"description": "Returning the Azure Subscription Id from the metadata properties table.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Metadata Integrity Checks",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "SubscriptionId"
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Metadata Integrity Checks",
"description": "Performs a series of checks on all metadata held in the framework SQLDB. This is intended to raise errors before an execution run even starts.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Execute Precursor",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[CheckMetadataIntegrity]",
"storedProcedureParameters": {
"DebugMode": {
"type": "Boolean",
"value": "false"
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Clean Up Previous Run",
"description": "Handle Worker pipelines that are reported as Running when the parent pipeline is called again. Get what the actual status of those pipelines is.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Metadata Integrity Checks",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Metadata Integrity Checks').output.value",
"type": "Expression"
},
"isSequential": false,
"batchCount": 20,
"activities": [
{
"name": "Get SPN Details",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetServicePrincipal]",
"storedProcedureParameters": {
"DataFactory": {
"type": "String",
"value": {
"value": "@item().DataFactoryName",
"type": "Expression"
}
},
"PipelineName": {
"type": "String",
"value": {
"value": "@item().PipelineName",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Pipeline Checking",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineChecking]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Pipeline Status",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Get SPN Details",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Log Pipeline Checking",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "CheckPipelineStatus",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',item().TenantId,'\",\n \"applicationId\": \"',activity('Get SPN Details').output.firstRow.Id,'\",\n \"authenticationKey\": \"',activity('Get SPN Details').output.firstRow.Secret,'\",\n \"subscriptionId\": \"',item().SubscriptionId,'\",\n \"resourceGroup\": \"',item().ResourceGroupName,'\",\n \"factoryName\": \"',item().DataFactoryName,'\",\n \"pipelineName\": \"',item().PipelineName,'\",\n \"runId\": \"',item().AdfPipelineRunId,'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Set Pipeline Status",
"description": "Update the metadata depending on the actual pipeline outcome. Using the status as the case.",
"type": "Switch",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"on": {
"value": "@activity('Get Pipeline Status').output.Status",
"type": "Expression"
},
"cases": [
{
"value": "Failed",
"activities": [
{
"name": "Pipeline Status Failed",
"description": "Updates the current execution table with a pipeline status of failed if the function outcome is failed. Also blocks pipelines in the downstream execution stage.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": null,
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Succeeded",
"activities": [
{
"name": "Pipeline Status Succeeded",
"description": "Updates the current execution table with a pipeline status of success if the function outcome is succeeded.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineSuccess]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Queued",
"activities": [
{
"name": "Pipeline Status Queued - Running",
"description": "Updates the current execution table with a pipeline status of running if the function outcome is queued.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "InProgress",
"activities": [
{
"name": "Pipeline Status InProgress - Running",
"description": "Updates the current execution table with a pipeline status of running if the function outcome is in progress.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Cancelled",
"activities": [
{
"name": "Pipeline Status Cancelled",
"description": "Updates the current execution table with a pipeline status of cancelled if the function outcome is cancelled.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineCancelled]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
],
"defaultActivities": [
{
"name": "Pipeline Status Unknown",
"description": "Updates the current execution table with a pipeline status of unknown if the function returns an unexpected outcome.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineUnknown]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Set Last Check DateTime",
"description": "Update the current execution table with a date time from when the function last checked the pipeline status.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineLastStatusCheck]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Execute Precursor",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[ExecutePrecursorProcedure]"
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Set Execution Id",
"description": "Set the local execution Id to a pipeline variable for each in several downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Execution Wrapper",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "ExecutionId",
"value": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
}
}
}
],
"variables": {
"ExecutionId": {
"type": "String"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk",
"Parent"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]",
"[concat(variables('factoryId'), '/pipelines/03-Child')]",
"[concat(variables('factoryId'), '/linkedServices/FrameworkFunctions')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/03-Child')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk child pipeline used to execute Worker pipelines within a given execution stage. This pipeline will be called once for each stage, then execute all Workers in parallel.",
"activities": [
{
"name": "Get Pipelines",
"description": "Returns all pipelines from the metadata to be executed within a given processing stage.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelinesInStage]",
"storedProcedureParameters": {
"StageId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Pipelines",
"description": "Second level ForEach to run in parallel all pipelines within the stage. Items for iteration passed from the Get Pipelines lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Pipelines",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Pipelines').output.value",
"type": "Expression"
},
"isSequential": false,
"batchCount": 50,
"activities": [
{
"name": "Execute Pipeline",
"description": "The lowest level executor with the metadata framework to call existing processing pipelines within Data Factory. The function called will block processing and wait for an outcome.",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Log Pipeline Running",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Pipeline Params",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get SPN Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "ExecutePipeline",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n\t\"tenantId\": \"',pipeline().parameters.TenantId,'\",\n\t\"applicationId\": \"',activity('Get SPN Details').output.firstRow.Id,'\",\n\t\"authenticationKey\": \"',activity('Get SPN Details').output.firstRow.Secret,'\",\n\t\"subscriptionId\": \"',pipeline().parameters.SubscriptionId,'\",\n\t\"resourceGroup\": \"',item().ResourceGroupName,'\",\n\t\"factoryName\": \"',item().DataFactoryName,'\",\n\t\"pipelineName\": \"',item().PipelineName,'\"',activity('Get Pipeline Params').output.firstRow.Params,'\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Pipeline Params",
"description": "Returns any parameters from metadata required for the processing pipeline being called. The output can be an empty string if no parameters are required.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelineParameters]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Pipeline Running",
"description": "Sets the current pipeline with a status of running within the current execution database table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get SPN Details",
"description": "Return the SPN ID and Secret for the processing pipeline being executed. Called at this level as each pipeline can have a different SPN.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetServicePrincipal]",
"storedProcedureParameters": {
"DataFactory": {
"type": "String",
"value": {
"value": "@item().DataFactoryName",
"type": "Expression"
}
},
"PipelineName": {
"type": "String",
"value": {
"value": "@item().PipelineName",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Activity Failure",
"description": "Handle true failures from calling out to the Azure Function and update the current execution table accordingly so a restart can occur.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Pipeline",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
},
"CallingActivity": {
"value": "ExecutePipeline",
"type": "String"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Running Pipeline Handler",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Execute Pipeline",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "04-Infant",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"tenantId": {
"value": "@pipeline().parameters.TenantId",
"type": "Expression"
},
"applicationId": {
"value": "@activity('Get SPN Details').output.firstRow.Id",
"type": "Expression"
},
"authenticationKey": {
"value": "@activity('Get SPN Details').output.firstRow.Secret",
"type": "Expression"
},
"subscriptionId": {
"value": "@pipeline().parameters.SubscriptionId",
"type": "Expression"
},
"resourceGroup": {
"value": "@item().ResourceGroupName",
"type": "Expression"
},
"factoryName": {
"value": "@item().DataFactoryName",
"type": "Expression"
},
"pipelineName": {
"value": "@item().PipelineName",
"type": "Expression"
},
"runId": {
"value": "@activity('Execute Pipeline').output.RunId",
"type": "Expression"
},
"executionId": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"stageId": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"pipelineId": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
}
},
{
"name": "Set Run Id",
"description": "Provide the actual ADF run ID back to the current execution table for long term logging and alignment between the metadata other Azure monitoring tools.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Pipeline",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunId]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@activity('Execute Pipeline').output.RunId",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check For Alerts",
"description": "Checks the properties tables and if any recipients in the database require alerts sending for the current pipeline ID.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Set Run Id",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Running Pipeline Handler",
"dependencyConditions": [
"Completed"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[CheckForEmailAlerts]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": true
}
},
{
"name": "Send Alerts",
"description": "True = alerts need sending.\nFalse = do nothing.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Check For Alerts",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@activity('Check For Alerts').output.firstRow.SendAlerts",
"type": "Expression"
},
"ifTrueActivities": [
{
"name": "Get Email Parts",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetEmailAlertParts]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": true
}
},
{
"name": "Send Email",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Get Email Parts",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "SendEmail",
"method": "POST",
"headers": {},
"body": {
"value": "@activity('Get Email Parts').output.firstRow",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
}
]
}
}
]
}
}
],
"parameters": {
"StageId": {
"type": "int"
},
"ExecutionId": {
"type": "string"
},
"TenantId": {
"type": "string"
},
"SubscriptionId": {
"type": "string"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk",
"Child"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/FrameworkFunctions')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]",
"[concat(variables('factoryId'), '/pipelines/04-Infant')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/04-Infant')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk infant pipeline used to check when the processing pipeline called by the Child completes and passes the resulting status back to the metadata database.",
"activities": [
{
"name": "Wait Until Pipeline Completes",
"description": "Loops until the Worker pipeline called completes.\n\nSimple status:\n- Running = new iteration.\n- Done = break.",
"type": "Until",
"dependsOn": [
{
"activity": "Get Wait Duration",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@variables('WorkerPipelineState')",
"type": "Expression"
},
"activities": [
{
"name": "Get Pipeline Status",
"description": "Checks the status of a given processing pipeline and provides the value for the downstream framework activities to act upon.",
"type": "AzureFunctionActivity",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "CheckPipelineStatus",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',pipeline().parameters.TenantId,'\",\n \"applicationId\": \"',pipeline().parameters.applicationId,'\",\n \"authenticationKey\": \"',pipeline().parameters.authenticationKey,'\",\n \"subscriptionId\": \"',pipeline().parameters.subscriptionId,'\",\n \"resourceGroup\": \"',pipeline().parameters.resourceGroup,'\",\n \"factoryName\": \"',pipeline().parameters.factoryName,'\",\n \"pipelineName\": \"',pipeline().parameters.pipelineName,'\",\n \"runId\": \"',pipeline().parameters.runId,'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Wait If Running",
"description": "True = Do nothing.\nFalse = Wait, before the next iteration.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Set Worker State",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@variables('WorkerPipelineState')",
"type": "Expression"
},
"ifFalseActivities": [
{
"name": "Wait for Pipeline",
"description": "The processing pipeline is still running so Wait before checking its status again.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@activity('Get Wait Duration').output.firstRow.PropertyValue",
"type": "Expression"
}
}
}
]
}
},
{
"name": "Set Last Check DateTime",
"description": "Update the current execution table with a date time from when the Worker pipeline status was last checked as part of the Until iterations.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineLastStatusCheck]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Activity Failure",
"description": "Report to the current execution table that the framework pipeline activity has failed. This failure is outside of the scope of the framework and is probably related to a wider platform problem.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"CallingActivity": {
"value": "GetPipelineStatus",
"type": "String"
},
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Set Worker State",
"description": "Set the bool state of the Worker pipeline to be used by the Until and If expressions. True = Complete, False = Running.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerPipelineState",
"value": {
"value": "@equals('Done',activity('Get Pipeline Status').output.SimpleStatus)",
"type": "Expression"
}
}
}
],
"timeout": "7.00:00:00"
}
},
{
"name": "Set Pipeline Result",
"description": "Receives the outcome from the function execution for a given processing pipeline and updates the current execution table with different pipelines status values depending on the result (case).",
"type": "Switch",
"dependsOn": [
{
"activity": "Wait Until Pipeline Completes",
"dependencyConditions": [
"Completed"
]
}
],
"userProperties": [],
"typeProperties": {
"on": {
"value": "@activity('Get Pipeline Status').output.Status",
"type": "Expression"
},
"cases": [
{
"value": "Succeeded",
"activities": [
{
"name": "Pipeline Status Succeeded",
"description": "Updates the current execution table with a pipeline status of success if the function outcome is succeeded.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineSuccess]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Failed",
"activities": [
{
"name": "Pipeline Status Failed",
"description": "Updates the current execution table with a pipeline status of failed if the function outcome is failed. Also blocks pipelines in the downstream execution stage.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@activity('Get Pipeline Status').output.RunId",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Error Details",
"description": "Get the activity error details for the run ID of the worker pipeline called. Returns an array of all errors.",
"type": "AzureFunctionActivity",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "GetActivityErrors",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',pipeline().parameters.TenantId,'\",\n \"applicationId\": \"',pipeline().parameters.applicationId,'\",\n \"authenticationKey\": \"',pipeline().parameters.authenticationKey,'\",\n \"subscriptionId\": \"',pipeline().parameters.subscriptionId,'\",\n \"resourceGroup\": \"',pipeline().parameters.resourceGroup,'\",\n \"factoryName\": \"',pipeline().parameters.factoryName,'\",\n \"pipelineName\": \"',pipeline().parameters.pipelineName,'\",\n \"runId\": \"',pipeline().parameters.runId,'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Error Details",
"description": "Parses pipeline error details and persists them to the metadata database error log table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Error Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetErrorLogDetails]",
"storedProcedureParameters": {
"JsonErrorDetails": {
"value": {
"value": "@string(activity('Get Error Details').output)",
"type": "Expression"
},
"type": "String"
},
"LocalExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Cancelled",
"activities": [
{
"name": "Pipeline Status Cancelled",
"description": "Updates the current execution table with a pipeline status of cancelled if the function outcome is cancelled.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineCancelled]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
],
"defaultActivities": [
{
"name": "Pipeline Status Unknown",
"description": "Updates the current execution table with a pipeline status of unknown if the function returns an unexpected outcome.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineUnknown]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Get Wait Duration",
"description": "Return wait duration in seconds from database properties table to be used during each Until iteration when the Worker pipeline is still running.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "PipelineStatusCheckDuration"
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
}
],
"parameters": {
"tenantId": {
"type": "string"
},
"applicationId": {
"type": "string"
},
"authenticationKey": {
"type": "string"
},
"subscriptionId": {
"type": "string"
},
"resourceGroup": {
"type": "string"
},
"factoryName": {
"type": "string"
},
"pipelineName": {
"type": "string"
},
"runId": {
"type": "string"
},
"executionId": {
"type": "string"
},
"stageId": {
"type": "int"
},
"pipelineId": {
"type": "int"
}
},
"variables": {
"WorkerPipelineState": {
"type": "Boolean"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk",
"Infant"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/FrameworkFunctions')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Intentional Error')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait1",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
},
{
"name": "Raise Errors or Not",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Wait1",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@equals(pipeline().parameters.RaiseErrors,'true')",
"type": "Expression"
},
"ifTrueActivities": [
{
"name": "Call Fail Procedure",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[dbo].[FailProcedure]",
"storedProcedureParameters": {
"RaiseError": {
"value": {
"value": "@pipeline().parameters.RaiseErrors",
"type": "Expression"
},
"type": "String"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
}
],
"parameters": {
"RaiseErrors": {
"type": "string",
"defaultValue": "false"
},
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Wait 1')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait1",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 10')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait10",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 2')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait2",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 3')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait3",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 4')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait4",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 5')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait5",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 6')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait6",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 7')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait7",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 8')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait8",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 9')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait9",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 15
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/GetSetMetadata')]",
"type": "Microsoft.DataFactory/factories/datasets",
"apiVersion": "2018-06-01",
"properties": {
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
},
"annotations": [
"ADF.procfwk"
],
"type": "AzureSqlTable",
"schema": [],
"typeProperties": {}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/FrameworkFunctions')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"annotations": [
"ADF.procfwk"
],
"type": "AzureFunction",
"typeProperties": {
"functionAppUrl": "[parameters('FrameworkFunctions_properties_typeProperties_functionAppUrl')]",
"functionKey": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "FrameworkFunctionsKey"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Keys')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Connection to Key Vault for all other ADF linked service credentials required to run the processing framework.",
"annotations": [
"ADF.procfwk"
],
"type": "AzureKeyVault",
"typeProperties": {
"baseUrl": "[parameters('Keys_properties_typeProperties_baseUrl')]"
}
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/SupportDatabase')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Connection between ADF and processing framework metadata SQLDB.",
"annotations": [
"ADF.procfwk"
],
"type": "AzureSqlDatabase",
"typeProperties": {
"connectionString": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "[parameters('SupportDatabase_properties_typeProperties_connectionString_secretName')]"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/FunctionalTestingTrigger')]",
"type": "Microsoft.DataFactory/factories/triggers",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used for functional testing of the framework in a dedicated environment.",
"annotations": [
"ADF.procfwk"
],
"runtimeState": "Stopped",
"pipelines": [
{
"pipelineReference": {
"referenceName": "01-Grandparent",
"type": "PipelineReference"
},
"parameters": {}
}
],
"type": "ScheduleTrigger",
"typeProperties": {
"recurrence": {
"frequency": "Hour",
"interval": 2,
"startTime": "2020-04-06T15:00:00.000Z",
"timeZone": "UTC"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/pipelines/01-Grandparent')]"
]
}
]
}
================================================
FILE: ARM Templates/Data Factory/v1.9 Export.json
================================================
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"factoryName": {
"type": "string",
"metadata": "Data Factory name",
"defaultValue": ""
},
"FrameworkFunctions_properties_typeProperties_functionAppUrl": {
"type": "string",
"defaultValue": ""
},
"Keys_properties_typeProperties_baseUrl": {
"type": "string",
"defaultValue": ""
},
"SupportDatabase_properties_typeProperties_connectionString_secretName": {
"type": "string",
"defaultValue": ""
}
},
"variables": {
"factoryId": "[concat('Microsoft.DataFactory/factories/', parameters('factoryName'))]"
},
"resources": [
{
"name": "[concat(parameters('factoryName'), '/01-Grandparent')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk grandparent pipeline used optionally to bootstrap any wider processes in your Data Factory that then calls the processing framework.",
"activities": [
{
"name": "Framework Processing",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "02-Parent",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {}
}
}
],
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk",
"Grandparent"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/pipelines/02-Parent')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/02-Parent')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk parent pipeline used to bootstrap the orchestration framework in perform the first level ForEach calls in sequence for the metadata stages.",
"activities": [
{
"name": "Get Stages",
"description": "Returns a distinct list of execution stages within the framework metadata.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Set Execution Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetStages]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@variables('ExecutionId')",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Stages",
"description": "Top level ForEach to sequentially call all processing stages within the framework metadata. Items for iteration passed from the Get Stages lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Stages",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Stages').output.value",
"type": "Expression"
},
"isSequential": true,
"activities": [
{
"name": "Stage Executor",
"description": "Call to the framework generic child pipeline for a given execution stage.",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Log Stage Preparing",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "03-Child",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"StageId": {
"value": "@item().StageId",
"type": "Expression"
},
"ExecutionId": {
"value": "@variables('ExecutionId')",
"type": "Expression"
}
}
}
},
{
"name": "Log Stage Preparing",
"description": "Update the current execution table flagging all pipelines within the stage as preparing.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Check and Update Blockers",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogStagePreparing]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@variables('ExecutionId')",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check and Update Blockers",
"description": "Used to double check and stop the next execution stage if failures and blockers have be incurred. This also depends on the failure handling property value which defines the stored procedure behaviour.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[CheckForBlockedPipelines]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@variables('ExecutionId')",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Execution Wrapper",
"description": "Wrapper to reset and restart processing or create a completely new execution instance of the framework metadata.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Clean Up Previous Run",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[ExecutionWrapper]",
"storedProcedureParameters": {
"CallingDataFactory": {
"type": "String",
"value": {
"value": "@pipeline().DataFactory",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Check Outcome and Update Logs",
"description": "After a successful execution run the current execution metadata is moved to the long term logging table by this stored procedure call. Otherwise an error will be raised.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Stages",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[UpdateExecutionLog]",
"storedProcedureParameters": {
"PerformErrorCheck": {
"value": {
"value": "@bool(1)",
"type": "Expression"
},
"type": "Boolean"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Metadata Integrity Checks",
"description": "Performs a series of checks on all metadata held in the framework SQLDB. This is intended to raise errors before an execution run even starts.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Execute Precursor",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[CheckMetadataIntegrity]",
"storedProcedureParameters": {
"DebugMode": {
"type": "Boolean",
"value": "false"
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Clean Up Previous Run",
"description": "Handle Worker pipelines that are reported as Running when the parent pipeline is called again. Get what the actual status of those pipelines is.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Metadata Integrity Checks",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Metadata Integrity Checks').output.value",
"type": "Expression"
},
"isSequential": false,
"batchCount": 20,
"activities": [
{
"name": "Get SPN Details",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetWorkerAuthDetails]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
}
},
"PipelineId": {
"type": "Int32",
"value": {
"value": "@item().PipelineId",
"type": "Expression"
}
},
"StageId": {
"type": "Int32",
"value": {
"value": "@item().StageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Pipeline Checking",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineChecking]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Pipeline Status",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Get SPN Details",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Log Pipeline Checking",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "CheckPipelineStatus",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',activity('Get SPN Details').output.firstRow.TenantId,'\",\n \"applicationId\": \"',activity('Get SPN Details').output.firstRow.AppId,'\",\n \"authenticationKey\": \"',activity('Get SPN Details').output.firstRow.AppSecret,'\",\n \"subscriptionId\": \"',activity('Get SPN Details').output.firstRow.SubscriptionId,'\",\n \"resourceGroup\": \"',item().ResourceGroupName,'\",\n \"factoryName\": \"',item().DataFactoryName,'\",\n \"pipelineName\": \"',item().PipelineName,'\",\n \"runId\": \"',item().AdfPipelineRunId,'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Set Pipeline Status",
"description": "Update the metadata depending on the actual pipeline outcome. Using the status as the case.",
"type": "Switch",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"on": {
"value": "@activity('Get Pipeline Status').output.Status",
"type": "Expression"
},
"cases": [
{
"value": "Failed",
"activities": [
{
"name": "Pipeline Status Failed",
"description": "Updates the current execution table with a pipeline status of failed if the function outcome is failed. Also blocks pipelines in the downstream execution stage.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": null,
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Succeeded",
"activities": [
{
"name": "Pipeline Status Succeeded",
"description": "Updates the current execution table with a pipeline status of success if the function outcome is succeeded.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineSuccess]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Queued",
"activities": [
{
"name": "Pipeline Status Queued - Running",
"description": "Updates the current execution table with a pipeline status of running if the function outcome is queued.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "InProgress",
"activities": [
{
"name": "Pipeline Status InProgress - Running",
"description": "Updates the current execution table with a pipeline status of running if the function outcome is in progress.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Cancelled",
"activities": [
{
"name": "Pipeline Status Cancelled",
"description": "Updates the current execution table with a pipeline status of cancelled if the function outcome is cancelled.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineCancelled]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
},
"CleanUpRun": {
"value": {
"value": "@bool(1)",
"type": "Expression"
},
"type": "Boolean"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
],
"defaultActivities": [
{
"name": "Pipeline Status Unknown",
"description": "Updates the current execution table with a pipeline status of unknown if the function returns an unexpected outcome.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineUnknown]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
},
"CleanUpRun": {
"value": {
"value": "@bool(1)",
"type": "Expression"
},
"type": "Boolean"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Set Last Check DateTime",
"description": "Update the current execution table with a date time from when the function last checked the pipeline status.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineLastStatusCheck]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Execute Precursor",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[ExecutePrecursorProcedure]"
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Set Execution Id",
"description": "Set the local execution Id to a pipeline variable for each in several downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Execution Wrapper",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "ExecutionId",
"value": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
}
}
}
],
"variables": {
"ExecutionId": {
"type": "String"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk",
"Parent"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]",
"[concat(variables('factoryId'), '/pipelines/03-Child')]",
"[concat(variables('factoryId'), '/linkedServices/FrameworkFunctions')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/03-Child')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk child pipeline used to execute Worker pipelines within a given execution stage. This pipeline will be called once for each stage, then execute all Workers in parallel.",
"activities": [
{
"name": "Get Pipelines",
"description": "Returns all pipelines from the metadata to be executed within a given processing stage.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelinesInStage]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
}
},
"StageId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Pipelines",
"description": "Second level ForEach to run in parallel all pipelines within the stage. Items for iteration passed from the Get Pipelines lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Pipelines",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Pipelines').output.value",
"type": "Expression"
},
"isSequential": false,
"batchCount": 50,
"activities": [
{
"name": "Worker Pipeline Executor",
"description": "Run the required worker pipeline and wait for its completion. Update metadata once done.",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "04-Infant",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"executionId": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"stageId": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"pipelineId": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
}
}
]
}
}
],
"parameters": {
"StageId": {
"type": "int"
},
"ExecutionId": {
"type": "string"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk",
"Child"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/pipelines/04-Infant')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/04-Infant')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk infant pipeline used to check when the processing pipeline called by the Child completes and passes the resulting status back to the metadata database.",
"activities": [
{
"name": "Execute Worker Pipeline",
"description": "The lowest level executor with the metadata framework to call existing processing pipelines within Data Factory. The function called will block processing and wait for an outcome.",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Log Pipeline Running",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Pipeline Params",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set App Id",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set App Secret",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Subscription Id",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Tenant Id",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Pipeline Name",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Data Factory Name",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Resource Group",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "ExecutePipeline",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n\t\"tenantId\": \"',variables('WorkerTenantId'),'\",\n\t\"applicationId\": \"',variables('WorkerAppId'),'\",\n\t\"authenticationKey\": \"',variables('WorkerAppSecret'),'\",\n\t\"subscriptionId\": \"',variables('WorkerSubscriptionId'),'\",\n\t\"resourceGroup\": \"',variables('WorkerResourceGroup'),'\",\n\t\"factoryName\": \"',variables('WorkerDataFactoryName'),'\",\n\t\"pipelineName\": \"',variables('WorkerPipelineName'),'\"',activity('Get Pipeline Params').output.firstRow.Params,'\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Pipeline Params",
"description": "Returns any parameters from metadata required for the processing pipeline being called. The output can be an empty string if no parameters are required.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelineParameters]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Pipeline Running",
"description": "Sets the current pipeline with a status of running within the current execution database table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Worker Authentication Details",
"description": "Return the SPN ID and Secret for the worker pipeline being executed. Called at this level as each pipeline can have a different SPN.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetWorkerAuthDetails]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
}
},
"PipelineId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
}
},
"StageId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Execute Function Activity Failure",
"description": "Handle true failures from calling out to the Azure Function and update the current execution table accordingly so a restart can occur.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Worker Pipeline",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
},
"CallingActivity": {
"value": "ExecuteWorkerPipeline",
"type": "String"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Update Run Id",
"description": "Provide the actual ADF run ID back to the current execution table for long term logging and alignment between the metadata other Azure monitoring tools.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Set Run Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunId]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@variables('WorkerRunId')",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check For Alerts",
"description": "Checks the properties tables and if any recipients in the database require alerts sending for the current pipeline ID.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Update Run Id",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Pipeline Result",
"dependencyConditions": [
"Completed"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[CheckForEmailAlerts]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": true
}
},
{
"name": "Send Alerts",
"description": "True = alerts need sending.\nFalse = do nothing.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Check For Alerts",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@activity('Check For Alerts').output.firstRow.SendAlerts",
"type": "Expression"
},
"ifTrueActivities": [
{
"name": "Get Email Parts",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetEmailAlertParts]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": true
}
},
{
"name": "Send Email",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Get Email Parts",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "SendEmail",
"method": "POST",
"headers": {},
"body": {
"value": "@activity('Get Email Parts').output.firstRow",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Wait Until Pipeline Completes",
"description": "Loops until the Worker pipeline called completes.\n\nSimple status:\n- Running = new iteration.\n- Done = break.",
"type": "Until",
"dependsOn": [
{
"activity": "Get Wait Duration",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Execute Worker Pipeline",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Run Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@variables('WorkerPipelineState')",
"type": "Expression"
},
"activities": [
{
"name": "Get Worker Pipeline Status",
"description": "Checks the status of a given processing pipeline and provides the value for the downstream framework activities to act upon.",
"type": "AzureFunctionActivity",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "CheckPipelineStatus",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',variables('WorkerTenantId'),'\",\n \"applicationId\": \"',variables('WorkerAppId'),'\",\n \"authenticationKey\": \"',variables('WorkerAppSecret'),'\",\n \"subscriptionId\": \"',variables('WorkerSubscriptionId'),'\",\n \"resourceGroup\": \"',variables('WorkerResourceGroup'),'\",\n \"factoryName\": \"',variables('WorkerDataFactoryName'),'\",\n \"pipelineName\": \"',variables('WorkerPipelineName'),'\",\n \"runId\": \"',variables('WorkerRunId'),'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Wait If Running",
"description": "True = Do nothing.\nFalse = Wait, before the next iteration.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Set Worker State",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@variables('WorkerPipelineState')",
"type": "Expression"
},
"ifFalseActivities": [
{
"name": "Wait for Pipeline",
"description": "The processing pipeline is still running so Wait before checking its status again.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@activity('Get Wait Duration').output.firstRow.PropertyValue",
"type": "Expression"
}
}
}
]
}
},
{
"name": "Set Last Check DateTime",
"description": "Update the current execution table with a date time from when the Worker pipeline status was last checked as part of the Until iterations.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Worker Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineLastStatusCheck]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Check Function Activity Failure",
"description": "Report to the current execution table that the framework pipeline activity has failed. This failure is outside of the scope of the framework and is probably related to a wider platform problem.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Worker Pipeline Status",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"CallingActivity": {
"value": "GetWorkerPipelineStatus",
"type": "String"
},
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Set Worker State",
"description": "Set the bool state of the Worker pipeline to be used by the Until and If expressions. True = Complete, False = Running.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Worker Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerPipelineState",
"value": {
"value": "@equals('Done',activity('Get Worker Pipeline Status').output.SimpleStatus)",
"type": "Expression"
}
}
}
],
"timeout": "7.00:00:00"
}
},
{
"name": "Set Pipeline Result",
"description": "Receives the outcome from the function execution for a given processing pipeline and updates the current execution table with different pipelines status values depending on the result (case).",
"type": "Switch",
"dependsOn": [
{
"activity": "Wait Until Pipeline Completes",
"dependencyConditions": [
"Completed"
]
}
],
"userProperties": [],
"typeProperties": {
"on": {
"value": "@activity('Get Worker Pipeline Status').output.Status",
"type": "Expression"
},
"cases": [
{
"value": "Succeeded",
"activities": [
{
"name": "Pipeline Status Succeeded",
"description": "Updates the current execution table with a pipeline status of success if the function outcome is succeeded.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineSuccess]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Failed",
"activities": [
{
"name": "Pipeline Status Failed",
"description": "Updates the current execution table with a pipeline status of failed if the function outcome is failed. Also blocks pipelines in the downstream execution stage.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@variables('WorkerRunId')",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Worker Pipeline Error Details",
"description": "Get the activity error details for the run ID of the worker pipeline called. Returns an array of all errors.",
"type": "AzureFunctionActivity",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "GetActivityErrors",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',variables('WorkerTenantId'),'\",\n \"applicationId\": \"',variables('WorkerAppId'),'\",\n \"authenticationKey\": \"',variables('WorkerAppSecret'),'\",\n \"subscriptionId\": \"',variables('WorkerSubscriptionId'),'\",\n \"resourceGroup\": \"',variables('WorkerResourceGroup'),'\",\n \"factoryName\": \"',variables('WorkerDataFactoryName'),'\",\n \"pipelineName\": \"',variables('WorkerPipelineName'),'\",\n \"runId\": \"',variables('WorkerRunId'),'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Error Details",
"description": "Parses pipeline error details and persists them to the metadata database error log table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Worker Pipeline Error Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetErrorLogDetails]",
"storedProcedureParameters": {
"JsonErrorDetails": {
"value": {
"value": "@string(activity('Get Worker Pipeline Error Details').output)",
"type": "Expression"
},
"type": "String"
},
"LocalExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Cancelled",
"activities": [
{
"name": "Pipeline Status Cancelled",
"description": "Updates the current execution table with a pipeline status of cancelled if the function outcome is cancelled.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineCancelled]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
],
"defaultActivities": [
{
"name": "Pipeline Status Unknown",
"description": "Updates the current execution table with a pipeline status of unknown if the function returns an unexpected outcome.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineUnknown]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Get Wait Duration",
"description": "Return wait duration in seconds from database properties table to be used during each Until iteration when the Worker pipeline is still running.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "PipelineStatusCheckDuration"
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Set App Id",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Worker Authentication Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerAppId",
"value": {
"value": "@activity('Get Worker Authentication Details').output.firstRow.AppId",
"type": "Expression"
}
}
},
{
"name": "Set App Secret",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Worker Authentication Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerAppSecret",
"value": {
"value": "@activity('Get Worker Authentication Details').output.firstRow.AppSecret",
"type": "Expression"
}
}
},
{
"name": "Set Run Id",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Execute Worker Pipeline",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerRunId",
"value": {
"value": "@activity('Execute Worker Pipeline').output.RunId",
"type": "Expression"
}
}
},
{
"name": "Get Worker Pipeline Details",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetWorkerPipelineDetails]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
}
},
"PipelineId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
}
},
"StageId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Set Tenant Id",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Worker Authentication Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerTenantId",
"value": {
"value": "@activity('Get Worker Authentication Details').output.firstRow.TenantId",
"type": "Expression"
}
}
},
{
"name": "Set Subscription Id",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Worker Authentication Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerSubscriptionId",
"value": {
"value": "@activity('Get Worker Authentication Details').output.firstRow.SubscriptionId",
"type": "Expression"
}
}
},
{
"name": "Set Pipeline Name",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Worker Pipeline Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerPipelineName",
"value": {
"value": "@activity('Get Worker Pipeline Details').output.firstRow.PipelineName",
"type": "Expression"
}
}
},
{
"name": "Set Data Factory Name",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Worker Pipeline Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerDataFactoryName",
"value": {
"value": "@activity('Get Worker Pipeline Details').output.firstRow.DataFactoryName",
"type": "Expression"
}
}
},
{
"name": "Set Resource Group",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Worker Pipeline Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerResourceGroup",
"value": {
"value": "@activity('Get Worker Pipeline Details').output.firstRow.ResourceGroupName",
"type": "Expression"
}
}
}
],
"parameters": {
"executionId": {
"type": "string"
},
"stageId": {
"type": "int"
},
"pipelineId": {
"type": "int"
}
},
"variables": {
"WorkerPipelineState": {
"type": "Boolean"
},
"WorkerAppId": {
"type": "String"
},
"WorkerAppSecret": {
"type": "String"
},
"WorkerRunId": {
"type": "String"
},
"WorkerTenantId": {
"type": "String"
},
"WorkerSubscriptionId": {
"type": "String"
},
"WorkerPipelineName": {
"type": "String"
},
"WorkerDataFactoryName": {
"type": "String"
},
"WorkerResourceGroup": {
"type": "String"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk",
"Infant"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/FrameworkFunctions')]",
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Intentional Error')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait1",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
},
{
"name": "Raise Errors or Not",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Wait1",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@equals(pipeline().parameters.RaiseErrors,'true')",
"type": "Expression"
},
"ifTrueActivities": [
{
"name": "Call Fail Procedure",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[dbo].[FailProcedure]",
"storedProcedureParameters": {
"RaiseError": {
"value": {
"value": "@pipeline().parameters.RaiseErrors",
"type": "Expression"
},
"type": "String"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
}
],
"parameters": {
"RaiseErrors": {
"type": "string",
"defaultValue": "false"
},
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Wait 1')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait1",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 10')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait10",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 2')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait2",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 3')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait3",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 4')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait4",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 5')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait5",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 6')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait6",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 7')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait7",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 8')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait8",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 9')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait9",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 15
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/GetSetMetadata')]",
"type": "Microsoft.DataFactory/factories/datasets",
"apiVersion": "2018-06-01",
"properties": {
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
},
"annotations": [
"ADF.procfwk"
],
"type": "AzureSqlTable",
"schema": [],
"typeProperties": {}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/FrameworkFunctions')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"annotations": [
"ADF.procfwk"
],
"type": "AzureFunction",
"typeProperties": {
"functionAppUrl": "[parameters('FrameworkFunctions_properties_typeProperties_functionAppUrl')]",
"functionKey": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "FrameworkFunctionsKey"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Keys')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Connection to Key Vault for all other ADF linked service credentials required to run the processing framework.",
"annotations": [
"ADF.procfwk"
],
"type": "AzureKeyVault",
"typeProperties": {
"baseUrl": "[parameters('Keys_properties_typeProperties_baseUrl')]"
}
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/SupportDatabase')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Connection between ADF and processing framework metadata SQLDB.",
"annotations": [
"ADF.procfwk"
],
"type": "AzureSqlDatabase",
"typeProperties": {
"connectionString": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "[parameters('SupportDatabase_properties_typeProperties_connectionString_secretName')]"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/FunctionalTestingTrigger')]",
"type": "Microsoft.DataFactory/factories/triggers",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used for functional testing of the framework in a dedicated environment.",
"annotations": [
"ADF.procfwk"
],
"runtimeState": "Stopped",
"pipelines": [
{
"pipelineReference": {
"referenceName": "01-Grandparent",
"type": "PipelineReference"
},
"parameters": {}
}
],
"type": "ScheduleTrigger",
"typeProperties": {
"recurrence": {
"frequency": "Hour",
"interval": 2,
"startTime": "2020-04-06T15:00:00.000Z",
"timeZone": "UTC"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/pipelines/01-Grandparent')]"
]
}
]
}
================================================
FILE: ARM Templates/Data Factory/v1.9.1 Export.json
================================================
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"factoryName": {
"type": "string",
"metadata": "Data Factory name",
"defaultValue": ""
},
"FrameworkFunctions_properties_typeProperties_functionAppUrl": {
"type": "string",
"defaultValue": ""
},
"Keys_properties_typeProperties_baseUrl": {
"type": "string",
"defaultValue": ""
},
"SupportDatabase_properties_typeProperties_connectionString_secretName": {
"type": "string",
"defaultValue": ""
}
},
"variables": {
"factoryId": "[concat('Microsoft.DataFactory/factories/', parameters('factoryName'))]"
},
"resources": [
{
"name": "[concat(parameters('factoryName'), '/01-Grandparent')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk grandparent pipeline used optionally to bootstrap any wider processes in your Data Factory that then calls the processing framework.",
"activities": [
{
"name": "Framework Processing",
"description": "Call procfwk",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "02-Parent",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {}
}
}
],
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk",
"Grandparent"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/pipelines/02-Parent')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/02-Parent')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk parent pipeline used to bootstrap the orchestration framework in perform the first level ForEach calls in sequence for the metadata stages.",
"activities": [
{
"name": "Get Stages",
"description": "Returns a distinct list of execution stages within the framework metadata.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Set Execution Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetStages]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@variables('ExecutionId')",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Stages",
"description": "Top level ForEach to sequentially call all processing stages within the framework metadata. Items for iteration passed from the Get Stages lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Stages",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Stages').output.value",
"type": "Expression"
},
"isSequential": true,
"activities": [
{
"name": "Stage Executor",
"description": "Call to the framework generic child pipeline for a given execution stage.",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Log Stage Preparing",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "03-Child",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"StageId": {
"value": "@item().StageId",
"type": "Expression"
},
"ExecutionId": {
"value": "@variables('ExecutionId')",
"type": "Expression"
}
}
}
},
{
"name": "Log Stage Preparing",
"description": "Update the current execution table flagging all pipelines within the stage as preparing.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Check and Update Blockers",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogStagePreparing]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@variables('ExecutionId')",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check and Update Blockers",
"description": "Used to double check and stop the next execution stage if failures and blockers have be incurred. This also depends on the failure handling property value which defines the stored procedure behaviour.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[CheckForBlockedPipelines]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@variables('ExecutionId')",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Execution Wrapper",
"description": "Wrapper to reset and restart processing or create a completely new execution instance of the framework metadata.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Clean Up Previous Run",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[ExecutionWrapper]",
"storedProcedureParameters": {
"CallingDataFactory": {
"type": "String",
"value": {
"value": "@pipeline().DataFactory",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Check Outcome and Update Logs",
"description": "After a successful execution run the current execution metadata is moved to the long term logging table by this stored procedure call. Otherwise an error will be raised.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Stages",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[UpdateExecutionLog]",
"storedProcedureParameters": {
"PerformErrorCheck": {
"value": {
"value": "@bool(1)",
"type": "Expression"
},
"type": "Boolean"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Metadata Integrity Checks",
"description": "Performs a series of checks on all metadata held in the framework SQLDB. This is intended to raise errors before an execution run even starts.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Execute Precursor",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[CheckMetadataIntegrity]",
"storedProcedureParameters": {
"DebugMode": {
"type": "Boolean",
"value": "false"
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Clean Up Previous Run",
"description": "Handle Worker pipelines that are reported as Running when the parent pipeline is called again. Get what the actual status of those pipelines is.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Metadata Integrity Checks",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Metadata Integrity Checks').output.value",
"type": "Expression"
},
"isSequential": false,
"batchCount": 50,
"activities": [
{
"name": "Get SPN Details",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetWorkerAuthDetails]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
}
},
"PipelineId": {
"type": "Int32",
"value": {
"value": "@item().PipelineId",
"type": "Expression"
}
},
"StageId": {
"type": "Int32",
"value": {
"value": "@item().StageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Pipeline Checking",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineChecking]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Pipeline Status",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Get SPN Details",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Log Pipeline Checking",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"functionName": "CheckPipelineStatus",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',activity('Get SPN Details').output.firstRow.TenantId,'\",\n \"applicationId\": \"',activity('Get SPN Details').output.firstRow.AppId,'\",\n \"authenticationKey\": \"',activity('Get SPN Details').output.firstRow.AppSecret,'\",\n \"subscriptionId\": \"',activity('Get SPN Details').output.firstRow.SubscriptionId,'\",\n \"resourceGroup\": \"',item().ResourceGroupName,'\",\n \"factoryName\": \"',item().DataFactoryName,'\",\n \"pipelineName\": \"',item().PipelineName,'\",\n \"runId\": \"',item().AdfPipelineRunId,'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Set Pipeline Status",
"description": "Update the metadata depending on the actual pipeline outcome. Using the status as the case.",
"type": "Switch",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"on": {
"value": "@activity('Get Pipeline Status').output.Status",
"type": "Expression"
},
"cases": [
{
"value": "Failed",
"activities": [
{
"name": "Pipeline Status Failed",
"description": "Updates the current execution table with a pipeline status of failed if the function outcome is failed. Also blocks pipelines in the downstream execution stage.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": null,
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Succeeded",
"activities": [
{
"name": "Pipeline Status Succeeded",
"description": "Updates the current execution table with a pipeline status of success if the function outcome is succeeded.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineSuccess]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Queued",
"activities": [
{
"name": "Pipeline Status Queued - Running",
"description": "Updates the current execution table with a pipeline status of running if the function outcome is queued.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "InProgress",
"activities": [
{
"name": "Pipeline Status InProgress - Running",
"description": "Updates the current execution table with a pipeline status of running if the function outcome is in progress.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Cancelled",
"activities": [
{
"name": "Pipeline Status Cancelled",
"description": "Updates the current execution table with a pipeline status of cancelled if the function outcome is cancelled.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineCancelled]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
},
"CleanUpRun": {
"value": {
"value": "@bool(1)",
"type": "Expression"
},
"type": "Boolean"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
],
"defaultActivities": [
{
"name": "Pipeline Status Unknown",
"description": "Updates the current execution table with a pipeline status of unknown if the function returns an unexpected outcome.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineUnknown]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
},
"CleanUpRun": {
"value": {
"value": "@bool(1)",
"type": "Expression"
},
"type": "Boolean"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Set Last Check DateTime",
"description": "Update the current execution table with a date time from when the function last checked the pipeline status.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineLastStatusCheck]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Execute Precursor",
"description": "Uses the database property value ExecutionPrecursorProc to run any custom logic against the metadata database before the execution run starts.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[ExecutePrecursorProcedure]"
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Set Execution Id",
"description": "Set the local execution Id to a pipeline variable for each in several downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Execution Wrapper",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "ExecutionId",
"value": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
}
}
}
],
"variables": {
"ExecutionId": {
"type": "String"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk",
"Parent"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]",
"[concat(variables('factoryId'), '/pipelines/03-Child')]",
"[concat(variables('factoryId'), '/linkedServices/FrameworkFunctions')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/03-Child')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk child pipeline used to execute Worker pipelines within a given execution stage. This pipeline will be called once for each stage, then execute all Workers in parallel.",
"activities": [
{
"name": "Get Pipelines",
"description": "Returns all pipelines from the metadata to be executed within a given processing stage.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelinesInStage]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
}
},
"StageId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Pipelines",
"description": "Second level ForEach to run in parallel all pipelines within the stage. Items for iteration passed from the Get Pipelines lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Pipelines",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Pipelines').output.value",
"type": "Expression"
},
"isSequential": false,
"batchCount": 50,
"activities": [
{
"name": "Worker Pipeline Executor",
"description": "Run the required worker pipeline and wait for its completion. Update metadata once done.",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "04-Infant",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"executionId": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"stageId": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"pipelineId": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
}
}
]
}
}
],
"parameters": {
"StageId": {
"type": "int"
},
"ExecutionId": {
"type": "string"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk",
"Child"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/pipelines/04-Infant')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/04-Infant')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk infant pipeline used to check when the processing pipeline called by the Child completes and passes the resulting status back to the metadata database.",
"activities": [
{
"name": "Execute Worker Pipeline",
"description": "The lowest level executor with the metadata framework to call existing processing pipelines within Data Factory. The function called will block processing and wait for an outcome.",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Log Pipeline Running",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Pipeline Params",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set App Id",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set App Secret",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Subscription Id",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Tenant Id",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Pipeline Name",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Data Factory Name",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Resource Group",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"functionName": "ExecutePipeline",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n\t\"tenantId\": \"',variables('WorkerTenantId'),'\",\n\t\"applicationId\": \"',variables('WorkerAppId'),'\",\n\t\"authenticationKey\": \"',variables('WorkerAppSecret'),'\",\n\t\"subscriptionId\": \"',variables('WorkerSubscriptionId'),'\",\n\t\"resourceGroup\": \"',variables('WorkerResourceGroup'),'\",\n\t\"factoryName\": \"',variables('WorkerDataFactoryName'),'\",\n\t\"pipelineName\": \"',variables('WorkerPipelineName'),'\"',activity('Get Pipeline Params').output.firstRow.Params,'\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Pipeline Params",
"description": "Returns any parameters from metadata required for the processing pipeline being called. The output can be an empty string if no parameters are required.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelineParameters]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Pipeline Running",
"description": "Sets the current pipeline with a status of running within the current execution database table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Worker Authentication Details",
"description": "Return the SPN ID and Secret for the worker pipeline being executed. Called at this level as each pipeline can have a different SPN.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": true,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetWorkerAuthDetails]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
}
},
"PipelineId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
}
},
"StageId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Execute Function Activity Failure",
"description": "Handle true failures from calling out to the Azure Function and update the current execution table accordingly so a restart can occur.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Worker Pipeline",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
},
"CallingActivity": {
"value": "ExecuteWorkerPipeline",
"type": "String"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Update Run Id",
"description": "Provide the actual ADF run ID back to the current execution table for long term logging and alignment between the metadata other Azure monitoring tools.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Set Run Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunId]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@variables('WorkerRunId')",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check For Alerts",
"description": "Checks the properties tables and if any recipients in the database require alerts sending for the current pipeline ID.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Update Run Id",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Pipeline Result",
"dependencyConditions": [
"Completed"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[CheckForEmailAlerts]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": true
}
},
{
"name": "Send Alerts",
"description": "True = alerts need sending.\nFalse = do nothing.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Check For Alerts",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@activity('Check For Alerts').output.firstRow.SendAlerts",
"type": "Expression"
},
"ifTrueActivities": [
{
"name": "Get Email Parts",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": true,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetEmailAlertParts]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": true
}
},
{
"name": "Send Email",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Get Email Parts",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"functionName": "SendEmail",
"method": "POST",
"headers": {},
"body": {
"value": "@activity('Get Email Parts').output.firstRow",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Wait Until Pipeline Completes",
"description": "Loops until the Worker pipeline called completes.\n\nSimple status:\n- Running = new iteration.\n- Done = break.",
"type": "Until",
"dependsOn": [
{
"activity": "Get Wait Duration",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Execute Worker Pipeline",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Run Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@variables('WorkerPipelineState')",
"type": "Expression"
},
"activities": [
{
"name": "Get Worker Pipeline Status",
"description": "Checks the status of a given processing pipeline and provides the value for the downstream framework activities to act upon.",
"type": "AzureFunctionActivity",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"functionName": "CheckPipelineStatus",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',variables('WorkerTenantId'),'\",\n \"applicationId\": \"',variables('WorkerAppId'),'\",\n \"authenticationKey\": \"',variables('WorkerAppSecret'),'\",\n \"subscriptionId\": \"',variables('WorkerSubscriptionId'),'\",\n \"resourceGroup\": \"',variables('WorkerResourceGroup'),'\",\n \"factoryName\": \"',variables('WorkerDataFactoryName'),'\",\n \"pipelineName\": \"',variables('WorkerPipelineName'),'\",\n \"runId\": \"',variables('WorkerRunId'),'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Wait If Running",
"description": "True = Do nothing.\nFalse = Wait, before the next iteration.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Set Worker State",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@variables('WorkerPipelineState')",
"type": "Expression"
},
"ifFalseActivities": [
{
"name": "Wait for Pipeline",
"description": "The processing pipeline is still running so Wait before checking its status again.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@activity('Get Wait Duration').output.firstRow.PropertyValue",
"type": "Expression"
}
}
}
]
}
},
{
"name": "Set Last Check DateTime",
"description": "Update the current execution table with a date time from when the Worker pipeline status was last checked as part of the Until iterations.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Worker Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineLastStatusCheck]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Check Function Activity Failure",
"description": "Report to the current execution table that the framework pipeline activity has failed. This failure is outside of the scope of the framework and is probably related to a wider platform problem.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Worker Pipeline Status",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"CallingActivity": {
"value": "GetWorkerPipelineStatus",
"type": "String"
},
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Set Worker State",
"description": "Set the bool state of the Worker pipeline to be used by the Until and If expressions. True = Complete, False = Running.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Worker Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerPipelineState",
"value": {
"value": "@equals('Done',activity('Get Worker Pipeline Status').output.SimpleStatus)",
"type": "Expression"
}
}
}
],
"timeout": "0.00:10:00"
}
},
{
"name": "Set Pipeline Result",
"description": "Receives the outcome from the function execution for a given processing pipeline and updates the current execution table with different pipelines status values depending on the result (case).",
"type": "Switch",
"dependsOn": [
{
"activity": "Wait Until Pipeline Completes",
"dependencyConditions": [
"Completed"
]
}
],
"userProperties": [],
"typeProperties": {
"on": {
"value": "@activity('Get Worker Pipeline Status').output.Status",
"type": "Expression"
},
"cases": [
{
"value": "Succeeded",
"activities": [
{
"name": "Pipeline Status Succeeded",
"description": "Updates the current execution table with a pipeline status of success if the function outcome is succeeded.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineSuccess]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Failed",
"activities": [
{
"name": "Pipeline Status Failed",
"description": "Updates the current execution table with a pipeline status of failed if the function outcome is failed. Also blocks pipelines in the downstream execution stage.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@variables('WorkerRunId')",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Worker Pipeline Error Details",
"description": "Get the activity error details for the run ID of the worker pipeline called. Returns an array of all errors.",
"type": "AzureFunctionActivity",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"functionName": "GetActivityErrors",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',variables('WorkerTenantId'),'\",\n \"applicationId\": \"',variables('WorkerAppId'),'\",\n \"authenticationKey\": \"',variables('WorkerAppSecret'),'\",\n \"subscriptionId\": \"',variables('WorkerSubscriptionId'),'\",\n \"resourceGroup\": \"',variables('WorkerResourceGroup'),'\",\n \"factoryName\": \"',variables('WorkerDataFactoryName'),'\",\n \"pipelineName\": \"',variables('WorkerPipelineName'),'\",\n \"runId\": \"',variables('WorkerRunId'),'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Error Details",
"description": "Parses pipeline error details and persists them to the metadata database error log table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Worker Pipeline Error Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetErrorLogDetails]",
"storedProcedureParameters": {
"JsonErrorDetails": {
"value": {
"value": "@string(activity('Get Worker Pipeline Error Details').output)",
"type": "Expression"
},
"type": "String"
},
"LocalExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Cancelled",
"activities": [
{
"name": "Pipeline Status Cancelled",
"description": "Updates the current execution table with a pipeline status of cancelled if the function outcome is cancelled.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineCancelled]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
],
"defaultActivities": [
{
"name": "Pipeline Status Unknown",
"description": "Updates the current execution table with a pipeline status of unknown if the function returns an unexpected outcome.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineUnknown]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Get Wait Duration",
"description": "Return wait duration in seconds from database properties table to be used during each Until iteration when the Worker pipeline is still running.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "PipelineStatusCheckDuration"
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Set App Id",
"description": "Set local variable from activity output once for value reuse in downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Worker Authentication Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerAppId",
"value": {
"value": "@activity('Get Worker Authentication Details').output.firstRow.AppId",
"type": "Expression"
}
}
},
{
"name": "Set App Secret",
"description": "Set local variable from activity output once for value reuse in downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Worker Authentication Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerAppSecret",
"value": {
"value": "@activity('Get Worker Authentication Details').output.firstRow.AppSecret",
"type": "Expression"
}
}
},
{
"name": "Set Run Id",
"description": "Set local variable from activity output once for value reuse in downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Execute Worker Pipeline",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerRunId",
"value": {
"value": "@activity('Execute Worker Pipeline').output.RunId",
"type": "Expression"
}
}
},
{
"name": "Get Worker Pipeline Details",
"description": "Return none sensitive worker pipeline information for metadata database. Including target data factory, pipeline name and resource group.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": true,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetWorkerPipelineDetails]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
}
},
"PipelineId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
}
},
"StageId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Set Tenant Id",
"description": "Set local variable from activity output once for value reuse in downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Worker Authentication Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerTenantId",
"value": {
"value": "@activity('Get Worker Authentication Details').output.firstRow.TenantId",
"type": "Expression"
}
}
},
{
"name": "Set Subscription Id",
"description": "Set local variable from activity output once for value reuse in downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Worker Authentication Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerSubscriptionId",
"value": {
"value": "@activity('Get Worker Authentication Details').output.firstRow.SubscriptionId",
"type": "Expression"
}
}
},
{
"name": "Set Pipeline Name",
"description": "Set local variable from activity output once for value reuse in downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Worker Pipeline Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerPipelineName",
"value": {
"value": "@activity('Get Worker Pipeline Details').output.firstRow.PipelineName",
"type": "Expression"
}
}
},
{
"name": "Set Data Factory Name",
"description": "Set local variable from activity output once for value reuse in downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Worker Pipeline Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerDataFactoryName",
"value": {
"value": "@activity('Get Worker Pipeline Details').output.firstRow.DataFactoryName",
"type": "Expression"
}
}
},
{
"name": "Set Resource Group",
"description": "Set local variable from activity output once for value reuse in downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Worker Pipeline Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerResourceGroup",
"value": {
"value": "@activity('Get Worker Pipeline Details').output.firstRow.ResourceGroupName",
"type": "Expression"
}
}
}
],
"parameters": {
"executionId": {
"type": "string"
},
"stageId": {
"type": "int"
},
"pipelineId": {
"type": "int"
}
},
"variables": {
"WorkerPipelineState": {
"type": "Boolean"
},
"WorkerAppId": {
"type": "String"
},
"WorkerAppSecret": {
"type": "String"
},
"WorkerRunId": {
"type": "String"
},
"WorkerTenantId": {
"type": "String"
},
"WorkerSubscriptionId": {
"type": "String"
},
"WorkerPipelineName": {
"type": "String"
},
"WorkerDataFactoryName": {
"type": "String"
},
"WorkerResourceGroup": {
"type": "String"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk",
"Infant"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/FrameworkFunctions')]",
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Intentional Error')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait1",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
},
{
"name": "Raise Errors or Not",
"description": "Framework development worker simulator.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Wait1",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@equals(pipeline().parameters.RaiseErrors,'true')",
"type": "Expression"
},
"ifTrueActivities": [
{
"name": "Call Fail Procedure",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[dbo].[FailProcedure]",
"storedProcedureParameters": {
"RaiseError": {
"value": {
"value": "@pipeline().parameters.RaiseErrors",
"type": "Expression"
},
"type": "String"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
}
],
"parameters": {
"RaiseErrors": {
"type": "string",
"defaultValue": "false"
},
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Wait 1')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait1",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 10')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait10",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 2')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait2",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 3')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait3",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 4')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait4",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 5')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait5",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 6')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait6",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 7')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait7",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 8')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait8",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 9')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait9",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 15
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/GetSetMetadata')]",
"type": "Microsoft.DataFactory/factories/datasets",
"apiVersion": "2018-06-01",
"properties": {
"description": "Single generic dataset used to get and set all database metadata.",
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
],
"type": "AzureSqlTable",
"schema": [],
"typeProperties": {}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/FrameworkFunctions')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Interact with the Azure Functions App used as middle ware when making requests to Worker pipelines. Authentication done at the Function App level.",
"annotations": [
"ADF.procfwk"
],
"type": "AzureFunction",
"typeProperties": {
"functionAppUrl": "[parameters('FrameworkFunctions_properties_typeProperties_functionAppUrl')]",
"functionKey": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "FrameworkFunctionsKey"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Keys')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Connection to Key Vault for all other ADF linked service credentials required to run the processing framework.",
"annotations": [
"ADF.procfwk"
],
"type": "AzureKeyVault",
"typeProperties": {
"baseUrl": "[parameters('Keys_properties_typeProperties_baseUrl')]"
}
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/SupportDatabase')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Connection between ADF and processing framework metadata SQLDB.",
"annotations": [
"ADF.procfwk"
],
"type": "AzureSqlDatabase",
"typeProperties": {
"connectionString": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "[parameters('SupportDatabase_properties_typeProperties_connectionString_secretName')]"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/FunctionalTestingTrigger')]",
"type": "Microsoft.DataFactory/factories/triggers",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used for functional testing of the framework in a dedicated environment.",
"annotations": [
"ADF.procfwk"
],
"runtimeState": "Stopped",
"pipelines": [
{
"pipelineReference": {
"referenceName": "01-Grandparent",
"type": "PipelineReference"
},
"parameters": {}
}
],
"type": "ScheduleTrigger",
"typeProperties": {
"recurrence": {
"frequency": "Hour",
"interval": 2,
"startTime": "2020-04-06T15:00:00Z",
"timeZone": "UTC"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/pipelines/01-Grandparent')]"
]
}
]
}
================================================
FILE: ARM Templates/Data Factory/v1.9.2 Export.json
================================================
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"factoryName": {
"type": "string",
"metadata": "Data Factory name",
"defaultValue": ""
},
"FrameworkFunctions_properties_typeProperties_functionAppUrl": {
"type": "string",
"defaultValue": ""
},
"Keys_properties_typeProperties_baseUrl": {
"type": "string",
"defaultValue": ""
},
"SupportDatabase_properties_typeProperties_connectionString_secretName": {
"type": "string",
"defaultValue": ""
}
},
"variables": {
"factoryId": "[concat('Microsoft.DataFactory/factories/', parameters('factoryName'))]"
},
"resources": [
{
"name": "[concat(parameters('factoryName'), '/01-Grandparent')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk grandparent pipeline used optionally to bootstrap any wider processes in your Data Factory that then calls the processing framework.",
"activities": [
{
"name": "procfwk",
"description": "Call procfwk",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "02-Parent",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"BatchName": {
"value": "@pipeline().parameters.BatchName",
"type": "Expression"
}
}
}
}
],
"parameters": {
"BatchName": {
"type": "string",
"defaultValue": "NotUsed"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"procfwk",
"Grandparent"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/pipelines/02-Parent')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/02-Parent')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk parent pipeline used to bootstrap the orchestration framework in perform the first level ForEach calls in sequence for the metadata stages.",
"activities": [
{
"name": "Get Stages",
"description": "Returns a distinct list of execution stages within the framework metadata.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Set Execution Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetStages]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@variables('ExecutionId')",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Stages",
"description": "Top level ForEach to sequentially call all processing stages within the framework metadata. Items for iteration passed from the Get Stages lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Stages",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Stages').output.value",
"type": "Expression"
},
"isSequential": true,
"activities": [
{
"name": "Stage Executor",
"description": "Call to the framework generic child pipeline for a given execution stage.",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Log Stage Preparing",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "03-Child",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"StageId": {
"value": "@item().StageId",
"type": "Expression"
},
"ExecutionId": {
"value": "@variables('ExecutionId')",
"type": "Expression"
}
}
}
},
{
"name": "Log Stage Preparing",
"description": "Update the current execution table flagging all pipelines within the stage as preparing.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Check and Update Blockers",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogStagePreparing]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@variables('ExecutionId')",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check and Update Blockers",
"description": "Used to double check and stop the next execution stage if failures and blockers have be incurred. This also depends on the failure handling property value which defines the stored procedure behaviour.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[CheckForBlockedPipelines]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@variables('ExecutionId')",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Execution Wrapper",
"description": "Wrapper to reset and restart processing or create a completely new execution instance of the framework metadata.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Clean Up Previous Run",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[ExecutionWrapper]",
"storedProcedureParameters": {
"CallingDataFactory": {
"type": "String",
"value": {
"value": "@pipeline().DataFactory",
"type": "Expression"
}
},
"BatchName": {
"type": "String",
"value": {
"value": "@pipeline().parameters.BatchName",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Check Outcome and Update Logs",
"description": "After a successful execution run the current execution metadata is moved to the long term logging table by this stored procedure call. Otherwise an error will be raised.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Stages",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[UpdateExecutionLog]",
"storedProcedureParameters": {
"PerformErrorCheck": {
"value": {
"value": "@bool(1)",
"type": "Expression"
},
"type": "Boolean"
},
"ExecutionId": {
"value": {
"value": "@variables('ExecutionId')",
"type": "Expression"
},
"type": "Guid"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check Previous Execution",
"description": "Query the current execution table for worker pipelines that require a clean up from the previous execution run.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Execute Precursor",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[CheckPreviousExeuction]",
"storedProcedureParameters": {
"BatchName": {
"type": "String",
"value": {
"value": "@pipeline().parameters.BatchName",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Clean Up Previous Run",
"description": "Handle Worker pipelines that are reported as Running when the parent pipeline is called again. Get what the actual status of those pipelines is.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Check Previous Execution",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Check Metadata Integrity",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Check Previous Execution').output.value",
"type": "Expression"
},
"isSequential": false,
"batchCount": 50,
"activities": [
{
"name": "Get SPN Details",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": true,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetWorkerAuthDetails]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
}
},
"PipelineId": {
"type": "Int32",
"value": {
"value": "@item().PipelineId",
"type": "Expression"
}
},
"StageId": {
"type": "Int32",
"value": {
"value": "@item().StageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Pipeline Checking",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineChecking]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Pipeline Status",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Get SPN Details",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Log Pipeline Checking",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"functionName": "CheckPipelineStatus",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',activity('Get SPN Details').output.firstRow.TenantId,'\",\n \"applicationId\": \"',activity('Get SPN Details').output.firstRow.AppId,'\",\n \"authenticationKey\": \"',activity('Get SPN Details').output.firstRow.AppSecret,'\",\n \"subscriptionId\": \"',activity('Get SPN Details').output.firstRow.SubscriptionId,'\",\n \"resourceGroup\": \"',item().ResourceGroupName,'\",\n \"factoryName\": \"',item().DataFactoryName,'\",\n \"pipelineName\": \"',item().PipelineName,'\",\n \"runId\": \"',item().AdfPipelineRunId,'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Set Pipeline Status",
"description": "Update the metadata depending on the actual pipeline outcome. Using the status as the case.",
"type": "Switch",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"on": {
"value": "@activity('Get Pipeline Status').output.Status",
"type": "Expression"
},
"cases": [
{
"value": "Failed",
"activities": [
{
"name": "Pipeline Status Failed",
"description": "Updates the current execution table with a pipeline status of failed if the function outcome is failed. Also blocks pipelines in the downstream execution stage.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": null,
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Succeeded",
"activities": [
{
"name": "Pipeline Status Succeeded",
"description": "Updates the current execution table with a pipeline status of success if the function outcome is succeeded.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineSuccess]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Queued",
"activities": [
{
"name": "Pipeline Status Queued - Running",
"description": "Updates the current execution table with a pipeline status of running if the function outcome is queued.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "InProgress",
"activities": [
{
"name": "Pipeline Status InProgress - Running",
"description": "Updates the current execution table with a pipeline status of running if the function outcome is in progress.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Cancelled",
"activities": [
{
"name": "Pipeline Status Cancelled",
"description": "Updates the current execution table with a pipeline status of cancelled if the function outcome is cancelled.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineCancelled]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
},
"CleanUpRun": {
"value": {
"value": "@bool(1)",
"type": "Expression"
},
"type": "Boolean"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
],
"defaultActivities": [
{
"name": "Pipeline Status Unknown",
"description": "Updates the current execution table with a pipeline status of unknown if the function returns an unexpected outcome.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineUnknown]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
},
"CleanUpRun": {
"value": {
"value": "@bool(1)",
"type": "Expression"
},
"type": "Boolean"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Set Last Check DateTime",
"description": "Update the current execution table with a date time from when the function last checked the pipeline status.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineLastStatusCheck]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Execute Precursor",
"description": "Uses the database property value ExecutionPrecursorProc to run any custom logic against the metadata database before the execution run starts.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Is Parent Already Running",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[ExecutePrecursorProcedure]"
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Set Execution Id",
"description": "Set the local execution Id to a pipeline variable for each in several downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Execution Wrapper",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "ExecutionId",
"value": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
}
}
},
{
"name": "Is Parent Already Running",
"description": "Establish before anything else if the parent pipeline is already running. Batch execution aware.",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "Check For Running Pipeline",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"BatchName": {
"value": "@pipeline().parameters.BatchName",
"type": "Expression"
},
"PipelineName": {
"value": "@pipeline().Pipeline",
"type": "Expression"
},
"ThisRunId": {
"value": "@pipeline().RunId",
"type": "Expression"
}
}
}
},
{
"name": "Check Metadata Integrity",
"description": "Performs a series of checks on all metadata held in the framework SQLDB. This is intended to raise errors before an execution run even starts.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Precursor",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[CheckMetadataIntegrity]",
"storedProcedureParameters": {
"BatchName": {
"value": {
"value": "@pipeline().parameters.BatchName",
"type": "Expression"
},
"type": "String"
},
"DebugMode": {
"value": {
"value": "@bool(0)",
"type": "Expression"
},
"type": "Boolean"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
],
"parameters": {
"BatchName": {
"type": "string",
"defaultValue": "NotUsed"
}
},
"variables": {
"ExecutionId": {
"type": "String"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"procfwk",
"Parent"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]",
"[concat(variables('factoryId'), '/pipelines/Check For Running Pipeline')]",
"[concat(variables('factoryId'), '/pipelines/03-Child')]",
"[concat(variables('factoryId'), '/linkedServices/FrameworkFunctions')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/03-Child')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk child pipeline used to execute Worker pipelines within a given execution stage. This pipeline will be called once for each stage, then execute all Workers in parallel.",
"activities": [
{
"name": "Get Pipelines",
"description": "Returns all pipelines from the metadata to be executed within a given processing stage.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelinesInStage]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
}
},
"StageId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Pipelines",
"description": "Second level ForEach to run in parallel all pipelines within the stage. Items for iteration passed from the Get Pipelines lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Pipelines",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Pipelines').output.value",
"type": "Expression"
},
"isSequential": false,
"batchCount": 50,
"activities": [
{
"name": "Worker Pipeline Executor",
"description": "Run the required worker pipeline and wait for its completion. Update metadata once done.",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "04-Infant",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"executionId": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"stageId": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"pipelineId": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
}
}
]
}
}
],
"parameters": {
"StageId": {
"type": "int"
},
"ExecutionId": {
"type": "string"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"procfwk",
"Child"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/pipelines/04-Infant')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/04-Infant')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk infant pipeline used to check when the processing pipeline called by the Child completes and passes the resulting status back to the metadata database.",
"activities": [
{
"name": "Execute Worker Pipeline",
"description": "The lowest level executor with the metadata framework to call existing processing pipelines within Data Factory. The function called will block processing and wait for an outcome.",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Log Pipeline Running",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Pipeline Params",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"functionName": "ExecutePipeline",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n\t\"tenantId\": \"',variables('WorkerTenantId'),'\",\n\t\"applicationId\": \"',variables('WorkerAppId'),'\",\n\t\"authenticationKey\": \"',variables('WorkerAppSecret'),'\",\n\t\"subscriptionId\": \"',variables('WorkerSubscriptionId'),'\",\n\t\"resourceGroup\": \"',variables('WorkerResourceGroup'),'\",\n\t\"factoryName\": \"',variables('WorkerDataFactoryName'),'\",\n\t\"pipelineName\": \"',variables('WorkerPipelineName'),'\"',activity('Get Pipeline Params').output.firstRow.Params,'\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Pipeline Params",
"description": "Returns any parameters from metadata required for the processing pipeline being called. The output can be an empty string if no parameters are required.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelineParameters]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Pipeline Running",
"description": "Sets the current pipeline with a status of running within the current execution database table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Is Target Worker Validate",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Worker Authentication Details",
"description": "Return the SPN ID and Secret for the worker pipeline being executed. Called at this level as each pipeline can have a different SPN.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": true,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetWorkerAuthDetails]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
}
},
"PipelineId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
}
},
"StageId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Execute Function Activity Failure",
"description": "Handle true failures from calling out to the Azure Function and update the current execution table accordingly so a restart can occur.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Worker Pipeline",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
},
"CallingActivity": {
"value": "ExecuteWorkerPipeline",
"type": "String"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Update Run Id",
"description": "Provide the actual ADF run ID back to the current execution table for long term logging and alignment between the metadata other Azure monitoring tools.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Set Run Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunId]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@variables('WorkerRunId')",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check For Alerts",
"description": "Checks the properties tables and if any recipients in the database require alerts sending for the current pipeline ID.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Update Run Id",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Pipeline Result",
"dependencyConditions": [
"Completed"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[CheckForEmailAlerts]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": true
}
},
{
"name": "Send Alerts",
"description": "True = alerts need sending.\nFalse = do nothing.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Check For Alerts",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@activity('Check For Alerts').output.firstRow.SendAlerts",
"type": "Expression"
},
"ifTrueActivities": [
{
"name": "Get Email Parts",
"description": "Return all required content from the metadata database to send an email alerting using the procfwk. The lookup returns the exact content for the function body request.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": true,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetEmailAlertParts]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": true
}
},
{
"name": "Send Email",
"description": "Use an Azure Function to perform an SMTP client email send operation.",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Get Email Parts",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"functionName": "SendEmail",
"method": "POST",
"headers": {},
"body": {
"value": "@activity('Get Email Parts').output.firstRow",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Wait Until Pipeline Completes",
"description": "Loops until the Worker pipeline called completes.\n\nSimple status:\n- Running = new iteration.\n- Done = break.",
"type": "Until",
"dependsOn": [
{
"activity": "Get Wait Duration",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Execute Worker Pipeline",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Run Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@variables('WorkerPipelineState')",
"type": "Expression"
},
"activities": [
{
"name": "Get Worker Pipeline Status",
"description": "Checks the status of a given processing pipeline and provides the value for the downstream framework activities to act upon.",
"type": "AzureFunctionActivity",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"functionName": "CheckPipelineStatus",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',variables('WorkerTenantId'),'\",\n \"applicationId\": \"',variables('WorkerAppId'),'\",\n \"authenticationKey\": \"',variables('WorkerAppSecret'),'\",\n \"subscriptionId\": \"',variables('WorkerSubscriptionId'),'\",\n \"resourceGroup\": \"',variables('WorkerResourceGroup'),'\",\n \"factoryName\": \"',variables('WorkerDataFactoryName'),'\",\n \"pipelineName\": \"',variables('WorkerPipelineName'),'\",\n \"runId\": \"',variables('WorkerRunId'),'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Wait If Running",
"description": "True = Do nothing.\nFalse = Wait, before the next iteration.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Set Worker State",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@variables('WorkerPipelineState')",
"type": "Expression"
},
"ifFalseActivities": [
{
"name": "Wait for Pipeline",
"description": "The processing pipeline is still running so Wait before checking its status again.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@activity('Get Wait Duration').output.firstRow.PropertyValue",
"type": "Expression"
}
}
}
]
}
},
{
"name": "Set Last Check DateTime",
"description": "Update the current execution table with a date time from when the Worker pipeline status was last checked as part of the Until iterations.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Worker Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineLastStatusCheck]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Check Function Activity Failure",
"description": "Report to the current execution table that the framework pipeline activity has failed. This failure is outside of the scope of the framework and is probably related to a wider platform problem.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Worker Pipeline Status",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"CallingActivity": {
"value": "GetWorkerPipelineStatus",
"type": "String"
},
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Set Worker State",
"description": "Set the bool state of the Worker pipeline to be used by the Until and If expressions. True = Complete, False = Running.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Worker Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerPipelineState",
"value": {
"value": "@equals('Done',activity('Get Worker Pipeline Status').output.SimpleStatus)",
"type": "Expression"
}
}
}
],
"timeout": "0.00:10:00"
}
},
{
"name": "Set Pipeline Result",
"description": "Receives the outcome from the function execution for a given processing pipeline and updates the current execution table with different pipelines status values depending on the result (case).",
"type": "Switch",
"dependsOn": [
{
"activity": "Wait Until Pipeline Completes",
"dependencyConditions": [
"Completed"
]
}
],
"userProperties": [],
"typeProperties": {
"on": {
"value": "@activity('Get Worker Pipeline Status').output.Status",
"type": "Expression"
},
"cases": [
{
"value": "Succeeded",
"activities": [
{
"name": "Pipeline Status Succeeded",
"description": "Updates the current execution table with a pipeline status of success if the function outcome is succeeded.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineSuccess]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Failed",
"activities": [
{
"name": "Pipeline Status Failed",
"description": "Updates the current execution table with a pipeline status of failed if the function outcome is failed. Also blocks pipelines in the downstream execution stage.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@variables('WorkerRunId')",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Worker Pipeline Error Details",
"description": "Get the activity error details for the run ID of the worker pipeline called. Returns an array of all errors.",
"type": "AzureFunctionActivity",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"functionName": "GetActivityErrors",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',variables('WorkerTenantId'),'\",\n \"applicationId\": \"',variables('WorkerAppId'),'\",\n \"authenticationKey\": \"',variables('WorkerAppSecret'),'\",\n \"subscriptionId\": \"',variables('WorkerSubscriptionId'),'\",\n \"resourceGroup\": \"',variables('WorkerResourceGroup'),'\",\n \"factoryName\": \"',variables('WorkerDataFactoryName'),'\",\n \"pipelineName\": \"',variables('WorkerPipelineName'),'\",\n \"runId\": \"',variables('WorkerRunId'),'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Error Details",
"description": "Parses pipeline error details and persists them to the metadata database error log table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Worker Pipeline Error Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetErrorLogDetails]",
"storedProcedureParameters": {
"JsonErrorDetails": {
"value": {
"value": "@string(activity('Get Worker Pipeline Error Details').output)",
"type": "Expression"
},
"type": "String"
},
"LocalExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Cancelled",
"activities": [
{
"name": "Pipeline Status Cancelled",
"description": "Updates the current execution table with a pipeline status of cancelled if the function outcome is cancelled.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineCancelled]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
],
"defaultActivities": [
{
"name": "Pipeline Status Unknown",
"description": "Updates the current execution table with a pipeline status of unknown if the function returns an unexpected outcome.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineUnknown]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Get Wait Duration",
"description": "Return wait duration in seconds from database properties table to be used during each Until iteration when the Worker pipeline is still running.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "PipelineStatusCheckDuration"
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Set App Id",
"description": "Set local variable from activity output once for value reuse in downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Worker Authentication Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerAppId",
"value": {
"value": "@activity('Get Worker Authentication Details').output.firstRow.AppId",
"type": "Expression"
}
}
},
{
"name": "Set App Secret",
"description": "Set local variable from activity output once for value reuse in downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Worker Authentication Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerAppSecret",
"value": {
"value": "@activity('Get Worker Authentication Details').output.firstRow.AppSecret",
"type": "Expression"
}
}
},
{
"name": "Set Run Id",
"description": "Set local variable from activity output once for value reuse in downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Execute Worker Pipeline",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerRunId",
"value": {
"value": "@activity('Execute Worker Pipeline').output.RunId",
"type": "Expression"
}
}
},
{
"name": "Get Worker Pipeline Details",
"description": "Return none sensitive worker pipeline information for metadata database. Including target data factory, pipeline name and resource group.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": true,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetWorkerPipelineDetails]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
}
},
"PipelineId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
}
},
"StageId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Set Tenant Id",
"description": "Set local variable from activity output once for value reuse in downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Worker Authentication Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerTenantId",
"value": {
"value": "@activity('Get Worker Authentication Details').output.firstRow.TenantId",
"type": "Expression"
}
}
},
{
"name": "Set Subscription Id",
"description": "Set local variable from activity output once for value reuse in downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Worker Authentication Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerSubscriptionId",
"value": {
"value": "@activity('Get Worker Authentication Details').output.firstRow.SubscriptionId",
"type": "Expression"
}
}
},
{
"name": "Set Pipeline Name",
"description": "Set local variable from activity output once for value reuse in downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Worker Pipeline Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerPipelineName",
"value": {
"value": "@activity('Get Worker Pipeline Details').output.firstRow.PipelineName",
"type": "Expression"
}
}
},
{
"name": "Set Data Factory Name",
"description": "Set local variable from activity output once for value reuse in downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Worker Pipeline Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerDataFactoryName",
"value": {
"value": "@activity('Get Worker Pipeline Details').output.firstRow.DataFactoryName",
"type": "Expression"
}
}
},
{
"name": "Set Resource Group",
"description": "Set local variable from activity output once for value reuse in downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Worker Pipeline Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerResourceGroup",
"value": {
"value": "@activity('Get Worker Pipeline Details').output.firstRow.ResourceGroupName",
"type": "Expression"
}
}
},
{
"name": "Validate Pipeline",
"description": "Query the target data factory and establish if the provided worker pipeline name is valid.",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Set Resource Group",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Data Factory Name",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Subscription Id",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set App Secret",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set App Id",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Pipeline Name",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Tenant Id",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Log Pipeline Validating",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"functionName": "ValidatePipeline",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n\t\"tenantId\": \"',variables('WorkerTenantId'),'\",\n\t\"applicationId\": \"',variables('WorkerAppId'),'\",\n\t\"authenticationKey\": \"',variables('WorkerAppSecret'),'\",\n\t\"subscriptionId\": \"',variables('WorkerSubscriptionId'),'\",\n\t\"resourceGroup\": \"',variables('WorkerResourceGroup'),'\",\n\t\"factoryName\": \"',variables('WorkerDataFactoryName'),'\",\n\t\"pipelineName\": \"',variables('WorkerPipelineName'),'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Is Target Worker Validate",
"description": "True = the worker pipeline name is valid.\nFalse = the worker pipeline name is invalid. Raise an exception.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Validate Pipeline",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@bool(activity('Validate Pipeline').output.PipelineExists)",
"type": "Expression"
},
"ifFalseActivities": [
{
"name": "Throw Exception - Invalid Infant",
"description": "Throw an exception with details about the invalid worker pipeline name.",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "Throw Exception",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"Message": {
"value": "@concat('Worker pipeline [',variables('WorkerPipelineName'),'] is not valid in target Data Factory [',variables('WorkerDataFactoryName'),']')",
"type": "Expression"
}
}
}
},
{
"name": "Update Execution With Invalid Worker",
"description": "Update the current execution table with an informed status for the worker pipeline that couldn't be executed.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"CallingActivity": {
"value": "InvalidPipelineName",
"type": "String"
},
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Log Validate Function Activity Failure",
"description": "Handle true failures from calling out to the Azure Function and update the current execution table accordingly so a restart can occur.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Validate Pipeline",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
},
"CallingActivity": {
"value": "ValidatePipeline",
"type": "String"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Pipeline Validating",
"description": "Sets the current pipeline with a status of validating within the current execution database table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineValidating]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
],
"parameters": {
"executionId": {
"type": "string"
},
"stageId": {
"type": "int"
},
"pipelineId": {
"type": "int"
}
},
"variables": {
"WorkerPipelineState": {
"type": "Boolean"
},
"WorkerAppId": {
"type": "String"
},
"WorkerAppSecret": {
"type": "String"
},
"WorkerRunId": {
"type": "String"
},
"WorkerTenantId": {
"type": "String"
},
"WorkerSubscriptionId": {
"type": "String"
},
"WorkerPipelineName": {
"type": "String"
},
"WorkerDataFactoryName": {
"type": "String"
},
"WorkerResourceGroup": {
"type": "String"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"procfwk",
"Infant"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/FrameworkFunctions')]",
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]",
"[concat(variables('factoryId'), '/pipelines/Throw Exception')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Check For Running Pipeline')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "For a given pipeline and optional batch name establish if a pipeline run is already in progress. Throw an exception if it it.",
"activities": [
{
"name": "Get Subscription",
"description": "Use the Azure Management API to return the current subscription.",
"type": "WebActivity",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"url": "https://management.azure.com/subscriptions?api-version=2020-01-01",
"method": "GET",
"headers": {},
"authentication": {
"type": "MSI",
"resource": "https://management.core.windows.net/"
}
}
},
{
"name": "Get Pipeline Runs",
"description": "Use the Azure Management API to return a list of pipeline runs within the given time window.",
"type": "WebActivity",
"dependsOn": [
{
"activity": "Get Query Run Days Value",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Check for Valid Pipeline Name",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"url": {
"value": "https://management.azure.com/subscriptions/@{variables('SubscriptionId')}/resourceGroups/@{activity('Get Resource Group').output.firstRow.PropertyValue}/providers/Microsoft.DataFactory/factories/@{pipeline().DataFactory}/queryPipelineRuns?api-version=2018-06-01",
"type": "Expression"
},
"method": "POST",
"headers": {},
"body": {
"value": "{\n \"lastUpdatedAfter\": \"@{adddays(utcnow(),int(activity('Get Query Run Days Value').output.firstRow.PropertyValue))}\",\n \"lastUpdatedBefore\": \"@{utcnow()}\",\n \"filters\": [\n {\n \"operand\": \"PipelineName\",\n \"operator\": \"Equals\",\n \"values\": [\n \"@{pipeline().parameters.PipelineName}\"\n ]\n }\n ]\n}",
"type": "Expression"
},
"authentication": {
"type": "MSI",
"resource": "https://management.core.windows.net/"
}
}
},
{
"name": "Set Parsed Subscription",
"description": "Parse the subscription string value to return just the subscription ID.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Subscription",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "SubscriptionId",
"value": {
"value": "@replace(activity('Get Subscription').output.value[0].id,'/subscriptions/','')",
"type": "Expression"
}
}
},
{
"name": "Filter Running Pipelines",
"description": "Filter the pipeline runs results for pipelines that exclude the current triggered run and that are currently running (in progress or queued).",
"type": "Filter",
"dependsOn": [
{
"activity": "Get Pipeline Runs",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Pipeline Runs').output.value",
"type": "Expression"
},
"condition": {
"value": "@and(not(equals(item().runId,pipeline().parameters.ThisRunId)),or(equals(item().status,'InProgress'),equals(item().status,'Queued')))",
"type": "Expression"
}
}
},
{
"name": "Get Resource Group",
"description": "Using the metadata properties table return the framework factory resource group name.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "FrameworkFactoryResourceGroup"
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Get Query Run Days Value",
"description": "Using the metadata properties table return the run days value to provide the API request with a date range for pipeline executions.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "PreviousPipelineRunsQueryRange"
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "If Pipeline Is Running",
"description": "If the running pipeline count is greater than or equal to one.\nTrue = raise an exception.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "If Using Batch Executions",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@greaterOrEquals(int(variables('RunCount')),1)",
"type": "Expression"
},
"ifTrueActivities": [
{
"name": "Throw Exceptiion - Pipeline Running",
"description": "Using the utils pipeline raise an exception to stop the new trigger while a run is already in progress.",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "Throw Exception",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"Message": {
"value": "@concat('Provided pipeline name (',pipeline().parameters.PipelineName,') still has a run in progress or queued given the query range parameters set in the properties table.')",
"type": "Expression"
}
}
}
}
]
}
},
{
"name": "Get Execution Batch Status",
"description": "Using the metadata properties table return the flag to indicate if batch execution setting are enabled or disabled.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "UseExecutionBatches"
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "If Using Batch Executions",
"description": "True = batch executions are enabled.\nFalse = batch execution are disabled.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Get Execution Batch Status",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Filter Running Pipelines",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@equals(activity('Get Execution Batch Status').output.firstRow.PropertyValue,string(1))",
"type": "Expression"
},
"ifFalseActivities": [
{
"name": "Set Run Count Without Batch",
"description": "Set the pipelines running count variable to be tested later.",
"type": "SetVariable",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"variableName": "RunCount",
"value": {
"value": "@string(activity('Filter Running Pipelines').output.FilteredItemsCount)",
"type": "Expression"
}
}
}
],
"ifTrueActivities": [
{
"name": "Filter for Batch Name",
"description": "Further filter the return pipeline runs for any running pipelines with the same batch name value.",
"type": "Filter",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Filter Running Pipelines').output.value",
"type": "Expression"
},
"condition": {
"value": "@equals(item().parameters.BatchName,pipeline().parameters.BatchName)",
"type": "Expression"
}
}
},
{
"name": "Set Run Count for Batch",
"description": "Set the resulting pipeline running count variable to be tested later.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Filter for Batch Name",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "RunCount",
"value": {
"value": "@string(activity('Filter for Batch Name').output.FilteredItemsCount)",
"type": "Expression"
}
}
}
]
}
},
{
"name": "Check for Valid Pipeline Name",
"description": "Use the Azure Management API to return and establish if the framework pipeline exists in the target Data Factory, including being deployed.",
"type": "WebActivity",
"dependsOn": [
{
"activity": "Set Parsed Subscription",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Resource Group",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"url": {
"value": "https://management.azure.com/subscriptions/@{variables('SubscriptionId')}/resourceGroups/@{activity('Get Resource Group').output.firstRow.PropertyValue}/providers/Microsoft.DataFactory/factories/@{pipeline().DataFactory}/pipelines/@{pipeline().parameters.PipelineName}?api-version=2018-06-01",
"type": "Expression"
},
"method": "GET",
"headers": {},
"authentication": {
"type": "MSI",
"resource": "https://management.core.windows.net/"
}
}
}
],
"parameters": {
"BatchName": {
"type": "string",
"defaultValue": "NotUsed"
},
"PipelineName": {
"type": "string"
},
"ThisRunId": {
"type": "string"
}
},
"variables": {
"SubscriptionId": {
"type": "String"
},
"RunCount": {
"type": "String"
}
},
"folder": {
"name": "_ProcFwk/_ProcFwkUtils"
},
"annotations": [
"procfwk",
"Utils"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/pipelines/Throw Exception')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Email Sender')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Provide a simple abstract over the send email function with request body item exposed as pipeline parameters.",
"activities": [
{
"name": "Send Email",
"description": "Use an Azure Function to perform an SMTP client email send operation.",
"type": "AzureFunctionActivity",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "SendEmail",
"method": "POST",
"headers": {},
"body": {
"value": "{\n\"emailRecipients\": \"@{pipeline().parameters.Recipients}\",\n\"emailCcRecipients\": \"@{pipeline().parameters.CcRecipients}\",\n\"emailBccRecipients\": \"@{pipeline().parameters.BccRecipients}\",\n\"emailSubject\": \"@{pipeline().parameters.Subject}\",\n\"emailBody\": \"@{pipeline().parameters.Body}\",\n\"emailImportance\": \"@{pipeline().parameters.Importance}\"\n}",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
}
],
"parameters": {
"Recipients": {
"type": "string"
},
"CcRecipients": {
"type": "string"
},
"BccRecipients": {
"type": "string"
},
"Subject": {
"type": "string"
},
"Body": {
"type": "string"
},
"Importance": {
"type": "string"
}
},
"folder": {
"name": "_ProcFwk/_ProcFwkUtils"
},
"annotations": [
"procfwk",
"Utils"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/FrameworkFunctions')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Intentional Error')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait1",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
},
{
"name": "Raise Errors or Not",
"description": "Framework development worker simulator.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Wait1",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@equals(pipeline().parameters.RaiseErrors,'true')",
"type": "Expression"
},
"ifTrueActivities": [
{
"name": "Call Fail Procedure",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[dbo].[FailProcedure]",
"storedProcedureParameters": {
"RaiseError": {
"value": {
"value": "@pipeline().parameters.RaiseErrors",
"type": "Expression"
},
"type": "String"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
}
],
"parameters": {
"RaiseErrors": {
"type": "string",
"defaultValue": "false"
},
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Throw Exception')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Provide a simple way of throwing an exception within Data Factory using TSQL error handling.",
"activities": [
{
"name": "Raise Error",
"description": "Using a SQL database to raise an error/exception but wrapped up as a data factory pipeline. Error message information exposed as a pipeline parameter.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderQuery": {
"value": "RAISERROR('@{pipeline().parameters.Message}',16,1);",
"type": "Expression"
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
}
],
"parameters": {
"Message": {
"type": "string"
}
},
"folder": {
"name": "_ProcFwk/_ProcFwkUtils"
},
"annotations": [
"procfwk",
"Utils"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Wait 1')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait1",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 10')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait10",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 2')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait2",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 3')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait3",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 4')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait4",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 5')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait5",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 6')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait6",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 7')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait7",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 8')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait8",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 9')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the ADF.procfwk has something to call during development.",
"activities": [
{
"name": "Wait9",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 15
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"Worker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/GetSetMetadata')]",
"type": "Microsoft.DataFactory/factories/datasets",
"apiVersion": "2018-06-01",
"properties": {
"description": "Single generic dataset used to get and set all database metadata.",
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"ADF.procfwk"
],
"type": "AzureSqlTable",
"schema": [],
"typeProperties": {}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/FrameworkFunctions')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Interact with the Azure Functions App used as middle ware when making requests to Worker pipelines. Authentication done at the Function App level.",
"annotations": [
"ADF.procfwk"
],
"type": "AzureFunction",
"typeProperties": {
"functionAppUrl": "[parameters('FrameworkFunctions_properties_typeProperties_functionAppUrl')]",
"functionKey": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "FrameworkFunctionsKey"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Keys')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Connection to Key Vault for all other ADF linked service credentials required to run the processing framework.",
"annotations": [
"ADF.procfwk"
],
"type": "AzureKeyVault",
"typeProperties": {
"baseUrl": "[parameters('Keys_properties_typeProperties_baseUrl')]"
}
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/SupportDatabase')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Connection between ADF and processing framework metadata SQLDB.",
"annotations": [
"ADF.procfwk"
],
"type": "AzureSqlDatabase",
"typeProperties": {
"connectionString": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "[parameters('SupportDatabase_properties_typeProperties_connectionString_secretName')]"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/FunctionalTestingTrigger')]",
"type": "Microsoft.DataFactory/factories/triggers",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used for functional testing of the framework in a dedicated environment.",
"annotations": [
"ADF.procfwk"
],
"runtimeState": "Stopped",
"pipelines": [
{
"pipelineReference": {
"referenceName": "01-Grandparent",
"type": "PipelineReference"
},
"parameters": {}
}
],
"type": "ScheduleTrigger",
"typeProperties": {
"recurrence": {
"frequency": "Hour",
"interval": 2,
"startTime": "2020-04-06T15:00:00Z",
"timeZone": "UTC"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/pipelines/01-Grandparent')]"
]
}
]
}
================================================
FILE: ARM Templates/Data Factory/v2.0 Export.json
================================================
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"factoryName": {
"type": "string",
"metadata": "Data Factory name",
"defaultValue": ""
},
"FrameworkFunctions_properties_typeProperties_functionAppUrl": {
"type": "string",
"defaultValue": ""
},
"Keys_properties_typeProperties_baseUrl": {
"type": "string",
"defaultValue": ""
},
"SupportDatabase_properties_typeProperties_connectionString_secretName": {
"type": "string",
"defaultValue": ""
}
},
"variables": {
"factoryId": "[concat('Microsoft.DataFactory/factories/', parameters('factoryName'))]"
},
"resources": [
{
"name": "[concat(parameters('factoryName'), '/01-Grandparent')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "procfwk grandparent pipeline used optionally to bootstrap any wider processes in your Data Factory that then calls the processing framework.",
"activities": [
{
"name": "procfwk",
"description": "Call procfwk",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "02-Parent",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"BatchName": {
"value": "@pipeline().parameters.BatchName",
"type": "Expression"
}
}
}
}
],
"parameters": {
"BatchName": {
"type": "string",
"defaultValue": "NotUsed"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"procfwk",
"Grandparent"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/pipelines/02-Parent')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/02-Parent')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "ADF.procfwk parent pipeline used to bootstrap the orchestration framework in perform the first level ForEach calls in sequence for the metadata stages.",
"activities": [
{
"name": "Get Stages",
"description": "Returns a distinct list of execution stages within the framework metadata.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Set Execution Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetStages]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@variables('ExecutionId')",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Stages",
"description": "Top level ForEach to sequentially call all processing stages within the framework metadata. Items for iteration passed from the Get Stages lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Stages",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Stages').output.value",
"type": "Expression"
},
"isSequential": true,
"activities": [
{
"name": "Stage Executor",
"description": "Call to the framework generic child pipeline for a given execution stage.",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Log Stage Preparing",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "03-Child",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"StageId": {
"value": "@item().StageId",
"type": "Expression"
},
"ExecutionId": {
"value": "@variables('ExecutionId')",
"type": "Expression"
}
}
}
},
{
"name": "Log Stage Preparing",
"description": "Update the current execution table flagging all pipelines within the stage as preparing.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Check and Update Blockers",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogStagePreparing]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@variables('ExecutionId')",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check and Update Blockers",
"description": "Used to double check and stop the next execution stage if failures and blockers have be incurred. This also depends on the failure handling property value which defines the stored procedure behaviour.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[CheckForBlockedPipelines]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@variables('ExecutionId')",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Execution Wrapper",
"description": "Wrapper to reset and restart processing or create a completely new execution instance of the framework metadata.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Clean Up Previous Run",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[ExecutionWrapper]",
"storedProcedureParameters": {
"CallingOrchestratorName": {
"type": "String",
"value": {
"value": "@pipeline().DataFactory",
"type": "Expression"
}
},
"BatchName": {
"type": "String",
"value": {
"value": "@pipeline().parameters.BatchName",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Check Outcome and Update Logs",
"description": "After a successful execution run the current execution metadata is moved to the long term logging table by this stored procedure call. Otherwise an error will be raised.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Stages",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[UpdateExecutionLog]",
"storedProcedureParameters": {
"PerformErrorCheck": {
"value": {
"value": "@bool(1)",
"type": "Expression"
},
"type": "Boolean"
},
"ExecutionId": {
"value": {
"value": "@variables('ExecutionId')",
"type": "Expression"
},
"type": "Guid"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check Previous Execution",
"description": "Query the current execution table for worker pipelines that require a clean up from the previous execution run.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Execute Precursor",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[CheckPreviousExeuction]",
"storedProcedureParameters": {
"BatchName": {
"type": "String",
"value": {
"value": "@pipeline().parameters.BatchName",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Clean Up Previous Run",
"description": "Handle Worker pipelines that are reported as Running when the parent pipeline is called again. Get what the actual status of those pipelines is.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Check Previous Execution",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Check Metadata Integrity",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Check Previous Execution').output.value",
"type": "Expression"
},
"isSequential": false,
"batchCount": 50,
"activities": [
{
"name": "Get SPN Details",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": true,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetWorkerAuthDetails]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
}
},
"PipelineId": {
"type": "Int32",
"value": {
"value": "@item().PipelineId",
"type": "Expression"
}
},
"StageId": {
"type": "Int32",
"value": {
"value": "@item().StageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Pipeline Checking",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineChecking]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Pipeline Status",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Get SPN Details",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Log Pipeline Checking",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"functionName": "CheckPipelineStatus",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',activity('Get SPN Details').output.firstRow.TenantId,'\",\n \"applicationId\": \"',activity('Get SPN Details').output.firstRow.AppId,'\",\n \"authenticationKey\": \"',activity('Get SPN Details').output.firstRow.AppSecret,'\",\n \"subscriptionId\": \"',activity('Get SPN Details').output.firstRow.SubscriptionId,'\",\n \"resourceGroupName\": \"',item().ResourceGroupName,'\",\n \"orchestratorName\": \"',item().OrchestratorName,'\",\n \"orchestratorType\": \"',item().OrchestratorType,'\",\n \"pipelineName\": \"',item().PipelineName,'\",\n \"runId\": \"',item().PipelineRunId,'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Set Pipeline Status",
"description": "Update the metadata depending on the actual pipeline outcome. Using the status as the case.",
"type": "Switch",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"on": {
"value": "@activity('Get Pipeline Status').output.ActualStatus",
"type": "Expression"
},
"cases": [
{
"value": "Failed",
"activities": [
{
"name": "Pipeline Status Failed",
"description": "Updates the current execution table with a pipeline status of failed if the function outcome is failed. Also blocks pipelines in the downstream execution stage.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": null,
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Succeeded",
"activities": [
{
"name": "Pipeline Status Succeeded",
"description": "Updates the current execution table with a pipeline status of success if the function outcome is succeeded.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineSuccess]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Queued",
"activities": [
{
"name": "Pipeline Status Queued - Running",
"description": "Updates the current execution table with a pipeline status of running if the function outcome is queued.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "InProgress",
"activities": [
{
"name": "Pipeline Status InProgress - Running",
"description": "Updates the current execution table with a pipeline status of running if the function outcome is in progress.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Cancelled",
"activities": [
{
"name": "Pipeline Status Cancelled",
"description": "Updates the current execution table with a pipeline status of cancelled if the function outcome is cancelled.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineCancelled]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
},
"CleanUpRun": {
"value": {
"value": "@bool(1)",
"type": "Expression"
},
"type": "Boolean"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
],
"defaultActivities": [
{
"name": "Pipeline Status Unknown",
"description": "Updates the current execution table with a pipeline status of unknown if the function returns an unexpected outcome.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineUnknown]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
},
"CleanUpRun": {
"value": {
"value": "@bool(1)",
"type": "Expression"
},
"type": "Boolean"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Set Last Check DateTime",
"description": "Update the current execution table with a date time from when the function last checked the pipeline status.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineLastStatusCheck]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Execute Precursor",
"description": "Uses the database property value ExecutionPrecursorProc to run any custom logic against the metadata database before the execution run starts.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Is Parent Already Running",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[ExecutePrecursorProcedure]"
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Set Execution Id",
"description": "Set the local execution Id to a pipeline variable for each in several downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Execution Wrapper",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "ExecutionId",
"value": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
}
}
},
{
"name": "Is Parent Already Running",
"description": "Establish before anything else if the parent pipeline is already running. Batch execution aware.",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "Check For Running Pipeline",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"BatchName": {
"value": "@pipeline().parameters.BatchName",
"type": "Expression"
},
"PipelineName": {
"value": "@pipeline().Pipeline",
"type": "Expression"
},
"ThisRunId": {
"value": "@pipeline().RunId",
"type": "Expression"
}
}
}
},
{
"name": "Check Metadata Integrity",
"description": "Performs a series of checks on all metadata held in the framework SQLDB. This is intended to raise errors before an execution run even starts.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Precursor",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[CheckMetadataIntegrity]",
"storedProcedureParameters": {
"BatchName": {
"value": {
"value": "@pipeline().parameters.BatchName",
"type": "Expression"
},
"type": "String"
},
"DebugMode": {
"value": {
"value": "@bool(0)",
"type": "Expression"
},
"type": "Boolean"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
],
"parameters": {
"BatchName": {
"type": "string",
"defaultValue": "NotUsed"
}
},
"variables": {
"ExecutionId": {
"type": "String"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"procfwk",
"Parent"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]",
"[concat(variables('factoryId'), '/pipelines/Check For Running Pipeline')]",
"[concat(variables('factoryId'), '/pipelines/03-Child')]",
"[concat(variables('factoryId'), '/linkedServices/FrameworkFunctions')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/03-Child')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "procfwk child pipeline used to execute Worker pipelines within a given execution stage. This pipeline will be called once for each stage, then execute all Workers in parallel.",
"activities": [
{
"name": "Get Pipelines",
"description": "Returns all pipelines from the metadata to be executed within a given processing stage.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelinesInStage]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
}
},
"StageId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Pipelines",
"description": "Second level ForEach to run in parallel all pipelines within the stage. Items for iteration passed from the Get Pipelines lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Pipelines",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Pipelines').output.value",
"type": "Expression"
},
"isSequential": false,
"batchCount": 50,
"activities": [
{
"name": "Worker Pipeline Executor",
"description": "Run the required worker pipeline and wait for its completion. Update metadata once done.",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "04-Infant",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"executionId": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"stageId": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"pipelineId": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
}
}
]
}
}
],
"parameters": {
"StageId": {
"type": "int"
},
"ExecutionId": {
"type": "string"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"procfwk",
"Child"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/pipelines/04-Infant')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/04-Infant')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "procfwk infant pipeline used to check when the processing pipeline called by the Child completes and passes the resulting status back to the metadata database.",
"activities": [
{
"name": "Execute Worker Pipeline",
"description": "The lowest level executor with the metadata framework to call existing processing pipelines within Data Factory. The function called will block processing and wait for an outcome.",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Log Pipeline Running",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Pipeline Params",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"functionName": "ExecutePipeline",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',variables('WorkerCoreDetails')[0].tenantId,'\",\n \"applicationId\": \"',variables('WorkerCoreDetails')[0].applicationId,'\",\n \"authenticationKey\": \"',variables('WorkerCoreDetails')[0].authenticationKey,'\",\n \"subscriptionId\": \"',variables('WorkerCoreDetails')[0].subscriptionId,'\",\n \"resourceGroupName\": \"',variables('WorkerCoreDetails')[0].resourceGroupName,'\",\n\t\"orchestratorName\": \"',variables('WorkerCoreDetails')[0].orchestratorName,'\",\n \"orchestratorType\": \"',variables('WorkerCoreDetails')[0].orchestratorType,'\",\n \"pipelineName\": \"',variables('WorkerCoreDetails')[0].pipelineName,'\"',activity('Get Pipeline Params').output.firstRow.Params,'\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Pipeline Params",
"description": "Returns any parameters from metadata required for the processing pipeline being called. The output can be an empty string if no parameters are required.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelineParameters]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Pipeline Running",
"description": "Sets the current pipeline with a status of running within the current execution database table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Is Target Worker Validate",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Execute Function Activity Failure",
"description": "Handle true failures from calling out to the Azure Function and update the current execution table accordingly so a restart can occur.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Worker Pipeline",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
},
"CallingActivity": {
"value": "ExecuteWorkerPipeline",
"type": "String"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Update Run Id",
"description": "Provide the actual ADF run ID back to the current execution table for long term logging and alignment between the metadata other Azure monitoring tools.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Set Run Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunId]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@variables('WorkerRunId')",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check For Alerts",
"description": "Checks the properties tables and if any recipients in the database require alerts sending for the current pipeline ID.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Update Run Id",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Pipeline Result",
"dependencyConditions": [
"Completed"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[CheckForEmailAlerts]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": true
}
},
{
"name": "Send Alerts",
"description": "True = alerts need sending.\nFalse = do nothing.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Check For Alerts",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@activity('Check For Alerts').output.firstRow.SendAlerts",
"type": "Expression"
},
"ifTrueActivities": [
{
"name": "Get Email Parts",
"description": "Return all required content from the metadata database to send an email alerting using the procfwk. The lookup returns the exact content for the function body request.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": true,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetEmailAlertParts]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": true
}
},
{
"name": "Call Email Sender",
"description": "Pass off email request to Utils Send Email pipeline.",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Get Email Parts",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "Email Sender",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"Recipients": {
"value": "@activity('Get Email Parts').output.firstRow.emailRecipients",
"type": "Expression"
},
"CcRecipients": {
"value": "@activity('Get Email Parts').output.firstRow.emailCcRecipients",
"type": "Expression"
},
"BccRecipients": {
"value": "@activity('Get Email Parts').output.firstRow.emailBccRecipients",
"type": "Expression"
},
"Subject": {
"value": "@activity('Get Email Parts').output.firstRow.emailSubject",
"type": "Expression"
},
"Body": {
"value": "@activity('Get Email Parts').output.firstRow.emailBody",
"type": "Expression"
},
"Importance": {
"value": "@activity('Get Email Parts').output.firstRow.emailImportance",
"type": "Expression"
}
}
}
}
]
}
},
{
"name": "Wait Until Pipeline Completes",
"description": "Loops until the Worker pipeline called completes.\n\nSimple status:\n- Running = new iteration.\n- Done = break.",
"type": "Until",
"dependsOn": [
{
"activity": "Get Wait Duration",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Execute Worker Pipeline",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Run Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@variables('WorkerPipelineState')",
"type": "Expression"
},
"activities": [
{
"name": "Get Worker Pipeline Status",
"description": "Checks the status of a given processing pipeline and provides the value for the downstream framework activities to act upon.",
"type": "AzureFunctionActivity",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"functionName": "CheckPipelineStatus",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',variables('WorkerCoreDetails')[0].tenantId,'\",\n \"applicationId\": \"',variables('WorkerCoreDetails')[0].applicationId,'\",\n \"authenticationKey\": \"',variables('WorkerCoreDetails')[0].authenticationKey,'\",\n \"subscriptionId\": \"',variables('WorkerCoreDetails')[0].subscriptionId,'\",\n \"resourceGroupName\": \"',variables('WorkerCoreDetails')[0].resourceGroupName,'\",\n\t\"orchestratorName\": \"',variables('WorkerCoreDetails')[0].orchestratorName,'\",\n \"orchestratorType\": \"',variables('WorkerCoreDetails')[0].orchestratorType,'\",\n \"pipelineName\": \"',variables('WorkerCoreDetails')[0].pipelineName,'\",\n \"runId\": \"',variables('WorkerRunId'),'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Wait If Running",
"description": "True = Do nothing.\nFalse = Wait, before the next iteration.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Set Worker State",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@variables('WorkerPipelineState')",
"type": "Expression"
},
"ifFalseActivities": [
{
"name": "Wait for Pipeline",
"description": "The processing pipeline is still running so Wait before checking its status again.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@activity('Get Wait Duration').output.firstRow.PropertyValue",
"type": "Expression"
}
}
}
]
}
},
{
"name": "Set Last Check DateTime",
"description": "Update the current execution table with a date time from when the Worker pipeline status was last checked as part of the Until iterations.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Worker Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineLastStatusCheck]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Check Function Activity Failure",
"description": "Report to the current execution table that the framework pipeline activity has failed. This failure is outside of the scope of the framework and is probably related to a wider platform problem.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Worker Pipeline Status",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"CallingActivity": {
"value": "GetWorkerPipelineStatus",
"type": "String"
},
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Set Worker State",
"description": "Set the bool state of the Worker pipeline to be used by the Until and If expressions. True = Complete, False = Running.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Worker Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerPipelineState",
"value": {
"value": "@equals('Complete',activity('Get Worker Pipeline Status').output.SimpleStatus)",
"type": "Expression"
}
}
}
],
"timeout": "0.00:10:00"
}
},
{
"name": "Set Pipeline Result",
"description": "Receives the outcome from the function execution for a given processing pipeline and updates the current execution table with different pipelines status values depending on the result (case).",
"type": "Switch",
"dependsOn": [
{
"activity": "Wait Until Pipeline Completes",
"dependencyConditions": [
"Completed"
]
}
],
"userProperties": [],
"typeProperties": {
"on": {
"value": "@activity('Get Worker Pipeline Status').output.ActualStatus",
"type": "Expression"
},
"cases": [
{
"value": "Succeeded",
"activities": [
{
"name": "Pipeline Status Succeeded",
"description": "Updates the current execution table with a pipeline status of success if the function outcome is succeeded.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineSuccess]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Failed",
"activities": [
{
"name": "Pipeline Status Failed",
"description": "Updates the current execution table with a pipeline status of failed if the function outcome is failed. Also blocks pipelines in the downstream execution stage.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@variables('WorkerRunId')",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Worker Pipeline Error Details",
"description": "Get the activity error details for the run ID of the worker pipeline called. Returns an array of all errors.",
"type": "AzureFunctionActivity",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"functionName": "GetActivityErrors",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',variables('WorkerCoreDetails')[0].tenantId,'\",\n \"applicationId\": \"',variables('WorkerCoreDetails')[0].applicationId,'\",\n \"authenticationKey\": \"',variables('WorkerCoreDetails')[0].authenticationKey,'\",\n \"subscriptionId\": \"',variables('WorkerCoreDetails')[0].subscriptionId,'\",\n \"resourceGroupName\": \"',variables('WorkerCoreDetails')[0].resourceGroupName,'\",\n\t\"orchestratorName\": \"',variables('WorkerCoreDetails')[0].orchestratorName,'\",\n \"orchestratorType\": \"',variables('WorkerCoreDetails')[0].orchestratorType,'\",\n \"pipelineName\": \"',variables('WorkerCoreDetails')[0].pipelineName,'\",\n \"runId\": \"',variables('WorkerRunId'),'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Error Details",
"description": "Parses pipeline error details and persists them to the metadata database error log table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Worker Pipeline Error Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetErrorLogDetails]",
"storedProcedureParameters": {
"JsonErrorDetails": {
"value": {
"value": "@string(activity('Get Worker Pipeline Error Details').output)",
"type": "Expression"
},
"type": "String"
},
"LocalExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Cancelled",
"activities": [
{
"name": "Pipeline Status Cancelled",
"description": "Updates the current execution table with a pipeline status of cancelled if the function outcome is cancelled.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineCancelled]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
],
"defaultActivities": [
{
"name": "Pipeline Status Unknown",
"description": "Updates the current execution table with a pipeline status of unknown if the function returns an unexpected outcome.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineUnknown]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Get Wait Duration",
"description": "Return wait duration in seconds from database properties table to be used during each Until iteration when the Worker pipeline is still running.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "PipelineStatusCheckDuration"
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Set Run Id",
"description": "Set local variable from activity output once for value reuse in downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Execute Worker Pipeline",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerRunId",
"value": {
"value": "@activity('Execute Worker Pipeline').output.RunId",
"type": "Expression"
}
}
},
{
"name": "Validate Pipeline",
"description": "Query the target data factory and establish if the provided worker pipeline name is valid.",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Log Pipeline Validating",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Capture Worker Core Details as an Array",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"functionName": "ValidatePipeline",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',variables('WorkerCoreDetails')[0].tenantId,'\",\n \"applicationId\": \"',variables('WorkerCoreDetails')[0].applicationId,'\",\n \"authenticationKey\": \"',variables('WorkerCoreDetails')[0].authenticationKey,'\",\n \"subscriptionId\": \"',variables('WorkerCoreDetails')[0].subscriptionId,'\",\n \"resourceGroupName\": \"',variables('WorkerCoreDetails')[0].resourceGroupName,'\",\n\t\"orchestratorName\": \"',variables('WorkerCoreDetails')[0].orchestratorName,'\",\n \"orchestratorType\": \"',variables('WorkerCoreDetails')[0].orchestratorType,'\",\n \"pipelineName\": \"',variables('WorkerCoreDetails')[0].pipelineName,'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Is Target Worker Validate",
"description": "True = the worker pipeline name is valid.\nFalse = the worker pipeline name is invalid. Raise an exception.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Validate Pipeline",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@bool(activity('Validate Pipeline').output.PipelineExists)",
"type": "Expression"
},
"ifFalseActivities": [
{
"name": "Throw Exception - Invalid Infant",
"description": "Throw an exception with details about the invalid worker pipeline name.",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "Throw Exception",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"Message": {
"value": "@concat('Worker pipeline [',variables('WorkerCoreDetails')[0].pipelineName,'] is not valid in target Orchestrator [',variables('WorkerCoreDetails')[0].orchestratorName,']')",
"type": "Expression"
}
}
}
},
{
"name": "Update Execution With Invalid Worker",
"description": "Update the current execution table with an informed status for the worker pipeline that couldn't be executed.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"CallingActivity": {
"value": "InvalidPipelineName",
"type": "String"
},
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Log Validate Function Activity Failure",
"description": "Handle true failures from calling out to the Azure Function and update the current execution table accordingly so a restart can occur.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Validate Pipeline",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
},
"CallingActivity": {
"value": "ValidatePipeline",
"type": "String"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Pipeline Validating",
"description": "Sets the current pipeline with a status of validating within the current execution database table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineValidating]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Worker Core Details",
"description": "Return worker pipeline information for metadata database. Including target data factory, pipeline name and resource group. Return the SPN ID and Secret for the worker pipeline being executed. Called at this level as each pipeline can have a different SPN.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": true,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetWorkerDetailsWrapper]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
}
},
"PipelineId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
}
},
"StageId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Capture Worker Core Details as an Array",
"description": "Add all worker pipeline details to a local variable array that can be accessed by each function call requiring the values.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Worker Core Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerCoreDetails",
"value": {
"value": "@array(activity('Get Worker Core Details').output.firstRow)",
"type": "Expression"
}
}
}
],
"parameters": {
"executionId": {
"type": "string"
},
"stageId": {
"type": "int"
},
"pipelineId": {
"type": "int"
}
},
"variables": {
"WorkerPipelineState": {
"type": "Boolean"
},
"WorkerRunId": {
"type": "String"
},
"WorkerCoreDetails": {
"type": "Array"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"procfwk",
"Infant"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/FrameworkFunctions')]",
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]",
"[concat(variables('factoryId'), '/pipelines/Email Sender')]",
"[concat(variables('factoryId'), '/pipelines/Throw Exception')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Check For Running Pipeline')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "For a given pipeline and optional batch name establish if a pipeline run is already in progress. Throw an exception if it it.",
"activities": [
{
"name": "Filter Running Pipelines",
"description": "Filter the pipeline runs results for pipelines that exclude the current triggered run and that are currently running (in progress or queued).",
"type": "Filter",
"dependsOn": [
{
"activity": "Switch For Orchestrator Type",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@variables('PipelineRuns')",
"type": "Expression"
},
"condition": {
"value": "@and(not(equals(item().runId,pipeline().parameters.ThisRunId)),or(equals(item().status,'InProgress'),equals(item().status,'Queued')))",
"type": "Expression"
}
}
},
{
"name": "Get Framework Orchestrator Details",
"description": "Using the metadata orchestrators return details about the resource running the framework pipelines.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetFrameworkOrchestratorDetails]",
"storedProcedureParameters": {
"CallingOrchestratorName": {
"type": "String",
"value": {
"value": "@pipeline().DataFactory",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Get Query Run Days Value",
"description": "Using the metadata properties table return the run days value to provide the API request with a date range for pipeline executions.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "PreviousPipelineRunsQueryRange"
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "If Pipeline Is Running",
"description": "If the running pipeline count is greater than or equal to one.\nTrue = raise an exception.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "If Using Batch Executions",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@greaterOrEquals(int(variables('RunCount')),1)",
"type": "Expression"
},
"ifTrueActivities": [
{
"name": "Throw Exception - Pipeline Running",
"description": "Using the utils pipeline raise an exception to stop the new trigger while a run is already in progress.",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "Throw Exception",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"Message": {
"value": "@concat('Provided pipeline name (',pipeline().parameters.PipelineName,') still has a run in progress or queued given the query range parameters set in the properties table.')",
"type": "Expression"
}
}
}
}
]
}
},
{
"name": "Get Execution Batch Status",
"description": "Using the metadata properties table return the flag to indicate if batch execution setting are enabled or disabled.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "UseExecutionBatches"
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "If Using Batch Executions",
"description": "True = batch executions are enabled.\nFalse = batch execution are disabled.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Get Execution Batch Status",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Filter Running Pipelines",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@equals(activity('Get Execution Batch Status').output.firstRow.PropertyValue,string(1))",
"type": "Expression"
},
"ifFalseActivities": [
{
"name": "Set Run Count Without Batch",
"description": "Set the pipelines running count variable to be tested later.",
"type": "SetVariable",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"variableName": "RunCount",
"value": {
"value": "@string(activity('Filter Running Pipelines').output.FilteredItemsCount)",
"type": "Expression"
}
}
}
],
"ifTrueActivities": [
{
"name": "Filter for Batch Name",
"description": "Further filter the return pipeline runs for any running pipelines with the same batch name value.",
"type": "Filter",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Filter Running Pipelines').output.value",
"type": "Expression"
},
"condition": {
"value": "@equals(item().parameters.BatchName,pipeline().parameters.BatchName)",
"type": "Expression"
}
}
},
{
"name": "Set Run Count for Batch",
"description": "Set the resulting pipeline running count variable to be tested later.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Filter for Batch Name",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "RunCount",
"value": {
"value": "@string(activity('Filter for Batch Name').output.FilteredItemsCount)",
"type": "Expression"
}
}
}
]
}
},
{
"name": "Set Subscription Id",
"description": "Set the subscription Id value to a local variable for use in various downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Framework Orchestrator Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "SubscriptionId",
"value": {
"value": "@activity('Get Framework Orchestrator Details').output.firstRow.SubscriptionId",
"type": "Expression"
}
}
},
{
"name": "Set Resource Group Name",
"description": "Set the resource group name value to a local variable for use in various downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Framework Orchestrator Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "ResourceGroupName",
"value": {
"value": "@activity('Get Framework Orchestrator Details').output.firstRow.ResourceGroupName",
"type": "Expression"
}
}
},
{
"name": "Set Orchestrator Type",
"description": "Set the orchestrator type value to a local variable for use in various downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Framework Orchestrator Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "OrchestratorType",
"value": {
"value": "@toUpper(activity('Get Framework Orchestrator Details').output.firstRow.OrchestratorType)",
"type": "Expression"
}
}
},
{
"name": "Switch For Orchestrator Type",
"description": "Switch and handle requests for both Azure Data Factory (ADF) and Azure Synapse Analytics (SYN).",
"type": "Switch",
"dependsOn": [
{
"activity": "Set Orchestrator Type",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Query Run Days",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Resource Group Name",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Subscription Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"on": {
"value": "@variables('OrchestratorType')",
"type": "Expression"
},
"cases": [
{
"value": "ADF",
"activities": [
{
"name": "Check for Valid ADF Pipeline Name",
"description": "Use the Azure Management API to return and establish if the framework pipeline exists in the target Data Factory instance, including being deployed.",
"type": "WebActivity",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"url": {
"value": "https://management.azure.com/subscriptions/@{variables('SubscriptionId')}/resourceGroups/@{variables('ResourceGroupName')}/providers/Microsoft.DataFactory/factories/@{pipeline().DataFactory}/pipelines/@{pipeline().parameters.PipelineName}?api-version=2018-06-01",
"type": "Expression"
},
"method": "GET",
"headers": {},
"authentication": {
"type": "MSI",
"resource": "https://management.core.windows.net/"
}
}
},
{
"name": "Get ADF Pipeline Runs",
"description": "Use the Azure Management API to return a list of data factory pipeline runs within the given time window.",
"type": "WebActivity",
"dependsOn": [
{
"activity": "Check for Valid ADF Pipeline Name",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"url": {
"value": "https://management.azure.com/subscriptions/@{variables('SubscriptionId')}/resourceGroups/@{variables('ResourceGroupName')}/providers/Microsoft.DataFactory/factories/@{pipeline().DataFactory}/queryPipelineRuns?api-version=2018-06-01",
"type": "Expression"
},
"method": "POST",
"headers": {},
"body": {
"value": "{\n \"lastUpdatedAfter\": \"@{adddays(utcnow(),int(variables('QueryRunDays')))}\",\n \"lastUpdatedBefore\": \"@{utcnow()}\",\n \"filters\": [\n {\n \"operand\": \"PipelineName\",\n \"operator\": \"Equals\",\n \"values\": [\n \"@{pipeline().parameters.PipelineName}\"\n ]\n }\n ]\n}",
"type": "Expression"
},
"authentication": {
"type": "MSI",
"resource": "https://management.core.windows.net/"
}
}
},
{
"name": "Set ADF Runs Output",
"description": "Set output to local array for use in downstream filtering and pipeline checks. Use the same array output for both switch cases.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get ADF Pipeline Runs",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "PipelineRuns",
"value": {
"value": "@activity('Get ADF Pipeline Runs').output.value",
"type": "Expression"
}
}
}
]
},
{
"value": "SYN",
"activities": [
{
"name": "Check for Valid SYN Pipeline Name",
"description": "Use the Azure Management API to return and establish if the framework pipeline exists in the target Synapse instance, including being deployed.\n\nSee: https://docs.microsoft.com/en-us/rest/api/synapse/data-plane/pipeline/getpipeline",
"type": "WebActivity",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"url": {
"value": "https://@{pipeline().DataFactory}.dev.azuresynapse.net/pipelines/@{pipeline().parameters.PipelineName}?api-version=2019-06-01-preview",
"type": "Expression"
},
"method": "GET",
"headers": {},
"authentication": {
"type": "MSI",
"resource": "https://management.core.windows.net/"
}
}
},
{
"name": "Get SYN Pipeline Runs",
"description": "Use the Azure Management API to return a list of synapse pipeline runs within the given time window.\n\nSee: https://docs.microsoft.com/en-us/rest/api/synapse/data-plane/pipelinerun/querypipelinerunsbyworkspace",
"type": "WebActivity",
"dependsOn": [
{
"activity": "Check for Valid SYN Pipeline Name",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"url": {
"value": "https://@{pipeline().DataFactory}.dev.azuresynapse.net/queryPipelineRuns?api-version=2019-06-01-preview",
"type": "Expression"
},
"method": "POST",
"headers": {},
"body": {
"value": "{\n \"lastUpdatedAfter\": \"@{adddays(utcnow(),int(variables('QueryRunDays')))}\",\n \"lastUpdatedBefore\": \"@{utcnow()}\",\n \"filters\": [\n {\n \"operand\": \"PipelineName\",\n \"operator\": \"Equals\",\n \"values\": [\n \"@{pipeline().parameters.PipelineName}\"\n ]\n }\n ]\n}",
"type": "Expression"
},
"authentication": {
"type": "MSI",
"resource": "https://management.core.windows.net/"
}
}
},
{
"name": "Set SYN Runs Output",
"description": "Set output to local array for use in downstream filtering and pipeline checks. Use the same array output for both switch cases.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get SYN Pipeline Runs",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "PipelineRuns",
"value": {
"value": "@activity('Get SYN Pipeline Runs').output.value",
"type": "Expression"
}
}
}
]
}
],
"defaultActivities": [
{
"name": "Throw Exception Invalid Orchestrator Type",
"description": "Throw exception if switch cases are not met.",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "Throw Exception",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"Message": "Invalid orchestrator type provided. Unable to check pipeline running state."
}
}
}
]
}
},
{
"name": "Set Query Run Days",
"description": "Set the query run days value to a local variable for use in various downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Query Run Days Value",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "QueryRunDays",
"value": {
"value": "@activity('Get Query Run Days Value').output.firstRow.PropertyValue",
"type": "Expression"
}
}
}
],
"parameters": {
"BatchName": {
"type": "string",
"defaultValue": "NotUsed"
},
"PipelineName": {
"type": "string"
},
"ThisRunId": {
"type": "string"
}
},
"variables": {
"SubscriptionId": {
"type": "String"
},
"RunCount": {
"type": "String"
},
"ResourceGroupName": {
"type": "String"
},
"OrchestratorType": {
"type": "String"
},
"QueryRunDays": {
"type": "String"
},
"PipelineRuns": {
"type": "Array"
}
},
"folder": {
"name": "_ProcFwk/_ProcFwkUtils"
},
"annotations": [
"procfwk",
"Utils"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]",
"[concat(variables('factoryId'), '/pipelines/Throw Exception')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Email Sender')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Provide a simple abstract over the send email function with request body item exposed as pipeline parameters.",
"activities": [
{
"name": "Send Email",
"description": "Use an Azure Function to perform an SMTP client email send operation.",
"type": "AzureFunctionActivity",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "SendEmail",
"method": "POST",
"headers": {},
"body": {
"value": "{\n\"emailRecipients\": \"@{pipeline().parameters.Recipients}\",\n\"emailCcRecipients\": \"@{pipeline().parameters.CcRecipients}\",\n\"emailBccRecipients\": \"@{pipeline().parameters.BccRecipients}\",\n\"emailSubject\": \"@{pipeline().parameters.Subject}\",\n\"emailBody\": \"@{pipeline().parameters.Body}\",\n\"emailImportance\": \"@{pipeline().parameters.Importance}\"\n}",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
}
],
"parameters": {
"Recipients": {
"type": "string"
},
"CcRecipients": {
"type": "string"
},
"BccRecipients": {
"type": "string"
},
"Subject": {
"type": "string"
},
"Body": {
"type": "string"
},
"Importance": {
"type": "string"
}
},
"folder": {
"name": "_ProcFwk/_ProcFwkUtils"
},
"annotations": [
"procfwk",
"Utils"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/FrameworkFunctions')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Intentional Error')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait1",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
},
{
"name": "Raise Errors or Not",
"description": "Framework development worker simulator.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Wait1",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@equals(pipeline().parameters.RaiseErrors,'true')",
"type": "Expression"
},
"ifTrueActivities": [
{
"name": "Call Fail Procedure",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[dbo].[FailProcedure]",
"storedProcedureParameters": {
"RaiseError": {
"value": {
"value": "@pipeline().parameters.RaiseErrors",
"type": "Expression"
},
"type": "String"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
}
],
"parameters": {
"RaiseErrors": {
"type": "string",
"defaultValue": "false"
},
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Throw Exception')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Provide a simple way of throwing an exception within Data Factory using TSQL error handling.",
"activities": [
{
"name": "Raise Error",
"description": "Using a SQL database to raise an error/exception but wrapped up as a data factory pipeline. Error message information exposed as a pipeline parameter.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderQuery": {
"value": "RAISERROR('@{pipeline().parameters.Message}',16,1);",
"type": "Expression"
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
}
],
"parameters": {
"Message": {
"type": "string"
}
},
"folder": {
"name": "_ProcFwk/_ProcFwkUtils"
},
"annotations": [
"procfwk",
"Utils"
]
},
"dependsOn": [
"[concat(variables('factoryId'), '/datasets/GetSetMetadata')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Wait 1')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait1",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 10')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait10",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 2')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait2",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 3')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait3",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 4')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait4",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 5')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait5",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 6')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait6",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 7')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait7",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 8')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait8",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/Wait 9')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait9",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 15
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/GetSetMetadata')]",
"type": "Microsoft.DataFactory/factories/datasets",
"apiVersion": "2018-06-01",
"properties": {
"description": "Single generic dataset used to get and set all database metadata.",
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"procfwk"
],
"type": "AzureSqlTable",
"schema": [],
"typeProperties": {}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/FrameworkFunctions')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Interact with the Azure Functions App used as middle ware when making requests to Worker pipelines. Authentication done at the Function App level.",
"annotations": [
"procfwk"
],
"type": "AzureFunction",
"typeProperties": {
"functionAppUrl": "[parameters('FrameworkFunctions_properties_typeProperties_functionAppUrl')]",
"functionKey": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "FrameworkFunctionsKey"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/Keys')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Connection to Key Vault for all other ADF linked service credentials required to run the processing framework.",
"annotations": [
"procfwk"
],
"type": "AzureKeyVault",
"typeProperties": {
"baseUrl": "[parameters('Keys_properties_typeProperties_baseUrl')]"
}
},
"dependsOn": []
},
{
"name": "[concat(parameters('factoryName'), '/SupportDatabase')]",
"type": "Microsoft.DataFactory/factories/linkedServices",
"apiVersion": "2018-06-01",
"properties": {
"description": "Connection between ADF and processing framework metadata SQLDB.",
"annotations": [
"procfwk"
],
"type": "AzureSqlDatabase",
"typeProperties": {
"connectionString": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "[parameters('SupportDatabase_properties_typeProperties_connectionString_secretName')]"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('factoryName'), '/FunctionalTestingTrigger')]",
"type": "Microsoft.DataFactory/factories/triggers",
"apiVersion": "2018-06-01",
"properties": {
"description": "Used for functional testing of the framework in a dedicated environment.",
"annotations": [
"procfwk"
],
"runtimeState": "Stopped",
"pipelines": [
{
"pipelineReference": {
"referenceName": "01-Grandparent",
"type": "PipelineReference"
},
"parameters": {}
}
],
"type": "ScheduleTrigger",
"typeProperties": {
"recurrence": {
"frequency": "Hour",
"interval": 2,
"startTime": "2020-04-06T15:00:00Z",
"timeZone": "UTC"
}
}
},
"dependsOn": [
"[concat(variables('factoryId'), '/pipelines/01-Grandparent')]"
]
}
]
}
================================================
FILE: ARM Templates/Functions App/v1.6 Export.json
================================================
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"FunctionAppName": {
"defaultValue": "",
"type": "String"
},
"SubscriptionAndRegionServerFarmLocation": {
"defaultValue": "/subscriptions/{YourSubscriptionId}/resourceGroups/{YourResourceGroupName}/providers/Microsoft.Web/serverfarms/UKSouthPlan",
"type": "String"
}
},
"variables": {},
"resources": [
{
"type": "Microsoft.Web/sites",
"apiVersion": "2018-11-01",
"name": "[parameters('FunctionAppName')]",
"location": "UK South",
"kind": "functionapp",
"properties": {
"enabled": true,
"hostNameSslStates": [
{
"name": "[parameters('FunctionAppName')].azurewebsites.net",
"sslState": "Disabled",
"hostType": "Standard"
},
{
"name": "[parameters('FunctionAppName')].scm.azurewebsites.net",
"sslState": "Disabled",
"hostType": "Repository"
}
],
"serverFarmId": "[parameters('SubscriptionAndRegionServerFarmLocation')]",
"reserved": false,
"isXenon": false,
"hyperV": false,
"siteConfig": {},
"scmSiteAlsoStopped": false,
"clientAffinityEnabled": false,
"clientCertEnabled": false,
"hostNamesDisabled": false,
"containerSize": 1536,
"dailyMemoryTimeQuota": 0,
"httpsOnly": true,
"redundancyMode": "None"
}
},
{
"type": "Microsoft.Web/sites/config",
"apiVersion": "2018-11-01",
"name": "[concat(parameters('FunctionAppName'), '/web')]",
"location": "UK South",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', parameters('FunctionAppName'))]"
],
"properties": {
"numberOfWorkers": -1,
"defaultDocuments": [
"Default.htm",
"Default.html",
"Default.asp",
"index.htm",
"index.html",
"iisstart.htm",
"default.aspx",
"index.php"
],
"netFrameworkVersion": "v4.0",
"phpVersion": "5.6",
"requestTracingEnabled": false,
"remoteDebuggingEnabled": false,
"httpLoggingEnabled": false,
"logsDirectorySizeLimit": 35,
"detailedErrorLoggingEnabled": false,
"publishingUsername": "$[parameters('FunctionAppName')]",
"scmType": "None",
"use32BitWorkerProcess": true,
"webSocketsEnabled": false,
"alwaysOn": false,
"managedPipelineMode": "Integrated",
"virtualApplications": [
{
"virtualPath": "/",
"physicalPath": "site\\wwwroot",
"preloadEnabled": false
}
],
"loadBalancing": "LeastRequests",
"experiments": {
"rampUpRules": []
},
"autoHealEnabled": false,
"cors": {
"allowedOrigins": [
"https://functions.azure.com",
"https://functions-staging.azure.com",
"https://functions-next.azure.com"
],
"supportCredentials": false
},
"localMySqlEnabled": false,
"ipSecurityRestrictions": [
{
"ipAddress": "Any",
"action": "Allow",
"priority": 1,
"name": "Allow all",
"description": "Allow all access"
}
],
"scmIpSecurityRestrictions": [
{
"ipAddress": "Any",
"action": "Allow",
"priority": 1,
"name": "Allow all",
"description": "Allow all access"
}
],
"scmIpSecurityRestrictionsUseMain": false,
"http20Enabled": false,
"minTlsVersion": "1.2",
"ftpsState": "AllAllowed",
"reservedInstanceCount": 0
}
},
{
"type": "Microsoft.Web/sites/deployments",
"apiVersion": "2018-11-01",
"name": "[concat(parameters('FunctionAppName'), '/5aee31e75b934c5f80fca0b26fe47dbb')]",
"location": "UK South",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', parameters('FunctionAppName'))]"
],
"properties": {
"status": 4,
"author_email": "N/A",
"author": "N/A",
"deployer": "Push-Deployer",
"message": "Created via a push deployment",
"start_time": "2020-04-30T13:29:11.8890295Z",
"end_time": "2020-04-30T13:29:16.4504076Z",
"active": false
}
},
{
"type": "Microsoft.Web/sites/deployments",
"apiVersion": "2018-11-01",
"name": "[concat(parameters('FunctionAppName'), '/6b0808e64188414e88d75565027efc59')]",
"location": "UK South",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', parameters('FunctionAppName'))]"
],
"properties": {
"status": 4,
"author_email": "N/A",
"author": "N/A",
"deployer": "Push-Deployer",
"message": "Created via a push deployment",
"start_time": "2020-04-30T16:17:52.965083Z",
"end_time": "2020-04-30T16:17:58.0803657Z",
"active": false
}
},
{
"type": "Microsoft.Web/sites/deployments",
"apiVersion": "2018-11-01",
"name": "[concat(parameters('FunctionAppName'), '/9ca87860d72f47049af7ab9bce50ccc1')]",
"location": "UK South",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', parameters('FunctionAppName'))]"
],
"properties": {
"status": 4,
"author_email": "N/A",
"author": "N/A",
"deployer": "Push-Deployer",
"message": "Created via a push deployment",
"start_time": "2020-05-06T13:21:39.9815784Z",
"end_time": "2020-05-06T13:21:45.8257955Z",
"active": true
}
},
{
"type": "Microsoft.Web/sites/functions",
"apiVersion": "2018-11-01",
"name": "[concat(parameters('FunctionAppName'), '/CheckPipelineStatus')]",
"location": "UK South",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', parameters('FunctionAppName'))]"
],
"properties": {
"script_root_path_href": "https://[parameters('FunctionAppName')].azurewebsites.net/admin/vfs/site/wwwroot/CheckPipelineStatus/",
"script_href": "https://[parameters('FunctionAppName')].azurewebsites.net/admin/vfs/site/wwwroot/bin/ADFprocfwk.dll",
"config_href": "https://[parameters('FunctionAppName')].azurewebsites.net/admin/vfs/site/wwwroot/CheckPipelineStatus/function.json",
"href": "https://[parameters('FunctionAppName')].azurewebsites.net/admin/functions/CheckPipelineStatus",
"config": {}
}
},
{
"type": "Microsoft.Web/sites/functions",
"apiVersion": "2018-11-01",
"name": "[concat(parameters('FunctionAppName'), '/ExecutePipeline')]",
"location": "UK South",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', parameters('FunctionAppName'))]"
],
"properties": {
"script_root_path_href": "https://[parameters('FunctionAppName')].azurewebsites.net/admin/vfs/site/wwwroot/ExecutePipeline/",
"script_href": "https://[parameters('FunctionAppName')].azurewebsites.net/admin/vfs/site/wwwroot/bin/ADFprocfwk.dll",
"config_href": "https://[parameters('FunctionAppName')].azurewebsites.net/admin/vfs/site/wwwroot/ExecutePipeline/function.json",
"href": "https://[parameters('FunctionAppName')].azurewebsites.net/admin/functions/ExecutePipeline",
"config": {}
}
},
{
"type": "Microsoft.Web/sites/functions",
"apiVersion": "2018-11-01",
"name": "[concat(parameters('FunctionAppName'), '/GetActivityErrors')]",
"location": "UK South",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', parameters('FunctionAppName'))]"
],
"properties": {
"script_root_path_href": "https://[parameters('FunctionAppName')].azurewebsites.net/admin/vfs/site/wwwroot/GetActivityErrors/",
"script_href": "https://[parameters('FunctionAppName')].azurewebsites.net/admin/vfs/site/wwwroot/bin/ADFprocfwk.dll",
"config_href": "https://[parameters('FunctionAppName')].azurewebsites.net/admin/vfs/site/wwwroot/GetActivityErrors/function.json",
"href": "https://[parameters('FunctionAppName')].azurewebsites.net/admin/functions/GetActivityErrors",
"config": {}
}
},
{
"type": "Microsoft.Web/sites/functions",
"apiVersion": "2018-11-01",
"name": "[concat(parameters('FunctionAppName'), '/SendEmail')]",
"location": "UK South",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', parameters('FunctionAppName'))]"
],
"properties": {
"script_root_path_href": "https://[parameters('FunctionAppName')].azurewebsites.net/admin/vfs/site/wwwroot/SendEmail/",
"script_href": "https://[parameters('FunctionAppName')].azurewebsites.net/admin/vfs/site/wwwroot/bin/ADFprocfwk.dll",
"config_href": "https://[parameters('FunctionAppName')].azurewebsites.net/admin/vfs/site/wwwroot/SendEmail/function.json",
"href": "https://[parameters('FunctionAppName')].azurewebsites.net/admin/functions/SendEmail",
"config": {}
}
},
{
"type": "Microsoft.Web/sites/hostNameBindings",
"apiVersion": "2018-11-01",
"name": "[concat(parameters('FunctionAppName'), '/', parameters('FunctionAppName'), '.azurewebsites.net')]",
"location": "UK South",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', parameters('FunctionAppName'))]"
],
"properties": {
"siteName": "[parameters('FunctionAppName')]",
"hostNameType": "Verified"
}
}
]
}
================================================
FILE: ARM Templates/SQL Database/v1.6 Export.json
================================================
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"servers_platformsupport01_name": {
"defaultValue": "frameworksupport01",
"type": "String"
}
},
"variables": {},
"resources": [
{
"type": "Microsoft.Sql/servers/databases",
"apiVersion": "2019-06-01-preview",
"name": "[concat(parameters('servers_platformsupport01_name'), '/OrchestrationSupport')]",
"location": "uksouth",
"sku": {
"name": "Standard",
"tier": "Standard",
"capacity": 20
},
"kind": "v12.0,user",
"properties": {
"collation": "SQL_Latin1_General_CP1_CI_AS",
"maxSizeBytes": 10737418240,
"catalogCollation": "SQL_Latin1_General_CP1_CI_AS",
"zoneRedundant": false,
"readScale": "Disabled",
"readReplicaCount": 0,
"storageAccountType": "GRS"
}
},
{
"type": "Microsoft.Sql/servers/databases/advisors",
"apiVersion": "2014-04-01",
"name": "[concat(parameters('servers_platformsupport01_name'), '/OrchestrationSupport/CreateIndex')]",
"dependsOn": [
"[resourceId('Microsoft.Sql/servers/databases', parameters('servers_platformsupport01_name'), 'OrchestrationSupport')]"
],
"properties": {
"autoExecuteValue": "Disabled"
}
},
{
"type": "Microsoft.Sql/servers/databases/advisors",
"apiVersion": "2014-04-01",
"name": "[concat(parameters('servers_platformsupport01_name'), '/OrchestrationSupport/DbParameterization')]",
"dependsOn": [
"[resourceId('Microsoft.Sql/servers/databases', parameters('servers_platformsupport01_name'), 'OrchestrationSupport')]"
],
"properties": {
"autoExecuteValue": "Disabled"
}
},
{
"type": "Microsoft.Sql/servers/databases/advisors",
"apiVersion": "2014-04-01",
"name": "[concat(parameters('servers_platformsupport01_name'), '/OrchestrationSupport/DefragmentIndex')]",
"dependsOn": [
"[resourceId('Microsoft.Sql/servers/databases', parameters('servers_platformsupport01_name'), 'OrchestrationSupport')]"
],
"properties": {
"autoExecuteValue": "Disabled"
}
},
{
"type": "Microsoft.Sql/servers/databases/advisors",
"apiVersion": "2014-04-01",
"name": "[concat(parameters('servers_platformsupport01_name'), '/OrchestrationSupport/DropIndex')]",
"dependsOn": [
"[resourceId('Microsoft.Sql/servers/databases', parameters('servers_platformsupport01_name'), 'OrchestrationSupport')]"
],
"properties": {
"autoExecuteValue": "Disabled"
}
},
{
"type": "Microsoft.Sql/servers/databases/advisors",
"apiVersion": "2014-04-01",
"name": "[concat(parameters('servers_platformsupport01_name'), '/OrchestrationSupport/ForceLastGoodPlan')]",
"dependsOn": [
"[resourceId('Microsoft.Sql/servers/databases', parameters('servers_platformsupport01_name'), 'OrchestrationSupport')]"
],
"properties": {
"autoExecuteValue": "Enabled"
}
},
{
"type": "Microsoft.Sql/servers/databases/auditingPolicies",
"apiVersion": "2014-04-01",
"name": "[concat(parameters('servers_platformsupport01_name'), '/OrchestrationSupport/Default')]",
"location": "UK South",
"dependsOn": [
"[resourceId('Microsoft.Sql/servers/databases', parameters('servers_platformsupport01_name'), 'OrchestrationSupport')]"
],
"properties": {
"auditingState": "Disabled"
}
},
{
"type": "Microsoft.Sql/servers/databases/auditingSettings",
"apiVersion": "2017-03-01-preview",
"name": "[concat(parameters('servers_platformsupport01_name'), '/OrchestrationSupport/Default')]",
"dependsOn": [
"[resourceId('Microsoft.Sql/servers/databases', parameters('servers_platformsupport01_name'), 'OrchestrationSupport')]"
],
"properties": {
"state": "Disabled",
"retentionDays": 0,
"storageAccountSubscriptionId": "00000000-0000-0000-0000-000000000000",
"isAzureMonitorTargetEnabled": false
}
},
{
"type": "Microsoft.Sql/servers/databases/backupLongTermRetentionPolicies",
"apiVersion": "2017-03-01-preview",
"name": "[concat(parameters('servers_platformsupport01_name'), '/OrchestrationSupport/default')]",
"dependsOn": [
"[resourceId('Microsoft.Sql/servers/databases', parameters('servers_platformsupport01_name'), 'OrchestrationSupport')]"
],
"properties": {
"weeklyRetention": "PT0S",
"monthlyRetention": "PT0S",
"yearlyRetention": "PT0S",
"weekOfYear": 0
}
},
{
"type": "Microsoft.Sql/servers/databases/backupShortTermRetentionPolicies",
"apiVersion": "2017-10-01-preview",
"name": "[concat(parameters('servers_platformsupport01_name'), '/OrchestrationSupport/default')]",
"dependsOn": [
"[resourceId('Microsoft.Sql/servers/databases', parameters('servers_platformsupport01_name'), 'OrchestrationSupport')]"
],
"properties": {
"retentionDays": 7
}
},
{
"type": "Microsoft.Sql/servers/databases/extendedAuditingSettings",
"apiVersion": "2017-03-01-preview",
"name": "[concat(parameters('servers_platformsupport01_name'), '/OrchestrationSupport/Default')]",
"dependsOn": [
"[resourceId('Microsoft.Sql/servers/databases', parameters('servers_platformsupport01_name'), 'OrchestrationSupport')]"
],
"properties": {
"state": "Disabled",
"retentionDays": 0,
"storageAccountSubscriptionId": "00000000-0000-0000-0000-000000000000",
"isAzureMonitorTargetEnabled": false
}
},
{
"type": "Microsoft.Sql/servers/databases/geoBackupPolicies",
"apiVersion": "2014-04-01",
"name": "[concat(parameters('servers_platformsupport01_name'), '/OrchestrationSupport/Default')]",
"location": "UK South",
"dependsOn": [
"[resourceId('Microsoft.Sql/servers/databases', parameters('servers_platformsupport01_name'), 'OrchestrationSupport')]"
],
"properties": {
"state": "Enabled"
}
},
{
"type": "Microsoft.Sql/servers/databases/securityAlertPolicies",
"apiVersion": "2018-06-01-preview",
"name": "[concat(parameters('servers_platformsupport01_name'), '/OrchestrationSupport/Default')]",
"dependsOn": [
"[resourceId('Microsoft.Sql/servers/databases', parameters('servers_platformsupport01_name'), 'OrchestrationSupport')]"
],
"properties": {
"state": "Disabled",
"disabledAlerts": [
""
],
"emailAddresses": [
""
],
"emailAccountAdmins": false,
"retentionDays": 0
}
},
{
"type": "Microsoft.Sql/servers/databases/transparentDataEncryption",
"apiVersion": "2014-04-01",
"name": "[concat(parameters('servers_platformsupport01_name'), '/OrchestrationSupport/current')]",
"location": "UK South",
"dependsOn": [
"[resourceId('Microsoft.Sql/servers/databases', parameters('servers_platformsupport01_name'), 'OrchestrationSupport')]"
],
"properties": {
"status": "Enabled"
}
},
{
"type": "Microsoft.Sql/servers/databases/vulnerabilityAssessments",
"apiVersion": "2017-03-01-preview",
"name": "[concat(parameters('servers_platformsupport01_name'), '/OrchestrationSupport/Default')]",
"dependsOn": [
"[resourceId('Microsoft.Sql/servers/databases', parameters('servers_platformsupport01_name'), 'OrchestrationSupport')]"
],
"properties": {
"recurringScans": {
"isEnabled": false,
"emailSubscriptionAdmins": true
}
}
}
]
}
================================================
FILE: ARM Templates/Synapse/v2.0 Export.json
================================================
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"workspaceName": {
"type": "string",
"metadata": "Workspace name",
"defaultValue": ""
},
"FrameworkFunctions_properties_typeProperties_functionAppUrl": {
"type": "string",
"defaultValue": ""
},
"Keys_properties_typeProperties_baseUrl": {
"type": "string",
"defaultValue": ""
},
"SupportDatabase_properties_typeProperties_connectionString_secretName": {
"type": "string",
"defaultValue": ""
}
},
"variables": {
"workspaceId": "[concat('Microsoft.Synapse/workspaces/', parameters('workspaceName'))]"
},
"resources": [
{
"name": "[concat(parameters('workspaceName'), '/01-Grandparent')]",
"type": "Microsoft.Synapse/workspaces/pipelines",
"apiVersion": "2019-06-01-preview",
"properties": {
"description": "procfwk grandparent pipeline used optionally to bootstrap any wider processes in your Data Factory that then calls the processing framework.",
"activities": [
{
"name": "procfwk",
"description": "Call procfwk",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "02-Parent",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"BatchName": {
"value": "@pipeline().parameters.BatchName",
"type": "Expression"
}
}
}
}
],
"parameters": {
"BatchName": {
"type": "string",
"defaultValue": "NotUsed"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"procfwk",
"Grandparent"
]
},
"dependsOn": [
"[concat(variables('workspaceId'), '/pipelines/02-Parent')]"
]
},
{
"name": "[concat(parameters('workspaceName'), '/02-Parent')]",
"type": "Microsoft.Synapse/workspaces/pipelines",
"apiVersion": "2019-06-01-preview",
"properties": {
"description": "ADF.procfwk parent pipeline used to bootstrap the orchestration framework in perform the first level ForEach calls in sequence for the metadata stages.",
"activities": [
{
"name": "Get Stages",
"description": "Returns a distinct list of execution stages within the framework metadata.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Set Execution Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetStages]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@variables('ExecutionId')",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Stages",
"description": "Top level ForEach to sequentially call all processing stages within the framework metadata. Items for iteration passed from the Get Stages lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Stages",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Stages').output.value",
"type": "Expression"
},
"isSequential": true,
"activities": [
{
"name": "Stage Executor",
"description": "Call to the framework generic child pipeline for a given execution stage.",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Log Stage Preparing",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "03-Child",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"StageId": {
"value": "@item().StageId",
"type": "Expression"
},
"ExecutionId": {
"value": "@variables('ExecutionId')",
"type": "Expression"
}
}
}
},
{
"name": "Log Stage Preparing",
"description": "Update the current execution table flagging all pipelines within the stage as preparing.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Check and Update Blockers",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogStagePreparing]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@variables('ExecutionId')",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check and Update Blockers",
"description": "Used to double check and stop the next execution stage if failures and blockers have be incurred. This also depends on the failure handling property value which defines the stored procedure behaviour.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[CheckForBlockedPipelines]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@variables('ExecutionId')",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Execution Wrapper",
"description": "Wrapper to reset and restart processing or create a completely new execution instance of the framework metadata.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Clean Up Previous Run",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[ExecutionWrapper]",
"storedProcedureParameters": {
"CallingOrchestratorName": {
"type": "String",
"value": {
"value": "@pipeline().DataFactory",
"type": "Expression"
}
},
"BatchName": {
"type": "String",
"value": {
"value": "@pipeline().parameters.BatchName",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Check Outcome and Update Logs",
"description": "After a successful execution run the current execution metadata is moved to the long term logging table by this stored procedure call. Otherwise an error will be raised.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Stages",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[UpdateExecutionLog]",
"storedProcedureParameters": {
"PerformErrorCheck": {
"value": {
"value": "@bool(1)",
"type": "Expression"
},
"type": "Boolean"
},
"ExecutionId": {
"value": {
"value": "@variables('ExecutionId')",
"type": "Expression"
},
"type": "Guid"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check Previous Execution",
"description": "Query the current execution table for worker pipelines that require a clean up from the previous execution run.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Execute Precursor",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[CheckPreviousExeuction]",
"storedProcedureParameters": {
"BatchName": {
"type": "String",
"value": {
"value": "@pipeline().parameters.BatchName",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Clean Up Previous Run",
"description": "Handle Worker pipelines that are reported as Running when the parent pipeline is called again. Get what the actual status of those pipelines is.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Check Previous Execution",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Check Metadata Integrity",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Check Previous Execution').output.value",
"type": "Expression"
},
"isSequential": false,
"batchCount": 50,
"activities": [
{
"name": "Get SPN Details",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": true,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetWorkerAuthDetails]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
}
},
"PipelineId": {
"type": "Int32",
"value": {
"value": "@item().PipelineId",
"type": "Expression"
}
},
"StageId": {
"type": "Int32",
"value": {
"value": "@item().StageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Pipeline Checking",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineChecking]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Pipeline Status",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Get SPN Details",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Log Pipeline Checking",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"functionName": "CheckPipelineStatus",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',activity('Get SPN Details').output.firstRow.TenantId,'\",\n \"applicationId\": \"',activity('Get SPN Details').output.firstRow.AppId,'\",\n \"authenticationKey\": \"',activity('Get SPN Details').output.firstRow.AppSecret,'\",\n \"subscriptionId\": \"',activity('Get SPN Details').output.firstRow.SubscriptionId,'\",\n \"resourceGroupName\": \"',item().ResourceGroupName,'\",\n \"orchestratorName\": \"',item().OrchestratorName,'\",\n \"orchestratorType\": \"',item().OrchestratorType,'\",\n \"pipelineName\": \"',item().PipelineName,'\",\n \"runId\": \"',item().PipelineRunId,'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Set Pipeline Status",
"description": "Update the metadata depending on the actual pipeline outcome. Using the status as the case.",
"type": "Switch",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"on": {
"value": "@activity('Get Pipeline Status').output.ActualStatus",
"type": "Expression"
},
"cases": [
{
"value": "Failed",
"activities": [
{
"name": "Pipeline Status Failed",
"description": "Updates the current execution table with a pipeline status of failed if the function outcome is failed. Also blocks pipelines in the downstream execution stage.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": null,
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Succeeded",
"activities": [
{
"name": "Pipeline Status Succeeded",
"description": "Updates the current execution table with a pipeline status of success if the function outcome is succeeded.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineSuccess]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Queued",
"activities": [
{
"name": "Pipeline Status Queued - Running",
"description": "Updates the current execution table with a pipeline status of running if the function outcome is queued.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "InProgress",
"activities": [
{
"name": "Pipeline Status InProgress - Running",
"description": "Updates the current execution table with a pipeline status of running if the function outcome is in progress.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Cancelled",
"activities": [
{
"name": "Pipeline Status Cancelled",
"description": "Updates the current execution table with a pipeline status of cancelled if the function outcome is cancelled.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineCancelled]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
},
"CleanUpRun": {
"value": {
"value": "@bool(1)",
"type": "Expression"
},
"type": "Boolean"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
],
"defaultActivities": [
{
"name": "Pipeline Status Unknown",
"description": "Updates the current execution table with a pipeline status of unknown if the function returns an unexpected outcome.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineUnknown]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
},
"CleanUpRun": {
"value": {
"value": "@bool(1)",
"type": "Expression"
},
"type": "Boolean"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Set Last Check DateTime",
"description": "Update the current execution table with a date time from when the function last checked the pipeline status.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineLastStatusCheck]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Execute Precursor",
"description": "Uses the database property value ExecutionPrecursorProc to run any custom logic against the metadata database before the execution run starts.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[ExecutePrecursorProcedure]"
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Set Execution Id",
"description": "Set the local execution Id to a pipeline variable for each in several downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Execution Wrapper",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "ExecutionId",
"value": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
}
}
},
{
"name": "Check Metadata Integrity",
"description": "Performs a series of checks on all metadata held in the framework SQLDB. This is intended to raise errors before an execution run even starts.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Precursor",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[CheckMetadataIntegrity]",
"storedProcedureParameters": {
"BatchName": {
"value": {
"value": "@pipeline().parameters.BatchName",
"type": "Expression"
},
"type": "String"
},
"DebugMode": {
"value": {
"value": "@bool(0)",
"type": "Expression"
},
"type": "Boolean"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
],
"parameters": {
"BatchName": {
"type": "string",
"defaultValue": "NotUsed"
}
},
"variables": {
"ExecutionId": {
"type": "String"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"procfwk",
"Parent"
]
},
"dependsOn": [
"[concat(variables('workspaceId'), '/datasets/GetSetMetadata')]",
"[concat(variables('workspaceId'), '/linkedServices/SupportDatabase')]",
"[concat(variables('workspaceId'), '/pipelines/03-Child')]",
"[concat(variables('workspaceId'), '/linkedServices/FrameworkFunctions')]"
]
},
{
"name": "[concat(parameters('workspaceName'), '/03-Child')]",
"type": "Microsoft.Synapse/workspaces/pipelines",
"apiVersion": "2019-06-01-preview",
"properties": {
"description": "procfwk child pipeline used to execute Worker pipelines within a given execution stage. This pipeline will be called once for each stage, then execute all Workers in parallel.",
"activities": [
{
"name": "Get Pipelines",
"description": "Returns all pipelines from the metadata to be executed within a given processing stage.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelinesInStage]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
}
},
"StageId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
},
{
"name": "Execute Pipelines",
"description": "Second level ForEach to run in parallel all pipelines within the stage. Items for iteration passed from the Get Pipelines lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Pipelines",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Pipelines').output.value",
"type": "Expression"
},
"isSequential": false,
"batchCount": 50,
"activities": [
{
"name": "Worker Pipeline Executor",
"description": "Run the required worker pipeline and wait for its completion. Update metadata once done.",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "04-Infant",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"executionId": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"stageId": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"pipelineId": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
}
}
]
}
}
],
"parameters": {
"StageId": {
"type": "int"
},
"ExecutionId": {
"type": "string"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"procfwk",
"Child"
]
},
"dependsOn": [
"[concat(variables('workspaceId'), '/datasets/GetSetMetadata')]",
"[concat(variables('workspaceId'), '/pipelines/04-Infant')]"
]
},
{
"name": "[concat(parameters('workspaceName'), '/04-Infant')]",
"type": "Microsoft.Synapse/workspaces/pipelines",
"apiVersion": "2019-06-01-preview",
"properties": {
"description": "procfwk infant pipeline used to check when the processing pipeline called by the Child completes and passes the resulting status back to the metadata database.",
"activities": [
{
"name": "Execute Worker Pipeline",
"description": "The lowest level executor with the metadata framework to call existing processing pipelines within Data Factory. The function called will block processing and wait for an outcome.",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Log Pipeline Running",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Pipeline Params",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"functionName": "ExecutePipeline",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',variables('WorkerCoreDetails')[0].tenantId,'\",\n \"applicationId\": \"',variables('WorkerCoreDetails')[0].applicationId,'\",\n \"authenticationKey\": \"',variables('WorkerCoreDetails')[0].authenticationKey,'\",\n \"subscriptionId\": \"',variables('WorkerCoreDetails')[0].subscriptionId,'\",\n \"resourceGroupName\": \"',variables('WorkerCoreDetails')[0].resourceGroupName,'\",\n\t\"orchestratorName\": \"',variables('WorkerCoreDetails')[0].orchestratorName,'\",\n \"orchestratorType\": \"',variables('WorkerCoreDetails')[0].orchestratorType,'\",\n \"pipelineName\": \"',variables('WorkerCoreDetails')[0].pipelineName,'\"',activity('Get Pipeline Params').output.firstRow.Params,'\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Pipeline Params",
"description": "Returns any parameters from metadata required for the processing pipeline being called. The output can be an empty string if no parameters are required.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPipelineParameters]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Log Pipeline Running",
"description": "Sets the current pipeline with a status of running within the current execution database table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Is Target Worker Validate",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Execute Function Activity Failure",
"description": "Handle true failures from calling out to the Azure Function and update the current execution table accordingly so a restart can occur.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Worker Pipeline",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
},
"CallingActivity": {
"value": "ExecuteWorkerPipeline",
"type": "String"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Update Run Id",
"description": "Provide the actual ADF run ID back to the current execution table for long term logging and alignment between the metadata other Azure monitoring tools.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Set Run Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineRunId]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@variables('WorkerRunId')",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check For Alerts",
"description": "Checks the properties tables and if any recipients in the database require alerts sending for the current pipeline ID.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Update Run Id",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Pipeline Result",
"dependencyConditions": [
"Completed"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[CheckForEmailAlerts]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": true
}
},
{
"name": "Send Alerts",
"description": "True = alerts need sending.\nFalse = do nothing.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Check For Alerts",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@activity('Check For Alerts').output.firstRow.SendAlerts",
"type": "Expression"
},
"ifTrueActivities": [
{
"name": "Get Email Parts",
"description": "Return all required content from the metadata database to send an email alerting using the procfwk. The lookup returns the exact content for the function body request.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": true,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetEmailAlertParts]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": true
}
},
{
"name": "Call Email Sender",
"description": "Pass off email request to Utils Send Email pipeline.",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Get Email Parts",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "Email Sender",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"Recipients": {
"value": "@activity('Get Email Parts').output.firstRow.emailRecipients",
"type": "Expression"
},
"CcRecipients": {
"value": "@activity('Get Email Parts').output.firstRow.emailCcRecipients",
"type": "Expression"
},
"BccRecipients": {
"value": "@activity('Get Email Parts').output.firstRow.emailBccRecipients",
"type": "Expression"
},
"Subject": {
"value": "@activity('Get Email Parts').output.firstRow.emailSubject",
"type": "Expression"
},
"Body": {
"value": "@activity('Get Email Parts').output.firstRow.emailBody",
"type": "Expression"
},
"Importance": {
"value": "@activity('Get Email Parts').output.firstRow.emailImportance",
"type": "Expression"
}
}
}
}
]
}
},
{
"name": "Wait Until Pipeline Completes",
"description": "Loops until the Worker pipeline called completes.\n\nSimple status:\n- Running = new iteration.\n- Done = break.",
"type": "Until",
"dependsOn": [
{
"activity": "Get Wait Duration",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Execute Worker Pipeline",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Run Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@variables('WorkerPipelineState')",
"type": "Expression"
},
"activities": [
{
"name": "Get Worker Pipeline Status",
"description": "Checks the status of a given processing pipeline and provides the value for the downstream framework activities to act upon.",
"type": "AzureFunctionActivity",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"functionName": "CheckPipelineStatus",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',variables('WorkerCoreDetails')[0].tenantId,'\",\n \"applicationId\": \"',variables('WorkerCoreDetails')[0].applicationId,'\",\n \"authenticationKey\": \"',variables('WorkerCoreDetails')[0].authenticationKey,'\",\n \"subscriptionId\": \"',variables('WorkerCoreDetails')[0].subscriptionId,'\",\n \"resourceGroupName\": \"',variables('WorkerCoreDetails')[0].resourceGroupName,'\",\n\t\"orchestratorName\": \"',variables('WorkerCoreDetails')[0].orchestratorName,'\",\n \"orchestratorType\": \"',variables('WorkerCoreDetails')[0].orchestratorType,'\",\n \"pipelineName\": \"',variables('WorkerCoreDetails')[0].pipelineName,'\",\n \"runId\": \"',variables('WorkerRunId'),'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Wait If Running",
"description": "True = Do nothing.\nFalse = Wait, before the next iteration.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Set Worker State",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@variables('WorkerPipelineState')",
"type": "Expression"
},
"ifFalseActivities": [
{
"name": "Wait for Pipeline",
"description": "The processing pipeline is still running so Wait before checking its status again.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@activity('Get Wait Duration').output.firstRow.PropertyValue",
"type": "Expression"
}
}
}
]
}
},
{
"name": "Set Last Check DateTime",
"description": "Update the current execution table with a date time from when the Worker pipeline status was last checked as part of the Until iterations.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Worker Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineLastStatusCheck]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Check Function Activity Failure",
"description": "Report to the current execution table that the framework pipeline activity has failed. This failure is outside of the scope of the framework and is probably related to a wider platform problem.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Worker Pipeline Status",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"CallingActivity": {
"value": "GetWorkerPipelineStatus",
"type": "String"
},
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Set Worker State",
"description": "Set the bool state of the Worker pipeline to be used by the Until and If expressions. True = Complete, False = Running.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Worker Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerPipelineState",
"value": {
"value": "@equals('Complete',activity('Get Worker Pipeline Status').output.SimpleStatus)",
"type": "Expression"
}
}
}
],
"timeout": "0.00:10:00"
}
},
{
"name": "Set Pipeline Result",
"description": "Receives the outcome from the function execution for a given processing pipeline and updates the current execution table with different pipelines status values depending on the result (case).",
"type": "Switch",
"dependsOn": [
{
"activity": "Wait Until Pipeline Completes",
"dependencyConditions": [
"Completed"
]
}
],
"userProperties": [],
"typeProperties": {
"on": {
"value": "@activity('Get Worker Pipeline Status').output.ActualStatus",
"type": "Expression"
},
"cases": [
{
"value": "Succeeded",
"activities": [
{
"name": "Pipeline Status Succeeded",
"description": "Updates the current execution table with a pipeline status of success if the function outcome is succeeded.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineSuccess]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Failed",
"activities": [
{
"name": "Pipeline Status Failed",
"description": "Updates the current execution table with a pipeline status of failed if the function outcome is failed. Also blocks pipelines in the downstream execution stage.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@variables('WorkerRunId')",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Worker Pipeline Error Details",
"description": "Get the activity error details for the run ID of the worker pipeline called. Returns an array of all errors.",
"type": "AzureFunctionActivity",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"functionName": "GetActivityErrors",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',variables('WorkerCoreDetails')[0].tenantId,'\",\n \"applicationId\": \"',variables('WorkerCoreDetails')[0].applicationId,'\",\n \"authenticationKey\": \"',variables('WorkerCoreDetails')[0].authenticationKey,'\",\n \"subscriptionId\": \"',variables('WorkerCoreDetails')[0].subscriptionId,'\",\n \"resourceGroupName\": \"',variables('WorkerCoreDetails')[0].resourceGroupName,'\",\n\t\"orchestratorName\": \"',variables('WorkerCoreDetails')[0].orchestratorName,'\",\n \"orchestratorType\": \"',variables('WorkerCoreDetails')[0].orchestratorType,'\",\n \"pipelineName\": \"',variables('WorkerCoreDetails')[0].pipelineName,'\",\n \"runId\": \"',variables('WorkerRunId'),'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Error Details",
"description": "Parses pipeline error details and persists them to the metadata database error log table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Worker Pipeline Error Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetErrorLogDetails]",
"storedProcedureParameters": {
"JsonErrorDetails": {
"value": {
"value": "@string(activity('Get Worker Pipeline Error Details').output)",
"type": "Expression"
},
"type": "String"
},
"LocalExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Cancelled",
"activities": [
{
"name": "Pipeline Status Cancelled",
"description": "Updates the current execution table with a pipeline status of cancelled if the function outcome is cancelled.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineCancelled]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
],
"defaultActivities": [
{
"name": "Pipeline Status Unknown",
"description": "Updates the current execution table with a pipeline status of unknown if the function returns an unexpected outcome.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineUnknown]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Get Wait Duration",
"description": "Return wait duration in seconds from database properties table to be used during each Until iteration when the Worker pipeline is still running.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "PipelineStatusCheckDuration"
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Set Run Id",
"description": "Set local variable from activity output once for value reuse in downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Execute Worker Pipeline",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerRunId",
"value": {
"value": "@activity('Execute Worker Pipeline').output.RunId",
"type": "Expression"
}
}
},
{
"name": "Validate Pipeline",
"description": "Query the target data factory and establish if the provided worker pipeline name is valid.",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Log Pipeline Validating",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Capture Worker Core Details as an Array",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"functionName": "ValidatePipeline",
"method": "POST",
"headers": {},
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',variables('WorkerCoreDetails')[0].tenantId,'\",\n \"applicationId\": \"',variables('WorkerCoreDetails')[0].applicationId,'\",\n \"authenticationKey\": \"',variables('WorkerCoreDetails')[0].authenticationKey,'\",\n \"subscriptionId\": \"',variables('WorkerCoreDetails')[0].subscriptionId,'\",\n \"resourceGroupName\": \"',variables('WorkerCoreDetails')[0].resourceGroupName,'\",\n\t\"orchestratorName\": \"',variables('WorkerCoreDetails')[0].orchestratorName,'\",\n \"orchestratorType\": \"',variables('WorkerCoreDetails')[0].orchestratorType,'\",\n \"pipelineName\": \"',variables('WorkerCoreDetails')[0].pipelineName,'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Is Target Worker Validate",
"description": "True = the worker pipeline name is valid.\nFalse = the worker pipeline name is invalid. Raise an exception.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Validate Pipeline",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@bool(activity('Validate Pipeline').output.PipelineExists)",
"type": "Expression"
},
"ifFalseActivities": [
{
"name": "Throw Exception - Invalid Infant",
"description": "Throw an exception with details about the invalid worker pipeline name.",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "Throw Exception",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"Message": {
"value": "@concat('Worker pipeline [',variables('WorkerCoreDetails')[0].pipelineName,'] is not valid in target Orchestrator [',variables('WorkerCoreDetails')[0].orchestratorName,']')",
"type": "Expression"
}
}
}
},
{
"name": "Update Execution With Invalid Worker",
"description": "Update the current execution table with an informed status for the worker pipeline that couldn't be executed.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"CallingActivity": {
"value": "InvalidPipelineName",
"type": "String"
},
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Log Validate Function Activity Failure",
"description": "Handle true failures from calling out to the Azure Function and update the current execution table accordingly so a restart can occur.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Validate Pipeline",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
},
"CallingActivity": {
"value": "ValidatePipeline",
"type": "String"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Pipeline Validating",
"description": "Sets the current pipeline with a status of validating within the current execution database table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[procfwk].[SetLogPipelineValidating]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Worker Core Details",
"description": "Return worker pipeline information for metadata database. Including target data factory, pipeline name and resource group. Return the SPN ID and Secret for the worker pipeline being executed. Called at this level as each pipeline can have a different SPN.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": true,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetWorkerDetailsWrapper]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
}
},
"PipelineId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
}
},
"StageId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Capture Worker Core Details as an Array",
"description": "Add all worker pipeline details to a local variable array that can be accessed by each function call requiring the values.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Worker Core Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerCoreDetails",
"value": {
"value": "@array(activity('Get Worker Core Details').output.firstRow)",
"type": "Expression"
}
}
}
],
"parameters": {
"executionId": {
"type": "string"
},
"stageId": {
"type": "int"
},
"pipelineId": {
"type": "int"
}
},
"variables": {
"WorkerPipelineState": {
"type": "Boolean"
},
"WorkerRunId": {
"type": "String"
},
"WorkerCoreDetails": {
"type": "Array"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"procfwk",
"Infant"
]
},
"dependsOn": [
"[concat(variables('workspaceId'), '/linkedServices/FrameworkFunctions')]",
"[concat(variables('workspaceId'), '/datasets/GetSetMetadata')]",
"[concat(variables('workspaceId'), '/linkedServices/SupportDatabase')]",
"[concat(variables('workspaceId'), '/pipelines/Email Sender')]",
"[concat(variables('workspaceId'), '/pipelines/Throw Exception')]"
]
},
{
"name": "[concat(parameters('workspaceName'), '/Check For Running Pipeline')]",
"type": "Microsoft.Synapse/workspaces/pipelines",
"apiVersion": "2019-06-01-preview",
"properties": {
"description": "For a given pipeline and optional batch name establish if a pipeline run is already in progress. Throw an exception if it it.",
"activities": [
{
"name": "Filter Running Pipelines",
"description": "Filter the pipeline runs results for pipelines that exclude the current triggered run and that are currently running (in progress or queued).",
"type": "Filter",
"dependsOn": [
{
"activity": "Switch For Orchestrator Type",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@variables('PipelineRuns')",
"type": "Expression"
},
"condition": {
"value": "@and(not(equals(item().runId,pipeline().parameters.ThisRunId)),or(equals(item().status,'InProgress'),equals(item().status,'Queued')))",
"type": "Expression"
}
}
},
{
"name": "Get Framework Orchestrator Details",
"description": "Using the metadata orchestrators return details about the resource running the framework pipelines.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetFrameworkOrchestratorDetails]",
"storedProcedureParameters": {
"CallingOrchestratorName": {
"type": "String",
"value": {
"value": "@pipeline().DataFactory",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "Get Query Run Days Value",
"description": "Using the metadata properties table return the run days value to provide the API request with a date range for pipeline executions.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "PreviousPipelineRunsQueryRange"
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "If Pipeline Is Running",
"description": "If the running pipeline count is greater than or equal to one.\nTrue = raise an exception.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "If Using Batch Executions",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@greaterOrEquals(int(variables('RunCount')),1)",
"type": "Expression"
},
"ifTrueActivities": [
{
"name": "Throw Exception - Pipeline Running",
"description": "Using the utils pipeline raise an exception to stop the new trigger while a run is already in progress.",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "Throw Exception",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"Message": {
"value": "@concat('Provided pipeline name (',pipeline().parameters.PipelineName,') still has a run in progress or queued given the query range parameters set in the properties table.')",
"type": "Expression"
}
}
}
}
]
}
},
{
"name": "Get Execution Batch Status",
"description": "Using the metadata properties table return the flag to indicate if batch execution setting are enabled or disabled.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "UseExecutionBatches"
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
}
}
},
{
"name": "If Using Batch Executions",
"description": "True = batch executions are enabled.\nFalse = batch execution are disabled.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Get Execution Batch Status",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Filter Running Pipelines",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@equals(activity('Get Execution Batch Status').output.firstRow.PropertyValue,string(1))",
"type": "Expression"
},
"ifFalseActivities": [
{
"name": "Set Run Count Without Batch",
"description": "Set the pipelines running count variable to be tested later.",
"type": "SetVariable",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"variableName": "RunCount",
"value": {
"value": "@string(activity('Filter Running Pipelines').output.FilteredItemsCount)",
"type": "Expression"
}
}
}
],
"ifTrueActivities": [
{
"name": "Filter for Batch Name",
"description": "Further filter the return pipeline runs for any running pipelines with the same batch name value.",
"type": "Filter",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Filter Running Pipelines').output.value",
"type": "Expression"
},
"condition": {
"value": "@equals(item().parameters.BatchName,pipeline().parameters.BatchName)",
"type": "Expression"
}
}
},
{
"name": "Set Run Count for Batch",
"description": "Set the resulting pipeline running count variable to be tested later.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Filter for Batch Name",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "RunCount",
"value": {
"value": "@string(activity('Filter for Batch Name').output.FilteredItemsCount)",
"type": "Expression"
}
}
}
]
}
},
{
"name": "Set Subscription Id",
"description": "Set the subscription Id value to a local variable for use in various downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Framework Orchestrator Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "SubscriptionId",
"value": {
"value": "@activity('Get Framework Orchestrator Details').output.firstRow.SubscriptionId",
"type": "Expression"
}
}
},
{
"name": "Set Resource Group Name",
"description": "Set the resource group name value to a local variable for use in various downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Framework Orchestrator Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "ResourceGroupName",
"value": {
"value": "@activity('Get Framework Orchestrator Details').output.firstRow.ResourceGroupName",
"type": "Expression"
}
}
},
{
"name": "Set Orchestrator Type",
"description": "Set the orchestrator type value to a local variable for use in various downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Framework Orchestrator Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "OrchestratorType",
"value": {
"value": "@toUpper(activity('Get Framework Orchestrator Details').output.firstRow.OrchestratorType)",
"type": "Expression"
}
}
},
{
"name": "Switch For Orchestrator Type",
"description": "Switch and handle requests for both Azure Data Factory (ADF) and Azure Synapse Analytics (SYN).",
"type": "Switch",
"dependsOn": [
{
"activity": "Set Orchestrator Type",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Query Run Days",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Resource Group Name",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Subscription Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"on": {
"value": "@variables('OrchestratorType')",
"type": "Expression"
},
"cases": [
{
"value": "ADF",
"activities": [
{
"name": "Check for Valid ADF Pipeline Name",
"description": "Use the Azure Management API to return and establish if the framework pipeline exists in the target Data Factory instance, including being deployed.",
"type": "WebActivity",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"url": {
"value": "https://management.azure.com/subscriptions/@{variables('SubscriptionId')}/resourceGroups/@{variables('ResourceGroupName')}/providers/Microsoft.DataFactory/factories/@{pipeline().DataFactory}/pipelines/@{pipeline().parameters.PipelineName}?api-version=2018-06-01",
"type": "Expression"
},
"method": "GET",
"headers": {},
"authentication": {
"type": "MSI",
"resource": "https://management.core.windows.net/"
}
}
},
{
"name": "Get ADF Pipeline Runs",
"description": "Use the Azure Management API to return a list of data factory pipeline runs within the given time window.",
"type": "WebActivity",
"dependsOn": [
{
"activity": "Check for Valid ADF Pipeline Name",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"url": {
"value": "https://management.azure.com/subscriptions/@{variables('SubscriptionId')}/resourceGroups/@{variables('ResourceGroupName')}/providers/Microsoft.DataFactory/factories/@{pipeline().DataFactory}/queryPipelineRuns?api-version=2018-06-01",
"type": "Expression"
},
"method": "POST",
"headers": {},
"body": {
"value": "{\n \"lastUpdatedAfter\": \"@{adddays(utcnow(),int(variables('QueryRunDays')))}\",\n \"lastUpdatedBefore\": \"@{utcnow()}\",\n \"filters\": [\n {\n \"operand\": \"PipelineName\",\n \"operator\": \"Equals\",\n \"values\": [\n \"@{pipeline().parameters.PipelineName}\"\n ]\n }\n ]\n}",
"type": "Expression"
},
"authentication": {
"type": "MSI",
"resource": "https://management.core.windows.net/"
}
}
},
{
"name": "Set ADF Runs Output",
"description": "Set output to local array for use in downstream filtering and pipeline checks. Use the same array output for both switch cases.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get ADF Pipeline Runs",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "PipelineRuns",
"value": {
"value": "@activity('Get ADF Pipeline Runs').output.value",
"type": "Expression"
}
}
}
]
},
{
"value": "SYN",
"activities": [
{
"name": "Check for Valid SYN Pipeline Name",
"description": "Use the Azure Management API to return and establish if the framework pipeline exists in the target Synapse instance, including being deployed.\n\nSee: https://docs.microsoft.com/en-us/rest/api/synapse/data-plane/pipeline/getpipeline",
"type": "WebActivity",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"url": {
"value": "https://@{pipeline().DataFactory}.dev.azuresynapse.net/pipelines/@{pipeline().parameters.PipelineName}?api-version=2019-06-01-preview",
"type": "Expression"
},
"method": "GET",
"headers": {},
"authentication": {
"type": "MSI",
"resource": "https://management.core.windows.net/"
}
}
},
{
"name": "Get SYN Pipeline Runs",
"description": "Use the Azure Management API to return a list of synapse pipeline runs within the given time window.\n\nSee: https://docs.microsoft.com/en-us/rest/api/synapse/data-plane/pipelinerun/querypipelinerunsbyworkspace",
"type": "WebActivity",
"dependsOn": [
{
"activity": "Check for Valid SYN Pipeline Name",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"url": {
"value": "https://@{pipeline().DataFactory}.dev.azuresynapse.net/queryPipelineRuns?api-version=2019-06-01-preview",
"type": "Expression"
},
"method": "POST",
"headers": {},
"body": {
"value": "{\n \"lastUpdatedAfter\": \"@{adddays(utcnow(),int(variables('QueryRunDays')))}\",\n \"lastUpdatedBefore\": \"@{utcnow()}\",\n \"filters\": [\n {\n \"operand\": \"PipelineName\",\n \"operator\": \"Equals\",\n \"values\": [\n \"@{pipeline().parameters.PipelineName}\"\n ]\n }\n ]\n}",
"type": "Expression"
},
"authentication": {
"type": "MSI",
"resource": "https://management.core.windows.net/"
}
}
},
{
"name": "Set SYN Runs Output",
"description": "Set output to local array for use in downstream filtering and pipeline checks. Use the same array output for both switch cases.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get SYN Pipeline Runs",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "PipelineRuns",
"value": {
"value": "@activity('Get SYN Pipeline Runs').output.value",
"type": "Expression"
}
}
}
]
}
],
"defaultActivities": [
{
"name": "Throw Exception Invalid Orchestrator Type",
"description": "Throw exception if switch cases are not met.",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "Throw Exception",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"Message": "Invalid orchestrator type provided. Unable to check pipeline running state."
}
}
}
]
}
},
{
"name": "Set Query Run Days",
"description": "Set the query run days value to a local variable for use in various downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Query Run Days Value",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "QueryRunDays",
"value": {
"value": "@activity('Get Query Run Days Value').output.firstRow.PropertyValue",
"type": "Expression"
}
}
}
],
"parameters": {
"BatchName": {
"type": "string",
"defaultValue": "NotUsed"
},
"PipelineName": {
"type": "string"
},
"ThisRunId": {
"type": "string"
}
},
"variables": {
"SubscriptionId": {
"type": "String"
},
"RunCount": {
"type": "String"
},
"ResourceGroupName": {
"type": "String"
},
"OrchestratorType": {
"type": "String"
},
"QueryRunDays": {
"type": "String"
},
"PipelineRuns": {
"type": "Array"
}
},
"folder": {
"name": "_ProcFwk/_ProcFwkUtils"
},
"annotations": [
"procfwk",
"Utils"
]
},
"dependsOn": [
"[concat(variables('workspaceId'), '/datasets/GetSetMetadata')]",
"[concat(variables('workspaceId'), '/pipelines/Throw Exception')]"
]
},
{
"name": "[concat(parameters('workspaceName'), '/Email Sender')]",
"type": "Microsoft.Synapse/workspaces/pipelines",
"apiVersion": "2019-06-01-preview",
"properties": {
"description": "Provide a simple abstract over the send email function with request body item exposed as pipeline parameters.",
"activities": [
{
"name": "Send Email",
"description": "Use an Azure Function to perform an SMTP client email send operation.",
"type": "AzureFunctionActivity",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "SendEmail",
"method": "POST",
"headers": {},
"body": {
"value": "{\n\"emailRecipients\": \"@{pipeline().parameters.Recipients}\",\n\"emailCcRecipients\": \"@{pipeline().parameters.CcRecipients}\",\n\"emailBccRecipients\": \"@{pipeline().parameters.BccRecipients}\",\n\"emailSubject\": \"@{pipeline().parameters.Subject}\",\n\"emailBody\": \"@{pipeline().parameters.Body}\",\n\"emailImportance\": \"@{pipeline().parameters.Importance}\"\n}",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
}
],
"parameters": {
"Recipients": {
"type": "string"
},
"CcRecipients": {
"type": "string"
},
"BccRecipients": {
"type": "string"
},
"Subject": {
"type": "string"
},
"Body": {
"type": "string"
},
"Importance": {
"type": "string"
}
},
"folder": {
"name": "_ProcFwk/_ProcFwkUtils"
},
"annotations": [
"procfwk",
"Utils"
]
},
"dependsOn": [
"[concat(variables('workspaceId'), '/linkedServices/FrameworkFunctions')]"
]
},
{
"name": "[concat(parameters('workspaceName'), '/Intentional Error')]",
"type": "Microsoft.Synapse/workspaces/pipelines",
"apiVersion": "2019-06-01-preview",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait1",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
},
{
"name": "Raise Errors or Not",
"description": "Framework development worker simulator.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Wait1",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@equals(pipeline().parameters.RaiseErrors,'true')",
"type": "Expression"
},
"ifTrueActivities": [
{
"name": "Call Fail Procedure",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[[dbo].[FailProcedure]",
"storedProcedureParameters": {
"RaiseError": {
"value": {
"value": "@pipeline().parameters.RaiseErrors",
"type": "Expression"
},
"type": "String"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
}
],
"parameters": {
"RaiseErrors": {
"type": "string",
"defaultValue": "false"
},
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
},
"dependsOn": [
"[concat(variables('workspaceId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('workspaceName'), '/Throw Exception')]",
"type": "Microsoft.Synapse/workspaces/pipelines",
"apiVersion": "2019-06-01-preview",
"properties": {
"description": "Provide a simple way of throwing an exception within Data Factory using TSQL error handling.",
"activities": [
{
"name": "Raise Error",
"description": "Using a SQL database to raise an error/exception but wrapped up as a data factory pipeline. Error message information exposed as a pipeline parameter.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderQuery": {
"value": "RAISERROR('@{pipeline().parameters.Message}',16,1);",
"type": "Expression"
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference",
"parameters": {}
},
"firstRowOnly": false
}
}
],
"parameters": {
"Message": {
"type": "string"
}
},
"folder": {
"name": "_ProcFwk/_ProcFwkUtils"
},
"annotations": [
"procfwk",
"Utils"
]
},
"dependsOn": [
"[concat(variables('workspaceId'), '/datasets/GetSetMetadata')]"
]
},
{
"name": "[concat(parameters('workspaceName'), '/Wait 1')]",
"type": "Microsoft.Synapse/workspaces/pipelines",
"apiVersion": "2019-06-01-preview",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait1",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('workspaceName'), '/Wait 10')]",
"type": "Microsoft.Synapse/workspaces/pipelines",
"apiVersion": "2019-06-01-preview",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait10",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('workspaceName'), '/Wait 2')]",
"type": "Microsoft.Synapse/workspaces/pipelines",
"apiVersion": "2019-06-01-preview",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait2",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('workspaceName'), '/Wait 3')]",
"type": "Microsoft.Synapse/workspaces/pipelines",
"apiVersion": "2019-06-01-preview",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait3",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('workspaceName'), '/Wait 4')]",
"type": "Microsoft.Synapse/workspaces/pipelines",
"apiVersion": "2019-06-01-preview",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait4",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('workspaceName'), '/Wait 5')]",
"type": "Microsoft.Synapse/workspaces/pipelines",
"apiVersion": "2019-06-01-preview",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait5",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('workspaceName'), '/Wait 6')]",
"type": "Microsoft.Synapse/workspaces/pipelines",
"apiVersion": "2019-06-01-preview",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait6",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('workspaceName'), '/Wait 7')]",
"type": "Microsoft.Synapse/workspaces/pipelines",
"apiVersion": "2019-06-01-preview",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait7",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('workspaceName'), '/Wait 8')]",
"type": "Microsoft.Synapse/workspaces/pipelines",
"apiVersion": "2019-06-01-preview",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait8",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('workspaceName'), '/Wait 9')]",
"type": "Microsoft.Synapse/workspaces/pipelines",
"apiVersion": "2019-06-01-preview",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait9",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 15
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
},
"dependsOn": []
},
{
"name": "[concat(parameters('workspaceName'), '/GetSetMetadata')]",
"type": "Microsoft.Synapse/workspaces/datasets",
"apiVersion": "2019-06-01-preview",
"properties": {
"description": "Single generic dataset used to get and set all database metadata.",
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"procfwk"
],
"type": "AzureSqlTable",
"schema": [],
"typeProperties": {}
},
"dependsOn": [
"[concat(variables('workspaceId'), '/linkedServices/SupportDatabase')]"
]
},
{
"name": "[concat(parameters('workspaceName'), '/FrameworkFunctions')]",
"type": "Microsoft.Synapse/workspaces/linkedServices",
"apiVersion": "2019-06-01-preview",
"properties": {
"description": "Interact with the Azure Functions App used as middle ware when making requests to Worker pipelines. Authentication done at the Function App level.",
"annotations": [
"procfwk"
],
"type": "AzureFunction",
"typeProperties": {
"functionAppUrl": "[parameters('FrameworkFunctions_properties_typeProperties_functionAppUrl')]",
"functionKey": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "FrameworkFunctionsKey"
}
}
},
"dependsOn": [
"[concat(variables('workspaceId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('workspaceName'), '/Keys')]",
"type": "Microsoft.Synapse/workspaces/linkedServices",
"apiVersion": "2019-06-01-preview",
"properties": {
"description": "Connection to Key Vault for all other ADF linked service credentials required to run the processing framework.",
"annotations": [
"procfwk"
],
"type": "AzureKeyVault",
"typeProperties": {
"baseUrl": "[parameters('Keys_properties_typeProperties_baseUrl')]"
}
},
"dependsOn": []
},
{
"name": "[concat(parameters('workspaceName'), '/SupportDatabase')]",
"type": "Microsoft.Synapse/workspaces/linkedServices",
"apiVersion": "2019-06-01-preview",
"properties": {
"description": "Connection between ADF and processing framework metadata SQLDB.",
"annotations": [
"procfwk"
],
"type": "AzureSqlDatabase",
"typeProperties": {
"connectionString": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "[parameters('SupportDatabase_properties_typeProperties_connectionString_secretName')]"
}
}
},
"dependsOn": [
"[concat(variables('workspaceId'), '/linkedServices/Keys')]"
]
},
{
"name": "[concat(parameters('workspaceName'), '/procfwkforsynapse-WorkspaceDefaultSqlServer')]",
"type": "Microsoft.Synapse/workspaces/linkedServices",
"apiVersion": "2019-06-01-preview",
"properties": {
"parameters": {
"DBName": {
"type": "String"
}
},
"annotations": [],
"type": "AzureSqlDW",
"typeProperties": {
"connectionString": "[parameters('procfwkforsynapse-WorkspaceDefaultSqlServer_connectionString')]"
},
"connectVia": {
"referenceName": "AutoResolveIntegrationRuntime",
"type": "IntegrationRuntimeReference"
}
},
"dependsOn": [
"[concat(variables('workspaceId'), '/integrationRuntimes/AutoResolveIntegrationRuntime')]"
]
},
{
"name": "[concat(parameters('workspaceName'), '/procfwkforsynapse-WorkspaceDefaultStorage')]",
"type": "Microsoft.Synapse/workspaces/linkedServices",
"apiVersion": "2019-06-01-preview",
"properties": {
"annotations": [],
"type": "AzureBlobFS",
"typeProperties": {
"url": "[parameters('procfwkforsynapse-WorkspaceDefaultStorage_properties_typeProperties_url')]"
},
"connectVia": {
"referenceName": "AutoResolveIntegrationRuntime",
"type": "IntegrationRuntimeReference"
}
},
"dependsOn": [
"[concat(variables('workspaceId'), '/integrationRuntimes/AutoResolveIntegrationRuntime')]"
]
},
{
"name": "[concat(parameters('workspaceName'), '/FunctionalTestingTrigger')]",
"type": "Microsoft.Synapse/workspaces/triggers",
"apiVersion": "2019-06-01-preview",
"properties": {
"description": "Used for functional testing of the framework in a dedicated environment.",
"annotations": [
"procfwk"
],
"runtimeState": "Stopped",
"pipelines": [
{
"pipelineReference": {
"referenceName": "01-Grandparent",
"type": "PipelineReference"
},
"parameters": {}
}
],
"type": "ScheduleTrigger",
"typeProperties": {
"recurrence": {
"frequency": "Hour",
"interval": 2,
"startTime": "2020-04-06T15:00:00Z",
"timeZone": "UTC"
}
}
},
"dependsOn": [
"[concat(variables('workspaceId'), '/pipelines/01-Grandparent')]"
]
},
{
"name": "[concat(parameters('workspaceName'), '/AutoResolveIntegrationRuntime')]",
"type": "Microsoft.Synapse/workspaces/integrationRuntimes",
"apiVersion": "2019-06-01-preview",
"properties": {
"type": "Managed",
"typeProperties": {
"computeProperties": {
"location": "AutoResolve",
"dataFlowProperties": {
"computeType": "General",
"coreCount": 8,
"timeToLive": 0
}
}
}
},
"dependsOn": []
}
]
}
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at paul@mrpaulandrew.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq
================================================
FILE: CONTRIBUTING.md
================================================
If you'd like to contribute towards this code project please contact me. I kindly request a minimum of 5 years experience working with Azure Data Platform services.
Thanks
Paul
================================================
FILE: DataFactory/dataset/GetSetMetadata.json
================================================
{
"name": "GetSetMetadata",
"properties": {
"description": "Single generic dataset used to get and set all database metadata.",
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"procfwk"
],
"type": "AzureSqlTable",
"schema": []
}
}
================================================
FILE: DataFactory/factory/FrameworkFactory.json
================================================
{
"name": "FrameworkFactory",
"properties": {
"globalConfigurations": {
"PipelineBillingEnabled": "true"
}
},
"location": "uksouth"
}
================================================
FILE: DataFactory/integrationRuntime/AzureIR-UKSouth.json
================================================
{
"name": "AzureIR-UKSouth",
"properties": {
"type": "Managed",
"typeProperties": {
"computeProperties": {
"location": "UK South",
"dataFlowProperties": {
"computeType": "General",
"coreCount": 8,
"timeToLive": 10,
"cleanup": false
}
}
}
}
}
================================================
FILE: DataFactory/linkedService/FrameworkFunctions.json
================================================
{
"name": "FrameworkFunctions",
"properties": {
"annotations": [
"procfwk"
],
"type": "AzureFunction",
"typeProperties": {
"functionAppUrl": "https://frameworksupportfunctions.azurewebsites.net",
"functionKey": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "FrameworkFunctionsKey"
}
},
"description": "Interact with the Azure Functions App used as middle ware when making requests to Worker pipelines. Authentication done at the Function App level."
}
}
================================================
FILE: DataFactory/linkedService/Keys.json
================================================
{
"name": "Keys",
"properties": {
"annotations": [
"procfwk"
],
"type": "AzureKeyVault",
"typeProperties": {
"baseUrl": "https://FrameworkKeys.vault.azure.net/"
},
"description": "Connection to Key Vault for all other ADF linked service credentials required to run the processing framework."
}
}
================================================
FILE: DataFactory/linkedService/SupportDatabase.json
================================================
{
"name": "SupportDatabase",
"properties": {
"description": "Connection between ADF and processing framework metadata SQLDB.",
"annotations": [
"procfwk"
],
"type": "AzureSqlDatabase",
"typeProperties": {
"connectionString": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "FrameworkMetadataDev"
}
}
}
}
================================================
FILE: DataFactory/pipeline/01-Grandparent.json
================================================
{
"name": "01-Grandparent",
"properties": {
"description": "procfwk grandparent pipeline used optionally to bootstrap any wider processes in your Data Factory that then calls the processing framework.",
"activities": [
{
"name": "procfwk",
"description": "Call procfwk",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "02-Parent",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"BatchName": {
"value": "@pipeline().parameters.BatchName",
"type": "Expression"
}
}
}
}
],
"parameters": {
"BatchName": {
"type": "string",
"defaultValue": "NotUsed"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"procfwk",
"Grandparent"
]
}
}
================================================
FILE: DataFactory/pipeline/02-Parent.json
================================================
{
"name": "02-Parent",
"properties": {
"description": "ADF.procfwk parent pipeline used to bootstrap the orchestration framework in perform the first level ForEach calls in sequence for the metadata stages.",
"activities": [
{
"name": "Get Stages",
"description": "Returns a distinct list of execution stages within the framework metadata.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Set Execution Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[procfwk].[GetStages]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@variables('ExecutionId')",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference"
},
"firstRowOnly": false
}
},
{
"name": "Execute Stages",
"description": "Top level ForEach to sequentially call all processing stages within the framework metadata. Items for iteration passed from the Get Stages lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Stages",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Stages').output.value",
"type": "Expression"
},
"isSequential": true,
"activities": [
{
"name": "Stage Executor",
"description": "Call to the framework generic child pipeline for a given execution stage.",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Log Stage Preparing",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "03-Child",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"StageId": {
"value": "@item().StageId",
"type": "Expression"
},
"ExecutionId": {
"value": "@variables('ExecutionId')",
"type": "Expression"
}
}
}
},
{
"name": "Log Stage Preparing",
"description": "Update the current execution table flagging all pipelines within the stage as preparing.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Check and Update Blockers",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogStagePreparing]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@variables('ExecutionId')",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check and Update Blockers",
"description": "Used to double check and stop the next execution stage if failures and blockers have be incurred. This also depends on the failure handling property value which defines the stored procedure behaviour.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[CheckForBlockedPipelines]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@variables('ExecutionId')",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Execution Wrapper",
"description": "Wrapper to reset and restart processing or create a completely new execution instance of the framework metadata.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Clean Up Previous Run",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[procfwk].[ExecutionWrapper]",
"storedProcedureParameters": {
"CallingOrchestratorName": {
"type": "String",
"value": {
"value": "@pipeline().DataFactory",
"type": "Expression"
}
},
"BatchName": {
"type": "String",
"value": {
"value": "@pipeline().parameters.BatchName",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference"
}
}
},
{
"name": "Check Outcome and Update Logs",
"description": "After a successful execution run the current execution metadata is moved to the long term logging table by this stored procedure call. Otherwise an error will be raised.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Stages",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[UpdateExecutionLog]",
"storedProcedureParameters": {
"PerformErrorCheck": {
"value": {
"value": "@bool(1)",
"type": "Expression"
},
"type": "Boolean"
},
"ExecutionId": {
"value": {
"value": "@variables('ExecutionId')",
"type": "Expression"
},
"type": "Guid"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check Previous Execution",
"description": "Query the current execution table for worker pipelines that require a clean up from the previous execution run.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Execute Precursor",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[procfwk].[CheckPreviousExeuction]",
"storedProcedureParameters": {
"BatchName": {
"type": "String",
"value": {
"value": "@pipeline().parameters.BatchName",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference"
},
"firstRowOnly": false
}
},
{
"name": "Clean Up Previous Run",
"description": "Handle Worker pipelines that are reported as Running when the parent pipeline is called again. Get what the actual status of those pipelines is.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Check Previous Execution",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Check Metadata Integrity",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Check Previous Execution').output.value",
"type": "Expression"
},
"isSequential": false,
"batchCount": 50,
"activities": [
{
"name": "Get SPN Details",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": true,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[procfwk].[GetWorkerAuthDetails]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
}
},
"PipelineId": {
"type": "Int32",
"value": {
"value": "@item().PipelineId",
"type": "Expression"
}
},
"StageId": {
"type": "Int32",
"value": {
"value": "@item().StageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference"
}
}
},
{
"name": "Log Pipeline Checking",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogPipelineChecking]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Pipeline Status",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Get SPN Details",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Log Pipeline Checking",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"functionName": "CheckPipelineStatus",
"method": "POST",
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',activity('Get SPN Details').output.firstRow.TenantId,'\",\n \"applicationId\": \"',activity('Get SPN Details').output.firstRow.AppId,'\",\n \"authenticationKey\": \"',activity('Get SPN Details').output.firstRow.AppSecret,'\",\n \"subscriptionId\": \"',activity('Get SPN Details').output.firstRow.SubscriptionId,'\",\n \"resourceGroupName\": \"',item().ResourceGroupName,'\",\n \"orchestratorName\": \"',item().OrchestratorName,'\",\n \"orchestratorType\": \"',item().OrchestratorType,'\",\n \"pipelineName\": \"',item().PipelineName,'\",\n \"runId\": \"',item().PipelineRunId,'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Set Pipeline Status",
"description": "Update the metadata depending on the actual pipeline outcome. Using the status as the case.",
"type": "Switch",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"on": {
"value": "@activity('Get Pipeline Status').output.ActualStatus",
"type": "Expression"
},
"cases": [
{
"value": "Failed",
"activities": [
{
"name": "Pipeline Status Failed",
"description": "Updates the current execution table with a pipeline status of failed if the function outcome is failed. Also blocks pipelines in the downstream execution stage.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogPipelineFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": null,
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Succeeded",
"activities": [
{
"name": "Pipeline Status Succeeded",
"description": "Updates the current execution table with a pipeline status of success if the function outcome is succeeded.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogPipelineSuccess]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Queued",
"activities": [
{
"name": "Pipeline Status Queued - Running",
"description": "Updates the current execution table with a pipeline status of running if the function outcome is queued.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "InProgress",
"activities": [
{
"name": "Pipeline Status InProgress - Running",
"description": "Updates the current execution table with a pipeline status of running if the function outcome is in progress.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Cancelled",
"activities": [
{
"name": "Pipeline Status Cancelled",
"description": "Updates the current execution table with a pipeline status of cancelled if the function outcome is cancelled.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogPipelineCancelled]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
},
"CleanUpRun": {
"value": {
"value": "@bool(1)",
"type": "Expression"
},
"type": "Boolean"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
],
"defaultActivities": [
{
"name": "Pipeline Status Unknown",
"description": "Updates the current execution table with a pipeline status of unknown if the function returns an unexpected outcome.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogPipelineUnknown]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
},
"CleanUpRun": {
"value": {
"value": "@bool(1)",
"type": "Expression"
},
"type": "Boolean"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Set Last Check DateTime",
"description": "Update the current execution table with a date time from when the function last checked the pipeline status.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogPipelineLastStatusCheck]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Execute Precursor",
"description": "Uses the database property value ExecutionPrecursorProc to run any custom logic against the metadata database before the execution run starts.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Is Parent Already Running",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[ExecutePrecursorProcedure]"
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Set Execution Id",
"description": "Set the local execution Id to a pipeline variable for each in several downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Execution Wrapper",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "ExecutionId",
"value": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
}
}
},
{
"name": "Is Parent Already Running",
"description": "Establish before anything else if the parent pipeline is already running. Batch execution aware.",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "Check For Running Pipeline",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"BatchName": {
"value": "@pipeline().parameters.BatchName",
"type": "Expression"
},
"PipelineName": {
"value": "@pipeline().Pipeline",
"type": "Expression"
},
"ThisRunId": {
"value": "@pipeline().RunId",
"type": "Expression"
}
}
}
},
{
"name": "Check Metadata Integrity",
"description": "Performs a series of checks on all metadata held in the framework SQLDB. This is intended to raise errors before an execution run even starts.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Precursor",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[CheckMetadataIntegrity]",
"storedProcedureParameters": {
"BatchName": {
"value": {
"value": "@pipeline().parameters.BatchName",
"type": "Expression"
},
"type": "String"
},
"DebugMode": {
"value": {
"value": "@bool(0)",
"type": "Expression"
},
"type": "Boolean"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
],
"parameters": {
"BatchName": {
"type": "string",
"defaultValue": "NotUsed"
}
},
"variables": {
"ExecutionId": {
"type": "String"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"procfwk",
"Parent"
]
}
}
================================================
FILE: DataFactory/pipeline/03-Child.json
================================================
{
"name": "03-Child",
"properties": {
"description": "procfwk child pipeline used to execute Worker pipelines within a given execution stage. This pipeline will be called once for each stage, then execute all Workers in parallel.",
"activities": [
{
"name": "Get Pipelines",
"description": "Returns all pipelines from the metadata to be executed within a given processing stage.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[procfwk].[GetPipelinesInStage]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
}
},
"StageId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference"
},
"firstRowOnly": false
}
},
{
"name": "Execute Pipelines",
"description": "Second level ForEach to run in parallel all pipelines within the stage. Items for iteration passed from the Get Pipelines lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Pipelines",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Pipelines').output.value",
"type": "Expression"
},
"isSequential": false,
"batchCount": 50,
"activities": [
{
"name": "Worker Pipeline Executor",
"description": "Run the required worker pipeline and wait for its completion. Update metadata once done.",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "04-Infant",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"executionId": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"stageId": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"pipelineId": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
}
}
]
}
}
],
"parameters": {
"StageId": {
"type": "int"
},
"ExecutionId": {
"type": "string"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"procfwk",
"Child"
]
}
}
================================================
FILE: DataFactory/pipeline/04-Infant.json
================================================
{
"name": "04-Infant",
"properties": {
"description": "procfwk infant pipeline used to check when the processing pipeline called by the Child completes and passes the resulting status back to the metadata database.",
"activities": [
{
"name": "Execute Worker Pipeline",
"description": "The lowest level executor with the metadata framework to call existing processing pipelines within Data Factory. The function called will block processing and wait for an outcome.",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Log Pipeline Running",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Pipeline Params",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"functionName": "ExecutePipeline",
"method": "POST",
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',variables('WorkerCoreDetails')[0].tenantId,'\",\n \"applicationId\": \"',variables('WorkerCoreDetails')[0].applicationId,'\",\n \"authenticationKey\": \"',variables('WorkerCoreDetails')[0].authenticationKey,'\",\n \"subscriptionId\": \"',variables('WorkerCoreDetails')[0].subscriptionId,'\",\n \"resourceGroupName\": \"',variables('WorkerCoreDetails')[0].resourceGroupName,'\",\n\t\"orchestratorName\": \"',variables('WorkerCoreDetails')[0].orchestratorName,'\",\n \"orchestratorType\": \"',variables('WorkerCoreDetails')[0].orchestratorType,'\",\n \"pipelineName\": \"',variables('WorkerCoreDetails')[0].pipelineName,'\"',activity('Get Pipeline Params').output.firstRow.Params,'\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Pipeline Params",
"description": "Returns any parameters from metadata required for the processing pipeline being called. The output can be an empty string if no parameters are required.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[procfwk].[GetPipelineParameters]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference"
}
}
},
{
"name": "Log Pipeline Running",
"description": "Sets the current pipeline with a status of running within the current execution database table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Is Target Worker Validate",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Execute Function Activity Failure",
"description": "Handle true failures from calling out to the Azure Function and update the current execution table accordingly so a restart can occur.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Worker Pipeline",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
},
"CallingActivity": {
"value": "ExecuteWorkerPipeline",
"type": "String"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Update Run Id",
"description": "Provide the actual ADF run ID back to the current execution table for long term logging and alignment between the metadata other Azure monitoring tools.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Set Run Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogPipelineRunId]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@variables('WorkerRunId')",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check For Alerts",
"description": "Checks the properties tables and if any recipients in the database require alerts sending for the current pipeline ID.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Update Run Id",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Pipeline Result",
"dependencyConditions": [
"Completed"
]
}
],
"policy": {
"timeout": "0.00:00:30",
"retry": 3,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[procfwk].[CheckForEmailAlerts]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference"
},
"firstRowOnly": true
}
},
{
"name": "Send Alerts",
"description": "True = alerts need sending.\nFalse = do nothing.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Check For Alerts",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@activity('Check For Alerts').output.firstRow.SendAlerts",
"type": "Expression"
},
"ifTrueActivities": [
{
"name": "Get Email Parts",
"description": "Return all required content from the metadata database to send an email alerting using the procfwk. The lookup returns the exact content for the function body request.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": true,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[procfwk].[GetEmailAlertParts]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference"
},
"firstRowOnly": true
}
},
{
"name": "Call Email Sender",
"description": "Pass off email request to Utils Send Email pipeline.",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Get Email Parts",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "Email Sender",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"Recipients": {
"value": "@activity('Get Email Parts').output.firstRow.emailRecipients",
"type": "Expression"
},
"CcRecipients": {
"value": "@activity('Get Email Parts').output.firstRow.emailCcRecipients",
"type": "Expression"
},
"BccRecipients": {
"value": "@activity('Get Email Parts').output.firstRow.emailBccRecipients",
"type": "Expression"
},
"Subject": {
"value": "@activity('Get Email Parts').output.firstRow.emailSubject",
"type": "Expression"
},
"Body": {
"value": "@activity('Get Email Parts').output.firstRow.emailBody",
"type": "Expression"
},
"Importance": {
"value": "@activity('Get Email Parts').output.firstRow.emailImportance",
"type": "Expression"
}
}
}
}
]
}
},
{
"name": "Wait Until Pipeline Completes",
"description": "Loops until the Worker pipeline called completes.\n\nSimple status:\n- Running = new iteration.\n- Done = break.",
"type": "Until",
"dependsOn": [
{
"activity": "Get Wait Duration",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Execute Worker Pipeline",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Run Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@variables('WorkerPipelineState')",
"type": "Expression"
},
"activities": [
{
"name": "Get Worker Pipeline Status",
"description": "Checks the status of a given processing pipeline and provides the value for the downstream framework activities to act upon.",
"type": "AzureFunctionActivity",
"dependsOn": [],
"policy": {
"timeout": "0.03:59:59",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"functionName": "CheckPipelineStatus",
"method": "POST",
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',variables('WorkerCoreDetails')[0].tenantId,'\",\n \"applicationId\": \"',variables('WorkerCoreDetails')[0].applicationId,'\",\n \"authenticationKey\": \"',variables('WorkerCoreDetails')[0].authenticationKey,'\",\n \"subscriptionId\": \"',variables('WorkerCoreDetails')[0].subscriptionId,'\",\n \"resourceGroupName\": \"',variables('WorkerCoreDetails')[0].resourceGroupName,'\",\n\t\"orchestratorName\": \"',variables('WorkerCoreDetails')[0].orchestratorName,'\",\n \"orchestratorType\": \"',variables('WorkerCoreDetails')[0].orchestratorType,'\",\n \"pipelineName\": \"',variables('WorkerCoreDetails')[0].pipelineName,'\",\n \"runId\": \"',variables('WorkerRunId'),'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Wait If Running",
"description": "True = Do nothing.\nFalse = Wait, before the next iteration.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Set Worker State",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@variables('WorkerPipelineState')",
"type": "Expression"
},
"ifFalseActivities": [
{
"name": "Wait for Pipeline",
"description": "The processing pipeline is still running so Wait before checking its status again.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@activity('Get Wait Duration').output.firstRow.PropertyValue",
"type": "Expression"
}
}
}
]
}
},
{
"name": "Set Last Check DateTime",
"description": "Update the current execution table with a date time from when the Worker pipeline status was last checked as part of the Until iterations.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Worker Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogPipelineLastStatusCheck]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Check Function Activity Failure",
"description": "Report to the current execution table that the framework pipeline activity has failed. This failure is outside of the scope of the framework and is probably related to a wider platform problem.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Worker Pipeline Status",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"CallingActivity": {
"value": "GetWorkerPipelineStatus",
"type": "String"
},
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Set Worker State",
"description": "Set the bool state of the Worker pipeline to be used by the Until and If expressions. True = Complete, False = Running.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Worker Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerPipelineState",
"value": {
"value": "@equals('Complete',activity('Get Worker Pipeline Status').output.SimpleStatus)",
"type": "Expression"
}
}
}
],
"timeout": "0.04:00:00"
}
},
{
"name": "Set Pipeline Result",
"description": "Receives the outcome from the function execution for a given processing pipeline and updates the current execution table with different pipelines status values depending on the result (case).",
"type": "Switch",
"dependsOn": [
{
"activity": "Wait Until Pipeline Completes",
"dependencyConditions": [
"Completed"
]
}
],
"userProperties": [],
"typeProperties": {
"on": {
"value": "@activity('Get Worker Pipeline Status').output.ActualStatus",
"type": "Expression"
},
"cases": [
{
"value": "Succeeded",
"activities": [
{
"name": "Pipeline Status Succeeded",
"description": "Updates the current execution table with a pipeline status of success if the function outcome is succeeded.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:01:00",
"retry": 2,
"retryIntervalInSeconds": 5,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogPipelineSuccess]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Failed",
"activities": [
{
"name": "Pipeline Status Failed",
"description": "Updates the current execution table with a pipeline status of failed if the function outcome is failed. Also blocks pipelines in the downstream execution stage.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:01:00",
"retry": 2,
"retryIntervalInSeconds": 5,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogPipelineFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@variables('WorkerRunId')",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Worker Pipeline Error Details",
"description": "Get the activity error details for the run ID of the worker pipeline called. Returns an array of all errors.",
"type": "AzureFunctionActivity",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"functionName": "GetActivityErrors",
"method": "POST",
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',variables('WorkerCoreDetails')[0].tenantId,'\",\n \"applicationId\": \"',variables('WorkerCoreDetails')[0].applicationId,'\",\n \"authenticationKey\": \"',variables('WorkerCoreDetails')[0].authenticationKey,'\",\n \"subscriptionId\": \"',variables('WorkerCoreDetails')[0].subscriptionId,'\",\n \"resourceGroupName\": \"',variables('WorkerCoreDetails')[0].resourceGroupName,'\",\n\t\"orchestratorName\": \"',variables('WorkerCoreDetails')[0].orchestratorName,'\",\n \"orchestratorType\": \"',variables('WorkerCoreDetails')[0].orchestratorType,'\",\n \"pipelineName\": \"',variables('WorkerCoreDetails')[0].pipelineName,'\",\n \"runId\": \"',variables('WorkerRunId'),'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Error Details",
"description": "Parses pipeline error details and persists them to the metadata database error log table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Worker Pipeline Error Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:01:00",
"retry": 2,
"retryIntervalInSeconds": 5,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetErrorLogDetails]",
"storedProcedureParameters": {
"JsonErrorDetails": {
"value": {
"value": "@string(activity('Get Worker Pipeline Error Details').output)",
"type": "Expression"
},
"type": "String"
},
"LocalExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Cancelled",
"activities": [
{
"name": "Pipeline Status Cancelled",
"description": "Updates the current execution table with a pipeline status of cancelled if the function outcome is cancelled.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:01:00",
"retry": 2,
"retryIntervalInSeconds": 5,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogPipelineCancelled]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
],
"defaultActivities": [
{
"name": "Pipeline Status Unknown",
"description": "Updates the current execution table with a pipeline status of unknown if the function returns an unexpected outcome.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:01:00",
"retry": 2,
"retryIntervalInSeconds": 5,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogPipelineUnknown]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Get Wait Duration",
"description": "Return wait duration in seconds from database properties table to be used during each Until iteration when the Worker pipeline is still running.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "PipelineStatusCheckDuration"
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference"
}
}
},
{
"name": "Set Run Id",
"description": "Set local variable from activity output once for value reuse in downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Execute Worker Pipeline",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerRunId",
"value": {
"value": "@activity('Execute Worker Pipeline').output.RunId",
"type": "Expression"
}
}
},
{
"name": "Validate Pipeline",
"description": "Query the target data factory and establish if the provided worker pipeline name is valid.",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Log Pipeline Validating",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Capture Worker Core Details as an Array",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"functionName": "ValidatePipeline",
"method": "POST",
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',variables('WorkerCoreDetails')[0].tenantId,'\",\n \"applicationId\": \"',variables('WorkerCoreDetails')[0].applicationId,'\",\n \"authenticationKey\": \"',variables('WorkerCoreDetails')[0].authenticationKey,'\",\n \"subscriptionId\": \"',variables('WorkerCoreDetails')[0].subscriptionId,'\",\n \"resourceGroupName\": \"',variables('WorkerCoreDetails')[0].resourceGroupName,'\",\n\t\"orchestratorName\": \"',variables('WorkerCoreDetails')[0].orchestratorName,'\",\n \"orchestratorType\": \"',variables('WorkerCoreDetails')[0].orchestratorType,'\",\n \"pipelineName\": \"',variables('WorkerCoreDetails')[0].pipelineName,'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Is Target Worker Validate",
"description": "True = the worker pipeline name is valid.\nFalse = the worker pipeline name is invalid. Raise an exception.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Validate Pipeline",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@bool(activity('Validate Pipeline').output.PipelineExists)",
"type": "Expression"
},
"ifFalseActivities": [
{
"name": "Throw Exception - Invalid Infant",
"description": "Throw an exception with details about the invalid worker pipeline name.",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "Throw Exception",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"Message": {
"value": "@concat('Worker pipeline [',variables('WorkerCoreDetails')[0].pipelineName,'] is not valid in target Orchestrator [',variables('WorkerCoreDetails')[0].orchestratorName,']')",
"type": "Expression"
}
}
}
},
{
"name": "Update Execution With Invalid Worker",
"description": "Update the current execution table with an informed status for the worker pipeline that couldn't be executed.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"CallingActivity": {
"value": "InvalidPipelineName",
"type": "String"
},
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Log Validate Function Activity Failure",
"description": "Handle true failures from calling out to the Azure Function and update the current execution table accordingly so a restart can occur.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Validate Pipeline",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
},
"CallingActivity": {
"value": "ValidatePipeline",
"type": "String"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Pipeline Validating",
"description": "Sets the current pipeline with a status of validating within the current execution database table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogPipelineValidating]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Worker Core Details",
"description": "Return worker pipeline information for metadata database. Including target data factory, pipeline name and resource group. Return the SPN ID and Secret for the worker pipeline being executed. Called at this level as each pipeline can have a different SPN.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": true,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[procfwk].[GetWorkerDetailsWrapper]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
}
},
"PipelineId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
}
},
"StageId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference"
}
}
},
{
"name": "Capture Worker Core Details as an Array",
"description": "Add all worker pipeline details to a local variable array that can be accessed by each function call requiring the values.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Worker Core Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerCoreDetails",
"value": {
"value": "@array(activity('Get Worker Core Details').output.firstRow)",
"type": "Expression"
}
}
}
],
"parameters": {
"executionId": {
"type": "string"
},
"stageId": {
"type": "int"
},
"pipelineId": {
"type": "int"
}
},
"variables": {
"WorkerPipelineState": {
"type": "Boolean"
},
"WorkerRunId": {
"type": "String"
},
"WorkerCoreDetails": {
"type": "Array"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"procfwk",
"Infant"
]
}
}
================================================
FILE: DataFactory/pipeline/Check For Running Pipeline.json
================================================
{
"name": "Check For Running Pipeline",
"properties": {
"description": "For a given pipeline and optional batch name establish if a pipeline run is already in progress. Throw an exception if it it.",
"activities": [
{
"name": "Filter Running Pipelines",
"description": "Filter the pipeline runs results for pipelines that exclude the current triggered run and that are currently running (in progress or queued).",
"type": "Filter",
"dependsOn": [
{
"activity": "Switch For Orchestrator Type",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@variables('PipelineRuns')",
"type": "Expression"
},
"condition": {
"value": "@and(not(equals(item().runId,pipeline().parameters.ThisRunId)),or(equals(item().status,'InProgress'),equals(item().status,'Queued')))",
"type": "Expression"
}
}
},
{
"name": "Get Framework Orchestrator Details",
"description": "Using the metadata orchestrators return details about the resource running the framework pipelines.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[procfwk].[GetFrameworkOrchestratorDetails]",
"storedProcedureParameters": {
"CallingOrchestratorName": {
"type": "String",
"value": {
"value": "@pipeline().DataFactory",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference"
}
}
},
{
"name": "Get Query Run Days Value",
"description": "Using the metadata properties table return the run days value to provide the API request with a date range for pipeline executions.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "PreviousPipelineRunsQueryRange"
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference"
}
}
},
{
"name": "If Pipeline Is Running",
"description": "If the running pipeline count is greater than or equal to one.\nTrue = raise an exception.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "If Using Batch Executions",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@greaterOrEquals(int(variables('RunCount')),1)",
"type": "Expression"
},
"ifTrueActivities": [
{
"name": "Throw Exception - Pipeline Running",
"description": "Using the utils pipeline raise an exception to stop the new trigger while a run is already in progress.",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "Throw Exception",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"Message": {
"value": "@concat('Provided pipeline name (',pipeline().parameters.PipelineName,') still has a run in progress or queued given the query range parameters set in the properties table.')",
"type": "Expression"
}
}
}
}
]
}
},
{
"name": "Get Execution Batch Status",
"description": "Using the metadata properties table return the flag to indicate if batch execution setting are enabled or disabled.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "UseExecutionBatches"
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference"
}
}
},
{
"name": "If Using Batch Executions",
"description": "True = batch executions are enabled.\nFalse = batch execution are disabled.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Get Execution Batch Status",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Filter Running Pipelines",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@equals(activity('Get Execution Batch Status').output.firstRow.PropertyValue,string(1))",
"type": "Expression"
},
"ifFalseActivities": [
{
"name": "Set Run Count Without Batch",
"description": "Set the pipelines running count variable to be tested later.",
"type": "SetVariable",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"variableName": "RunCount",
"value": {
"value": "@string(activity('Filter Running Pipelines').output.FilteredItemsCount)",
"type": "Expression"
}
}
}
],
"ifTrueActivities": [
{
"name": "Filter for Batch Name",
"description": "Further filter the return pipeline runs for any running pipelines with the same batch name value.",
"type": "Filter",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Filter Running Pipelines').output.value",
"type": "Expression"
},
"condition": {
"value": "@equals(item().parameters.BatchName,pipeline().parameters.BatchName)",
"type": "Expression"
}
}
},
{
"name": "Set Run Count for Batch",
"description": "Set the resulting pipeline running count variable to be tested later.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Filter for Batch Name",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "RunCount",
"value": {
"value": "@string(activity('Filter for Batch Name').output.FilteredItemsCount)",
"type": "Expression"
}
}
}
]
}
},
{
"name": "Set Subscription Id",
"description": "Set the subscription Id value to a local variable for use in various downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Framework Orchestrator Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "SubscriptionId",
"value": {
"value": "@activity('Get Framework Orchestrator Details').output.firstRow.SubscriptionId",
"type": "Expression"
}
}
},
{
"name": "Set Resource Group Name",
"description": "Set the resource group name value to a local variable for use in various downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Framework Orchestrator Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "ResourceGroupName",
"value": {
"value": "@activity('Get Framework Orchestrator Details').output.firstRow.ResourceGroupName",
"type": "Expression"
}
}
},
{
"name": "Set Orchestrator Type",
"description": "Set the orchestrator type value to a local variable for use in various downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Framework Orchestrator Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "OrchestratorType",
"value": {
"value": "@toUpper(activity('Get Framework Orchestrator Details').output.firstRow.OrchestratorType)",
"type": "Expression"
}
}
},
{
"name": "Switch For Orchestrator Type",
"description": "Switch and handle requests for both Azure Data Factory (ADF) and Azure Synapse Analytics (SYN).",
"type": "Switch",
"dependsOn": [
{
"activity": "Set Orchestrator Type",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Query Run Days",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Resource Group Name",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Subscription Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"on": {
"value": "@variables('OrchestratorType')",
"type": "Expression"
},
"cases": [
{
"value": "ADF",
"activities": [
{
"name": "Check for Valid ADF Pipeline Name",
"description": "Use the Azure Management API to return and establish if the framework pipeline exists in the target Data Factory instance, including being deployed.",
"type": "WebActivity",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"url": {
"value": "https://management.azure.com/subscriptions/@{variables('SubscriptionId')}/resourceGroups/@{variables('ResourceGroupName')}/providers/Microsoft.DataFactory/factories/@{pipeline().DataFactory}/pipelines/@{pipeline().parameters.PipelineName}?api-version=2018-06-01",
"type": "Expression"
},
"method": "GET",
"authentication": {
"type": "MSI",
"resource": "https://management.core.windows.net/"
}
}
},
{
"name": "Get ADF Pipeline Runs",
"description": "Use the Azure Management API to return a list of data factory pipeline runs within the given time window.",
"type": "WebActivity",
"dependsOn": [
{
"activity": "Check for Valid ADF Pipeline Name",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"url": {
"value": "https://management.azure.com/subscriptions/@{variables('SubscriptionId')}/resourceGroups/@{variables('ResourceGroupName')}/providers/Microsoft.DataFactory/factories/@{pipeline().DataFactory}/queryPipelineRuns?api-version=2018-06-01",
"type": "Expression"
},
"method": "POST",
"body": {
"value": "{\n \"lastUpdatedAfter\": \"@{adddays(utcnow(),int(variables('QueryRunDays')))}\",\n \"lastUpdatedBefore\": \"@{utcnow()}\",\n \"filters\": [\n {\n \"operand\": \"PipelineName\",\n \"operator\": \"Equals\",\n \"values\": [\n \"@{pipeline().parameters.PipelineName}\"\n ]\n }\n ]\n}",
"type": "Expression"
},
"authentication": {
"type": "MSI",
"resource": "https://management.core.windows.net/"
}
}
},
{
"name": "Set ADF Runs Output",
"description": "Set output to local array for use in downstream filtering and pipeline checks. Use the same array output for both switch cases.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get ADF Pipeline Runs",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "PipelineRuns",
"value": {
"value": "@activity('Get ADF Pipeline Runs').output.value",
"type": "Expression"
}
}
}
]
},
{
"value": "SYN",
"activities": [
{
"name": "Check for Valid SYN Pipeline Name",
"description": "Use the Azure Management API to return and establish if the framework pipeline exists in the target Synapse instance, including being deployed.\n\nSee: https://docs.microsoft.com/en-us/rest/api/synapse/data-plane/pipeline/getpipeline",
"type": "WebActivity",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"url": {
"value": "https://@{pipeline().DataFactory}.dev.azuresynapse.net/pipelines/@{pipeline().parameters.PipelineName}?api-version=2019-06-01-preview",
"type": "Expression"
},
"method": "GET",
"authentication": {
"type": "MSI",
"resource": "https://management.core.windows.net/"
}
}
},
{
"name": "Get SYN Pipeline Runs",
"description": "Use the Azure Management API to return a list of synapse pipeline runs within the given time window.\n\nSee: https://docs.microsoft.com/en-us/rest/api/synapse/data-plane/pipelinerun/querypipelinerunsbyworkspace",
"type": "WebActivity",
"dependsOn": [
{
"activity": "Check for Valid SYN Pipeline Name",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"url": {
"value": "https://@{pipeline().DataFactory}.dev.azuresynapse.net/queryPipelineRuns?api-version=2019-06-01-preview",
"type": "Expression"
},
"method": "POST",
"body": {
"value": "{\n \"lastUpdatedAfter\": \"@{adddays(utcnow(),int(variables('QueryRunDays')))}\",\n \"lastUpdatedBefore\": \"@{utcnow()}\",\n \"filters\": [\n {\n \"operand\": \"PipelineName\",\n \"operator\": \"Equals\",\n \"values\": [\n \"@{pipeline().parameters.PipelineName}\"\n ]\n }\n ]\n}",
"type": "Expression"
},
"authentication": {
"type": "MSI",
"resource": "https://management.core.windows.net/"
}
}
},
{
"name": "Set SYN Runs Output",
"description": "Set output to local array for use in downstream filtering and pipeline checks. Use the same array output for both switch cases.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get SYN Pipeline Runs",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "PipelineRuns",
"value": {
"value": "@activity('Get SYN Pipeline Runs').output.value",
"type": "Expression"
}
}
}
]
}
],
"defaultActivities": [
{
"name": "Throw Exception Invalid Orchestrator Type",
"description": "Throw exception if switch cases are not met.",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "Throw Exception",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"Message": "Invalid orchestrator type provided. Unable to check pipeline running state."
}
}
}
]
}
},
{
"name": "Set Query Run Days",
"description": "Set the query run days value to a local variable for use in various downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Query Run Days Value",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "QueryRunDays",
"value": {
"value": "@activity('Get Query Run Days Value').output.firstRow.PropertyValue",
"type": "Expression"
}
}
}
],
"parameters": {
"BatchName": {
"type": "string",
"defaultValue": "NotUsed"
},
"PipelineName": {
"type": "string"
},
"ThisRunId": {
"type": "string"
}
},
"variables": {
"SubscriptionId": {
"type": "String"
},
"RunCount": {
"type": "String"
},
"ResourceGroupName": {
"type": "String"
},
"OrchestratorType": {
"type": "String"
},
"QueryRunDays": {
"type": "String"
},
"PipelineRuns": {
"type": "Array"
}
},
"folder": {
"name": "_ProcFwk/_ProcFwkUtils"
},
"annotations": [
"procfwk",
"Utils"
]
}
}
================================================
FILE: DataFactory/pipeline/Email Sender.json
================================================
{
"name": "Email Sender",
"properties": {
"description": "Provide a simple abstract over the send email function with request body item exposed as pipeline parameters.",
"activities": [
{
"name": "Send Email",
"description": "Use an Azure Function to perform an SMTP client email send operation.",
"type": "AzureFunctionActivity",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "SendEmail",
"method": "POST",
"body": {
"value": "{\n\"emailRecipients\": \"@{pipeline().parameters.Recipients}\",\n\"emailCcRecipients\": \"@{pipeline().parameters.CcRecipients}\",\n\"emailBccRecipients\": \"@{pipeline().parameters.BccRecipients}\",\n\"emailSubject\": \"@{pipeline().parameters.Subject}\",\n\"emailBody\": \"@{pipeline().parameters.Body}\",\n\"emailImportance\": \"@{pipeline().parameters.Importance}\"\n}",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
}
],
"parameters": {
"Recipients": {
"type": "string"
},
"CcRecipients": {
"type": "string"
},
"BccRecipients": {
"type": "string"
},
"Subject": {
"type": "string"
},
"Body": {
"type": "string"
},
"Importance": {
"type": "string"
}
},
"folder": {
"name": "_ProcFwk/_ProcFwkUtils"
},
"annotations": [
"procfwk",
"Utils"
]
}
}
================================================
FILE: DataFactory/pipeline/Intentional Error.json
================================================
{
"name": "Intentional Error",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait1",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
},
{
"name": "Raise Errors or Not",
"description": "Framework development worker simulator.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Wait1",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@equals(pipeline().parameters.RaiseErrors,'true')",
"type": "Expression"
},
"ifTrueActivities": [
{
"name": "Call Fail Procedure",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[dbo].[FailProcedure]",
"storedProcedureParameters": {
"RaiseError": {
"value": {
"value": "@pipeline().parameters.RaiseErrors",
"type": "Expression"
},
"type": "String"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
}
],
"parameters": {
"RaiseErrors": {
"type": "string",
"defaultValue": "false"
},
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
}
}
================================================
FILE: DataFactory/pipeline/Throw Exception.json
================================================
{
"name": "Throw Exception",
"properties": {
"description": "Provide a simple way of throwing an exception within Data Factory using TSQL error handling.",
"activities": [
{
"name": "Raise Error Backup",
"description": "Using a SQL database to raise an error/exception but wrapped up as a data factory pipeline. Error message information exposed as a pipeline parameter.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Raise Error",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderQuery": {
"value": "RAISERROR('@{pipeline().parameters.Message}',16,1);",
"type": "Expression"
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference"
},
"firstRowOnly": false
}
},
{
"name": "Raise Error",
"description": "Using newer native activity raise an error/exception but wrapped up as a data factory pipeline. Error message information exposed as a pipeline parameter.",
"type": "Fail",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"message": {
"value": "@pipeline().parameters.Message",
"type": "Expression"
},
"errorCode": "16"
}
}
],
"parameters": {
"Message": {
"type": "string"
}
},
"folder": {
"name": "_ProcFwk/_ProcFwkUtils"
},
"annotations": [
"procfwk",
"Utils"
]
}
}
================================================
FILE: DataFactory/pipeline/Wait 1.json
================================================
{
"name": "Wait 1",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait1",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
}
}
================================================
FILE: DataFactory/pipeline/Wait 10.json
================================================
{
"name": "Wait 10",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait10",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
}
}
================================================
FILE: DataFactory/pipeline/Wait 2.json
================================================
{
"name": "Wait 2",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait2",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
}
}
================================================
FILE: DataFactory/pipeline/Wait 3.json
================================================
{
"name": "Wait 3",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait3",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
}
}
================================================
FILE: DataFactory/pipeline/Wait 4.json
================================================
{
"name": "Wait 4",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait4",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
}
}
================================================
FILE: DataFactory/pipeline/Wait 5.json
================================================
{
"name": "Wait 5",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait5",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
}
}
================================================
FILE: DataFactory/pipeline/Wait 6.json
================================================
{
"name": "Wait 6",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait6",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
}
}
================================================
FILE: DataFactory/pipeline/Wait 7.json
================================================
{
"name": "Wait 7",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait7",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
}
}
================================================
FILE: DataFactory/pipeline/Wait 8.json
================================================
{
"name": "Wait 8",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait8",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
}
}
================================================
FILE: DataFactory/pipeline/Wait 9.json
================================================
{
"name": "Wait 9",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait9",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 15
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
}
}
================================================
FILE: DataFactory/trigger/FunctionalTestingTrigger.json
================================================
{
"name": "FunctionalTestingTrigger",
"properties": {
"description": "Used for functional testing of the framework in a dedicated environment.",
"annotations": [
"procfwk"
],
"runtimeState": "Stopped",
"pipelines": [
{
"pipelineReference": {
"referenceName": "01-Grandparent",
"type": "PipelineReference"
}
}
],
"type": "ScheduleTrigger",
"typeProperties": {
"recurrence": {
"frequency": "Hour",
"interval": 2,
"startTime": "2020-04-06T15:00:00Z",
"timeZone": "UTC"
}
}
}
}
================================================
FILE: DeploymentTools/DataFactory/DeployProcFwkComponents.ps1
================================================
function Publish-procfwkadf
{
Param(
[Parameter(Mandatory)]
[string]$resourceGroupName,
[Parameter(Mandatory)]
[string]$dataFactoryName,
[Parameter(Mandatory)]
[string]$region,
[Parameter(Mandatory)]
[string]$adfPath,
[Parameter(Mandatory)]
[string]$scriptPath
)
#SPN for deploying ADF:
$tenantId = [System.Environment]::GetEnvironmentVariable('AZURE_TENANT_ID')
$subscriptionId = [System.Environment]::GetEnvironmentVariable('AZURE_SUBSCRIPTION_ID')
$spId = [System.Environment]::GetEnvironmentVariable('AZURE_CLIENT_ID')
$spKey = [System.Environment]::GetEnvironmentVariable('AZURE_CLIENT_SECRET')
#Modules
Import-Module -Name "Az"
#Update-Module -Name "Az"
Import-Module -Name "Az.DataFactory"
#Update-Module -Name "Az.DataFactory"
Import-Module -Name "azure.datafactory.tools"
#Update-Module -Name "azure.datafactory.tools"
Get-Module -Name "*DataFactory*"
# Login as a Service Principal
if ($spId) {
$passwd = ConvertTo-SecureString $spKey -AsPlainText -Force
$pscredential = New-Object System.Management.Automation.PSCredential($spId, $passwd)
Connect-AzAccount -ServicePrincipal -Credential $pscredential -TenantId $tenantId | Out-Null
}
Get-AzContext
# Get Deployment Objects and Params files
$deploymentFilePath = Join-Path -Path $scriptPath -ChildPath "ProcFwkComponents.json"
$configFilePath = Join-Path -Path $scriptPath -ChildPath "config-all.csv"
$Env:SQLDatabase = "secretKeyToDbConnectionString"
$opt = New-AdfPublishOption
$deploymentObject = (Get-Content $deploymentFilePath) | ConvertFrom-Json
$objectsToInclude = $deploymentObject.datasets + $deploymentObject.linkedServices + $deploymentObject.pipelines + $deploymentObject.triggers
$objectsToInclude | ForEach-Object {
$objName = $_.substring(1).Replace('.json', '').Replace('/', '.')
$opt.Includes.Add($objName, "")
}
# Deployment of ADF
$opt.CreateNewInstance = $true
$opt.DeleteNotInSource = $false
$opt.StopStartTriggers = $true
Publish-AdfV2FromJson -RootFolder $adfPath `
-ResourceGroupName $resourceGroupName `
-DataFactoryName $dataFactoryName `
-Location $region `
-Option $opt `
-Stage $configFilePath
}
# Run function
$VerbosePreference = 'Continue'
$ErrorActionPreference = 'Stop'
$scriptPath = Join-Path -Path (Get-Location) -ChildPath "\DeploymentTools\DataFactory"
$AdfPath = Join-Path -Path (Get-Location) -ChildPath "DataFactory"
Publish-procfwkadf -resourceGroupName 'rg-pademo' -dataFactoryName 'adf-metadata-driven-proc' -region 'uksouth' `
-adfPath "$AdfPath" -scriptPath "$scriptPath"
================================================
FILE: DeploymentTools/DataFactory/DeployProcFwkComponents_Old.ps1
================================================
# Set global variables as required:
$resourceGroupName = "ADF.procfwk"
$dataFactoryName = "FrameworkFactoryDev"
$region = "uksouth"
#SPN for deploying ADF:
$tenantId = [System.Environment]::GetEnvironmentVariable('AZURE_TENANT_ID')
$subscriptionId = [System.Environment]::GetEnvironmentVariable('AZURE_SUBSCRIPTION_ID')
$spId = [System.Environment]::GetEnvironmentVariable('AZURE_CLIENT_ID')
$spKey = [System.Environment]::GetEnvironmentVariable('AZURE_CLIENT_SECRET')
#Modules
Import-Module -Name "Az"
#Update-Module -Name "Az"
Import-Module -Name "Az.DataFactory"
#Update-Module -Name "Az.DataFactory"
# Login as a Service Principal
$passwd = ConvertTo-SecureString $spKey -AsPlainText -Force
$pscredential = New-Object System.Management.Automation.PSCredential($spId, $passwd)
Connect-AzAccount -ServicePrincipal -Credential $pscredential -TenantId $tenantId | Out-Null
# Get Deployment Objects and Params files
$scriptPath = "C:\Users\PaulAndrew\Source\GitHub\ADF.procfwk\DeploymentTools\DataFactory\"
#$deploymentFilePath = $scriptPath + "\ProcFwkComponents.json"
$deploymentFilePath = "C:\Users\PaulAndrew\Source\GitHub\ADF.procfwk\DeploymentTools\DataFactory\ProcFwkComponents.json"
#Write-Host $scriptPath
$deploymentObject = (Get-Content $deploymentFilePath) | ConvertFrom-Json
<#
Create Data Factory
#>
Write-Host ""
Write-Host "-----------------------Data Factory-------------------------"
$check = Get-AzDataFactoryV2 `
-ResourceGroupName $resourceGroupName `
-DataFactoryName $dataFactoryName `
-ErrorAction SilentlyContinue
if($check -eq $null)
{
Write-Host "Creating Data Factory:" $dataFactoryName
try
{
Set-AzDataFactoryV2 `
-ResourceGroupName $resourceGroupName `
-DataFactoryName $dataFactoryName `
-Location $region | Format-List | Out-Null
Write-Host "...done" -ForegroundColor Green
Write-Host ""
}
catch
{
Write-Host "Failed to created data factory:" $dataFactoryName -ForegroundColor Red
Write-Host $_.Exception.Message
Write-Host $_.Exception.ItemName
Exit
}
}
else
{
Write-Host "Data Factory $dataFactoryName already exists..."
}
<#
Deploy Linked Services
#>
Write-Host ""
Write-Host "----------------------Linked Services-----------------------"
ForEach ($linkedService in $deploymentObject.linkedServices)
{
$componentPath = $scriptPath.Replace("DeploymentTools\","") + $linkedService
$linkedServiceFile = (Get-Content $componentPath) | ConvertFrom-Json
$linkedServiceName = $linkedServiceFile.name
Write-Host "Deploying Linked Service:" $linkedServiceName
try
{
Set-AzDataFactoryV2LinkedService `
-ResourceGroupName $resourceGroupName `
-DataFactoryName $dataFactoryName `
-Name $linkedServiceName `
-DefinitionFile $componentPath `
-Force | Format-List | Out-Null
Write-Host "...done" -ForegroundColor Green
Write-Host ""
}
catch
{
Write-Host "Failed to deploy linked service:" $linkedServiceName -ForegroundColor Green
Write-Host $_.Exception.Message
Write-Host $_.Exception.ItemName
Exit
}
}
<#
Deploy Datasets
#>
Write-Host ""
Write-Host "--------------------------Datasets--------------------------"
ForEach ($dataSet in $deploymentObject.datasets)
{
$componentPath = $scriptPath.Replace("DeploymentTools\","") + $dataSet
$datasetFile = (Get-Content $componentPath) | ConvertFrom-Json
$datasetName = $datasetFile.name
Write-Host "Deploying Dataset:" $datasetName
try
{
Set-AzDataFactoryV2Dataset `
-ResourceGroupName $resourceGroupName `
-DataFactoryName $dataFactoryName `
-Name $datasetName `
-DefinitionFile $componentPath `
-Force | Format-List | Out-Null
Write-Host "...done" -ForegroundColor Green
Write-Host ""
}
catch
{
Write-Host "Failed to deploy dataset:" $datasetName -ForegroundColor Red
Write-Host $_.Exception.Message
Write-Host $_.Exception.ItemName
Exit
}
}
<#
Deploy Pipelines
#>
Write-Host ""
Write-Host "-------------------------Pipelines--------------------------"
ForEach ($pipeline in $deploymentObject.pipelines)
{
$componentPath = $scriptPath.Replace("DeploymentTools\","") + $pipeline
$pipelineFile = (Get-Content $componentPath) | ConvertFrom-Json
$pipelineName = $pipelineFile.name
Write-Host "Deploying Pipeline:" $pipelineName
try
{
##Bug in SDK means this native cmdlet can't be used if pipeline contains a Wait activity expression.
<#
Set-AzDataFactoryV2Pipeline `
-ResourceGroupName $resourceGroupName `
-DataFactoryName $dataFactoryName `
-Name $pipelineName `
-DefinitionFile $componentPath `
-Force | Format-List | Out-Null
#>
$body = (Get-Content -Path $componentPath | Out-String)
$json = $body | ConvertFrom-Json
New-AzResource `
-ResourceType 'Microsoft.DataFactory/factories/pipelines' `
-ResourceGroupName $resourceGroupName `
-Name "$dataFactoryName/$pipelineName" `
-ApiVersion "2018-06-01" `
-Properties $json `
-IsFullObject -Force | Out-Null
Write-Host "...done" -ForegroundColor Green
Write-Host ""
}
catch
{
Write-Host "Failed to deploy pipeline:" $pipelineName -ForegroundColor Red
Write-Host $_.Exception.Message
Write-Host $_.Exception.ItemName
Exit
}
}
<#
Deploy Triggers
#>
Write-Host ""
Write-Host "-------------------------Triggers---------------------------"
ForEach ($trigger in $deploymentObject.triggers)
{
$componentPath = $scriptPath.Replace("DeploymentTools\","") + $trigger
$triggerFile = (Get-Content $componentPath) | ConvertFrom-Json
$triggerName = $triggerFile.name
Write-Host "Deploying Trigger:" $triggerName
$currentTrigger = Get-AzDataFactoryV2Trigger `
-ResourceGroupName $resourceGroupName `
-DataFactoryName $dataFactoryName `
-Name $triggerName `
-ErrorAction SilentlyContinue
try
{
if($currentTrigger -ne $null)
{
#Stop trigger if already deployed as can't deploy over running trigger.
Stop-AzDataFactoryV2Trigger `
-ResourceGroupName $resourceGroupName `
-DataFactoryName $dataFactoryName `
-Name $triggerName -Force | Out-Null
}
Set-AzDataFactoryV2Trigger `
-ResourceGroupName $resourceGroupName `
-DataFactoryName $dataFactoryName `
-Name $triggerName `
-DefinitionFile $componentPath `
-Force | Format-List | Out-Null
Write-Host "...done" -ForegroundColor Green
Write-Host ""
}
catch
{
Write-Host "Failed to deploy trigger:" $triggerName -ForegroundColor Red
Write-Host $_.Exception.Message
Write-Host $_.Exception.ItemName
Exit
}
}
================================================
FILE: DeploymentTools/DataFactory/Get Pipelines.ps1
================================================
# Set global variables as required:
$resourceGroupName = "ADF.procfwk"
$dataFactoryName = "FrameworkFactory"
$region = "uksouth"
#SPN for deploying ADF:
$tenantId = [System.Environment]::GetEnvironmentVariable('AZURE_TENANT_ID')
$subscriptionId = [System.Environment]::GetEnvironmentVariable('AZURE_SUBSCRIPTION_ID')
$spId = [System.Environment]::GetEnvironmentVariable('AZURE_CLIENT_ID')
$spKey = [System.Environment]::GetEnvironmentVariable('AZURE_CLIENT_SECRET')
#Modules
Import-Module -Name "Az"
Import-Module -Name "Az.DataFactory"
# Login as a Service Principal
$passwd = ConvertTo-SecureString $spKey -AsPlainText -Force
$pscredential = New-Object System.Management.Automation.PSCredential($spId, $passwd)
Connect-AzAccount -ServicePrincipal -Credential $pscredential -TenantId $tenantId | Out-Null
Get-AzDataFactoryV2Pipeline -DataFactoryName $dataFactoryName -ResourceGroupName $resourceGroupName
================================================
FILE: DeploymentTools/DataFactory/GlobalVars.ps1
================================================
# Set global variables as required:
$resourceGroupName = "ADF.procfwk"
$dataFactoryName = "FrameworkFactory"
$region = "uksouth"
# ADF deployment from PS script
.\DeploymentTools\DataFactory\DeployProcFwkComponents.ps1 `
-resourceGroupName "$resourceGroupName" `
-dataFactoryName "$dataFactoryName" `
-region "$region"
.\DeploymentTools\DataFactory\PopulatePipelinesInDb.ps1 `
-SqlServerName '*****.database.windows.net' `
-SqlDatabaseName 'adfprocfwk' `
-SqlUser 'adm' `
-SqlPass '******' `
-resourceGroupName "$resourceGroupName" `
-dataFactoryName "$dataFactoryName" `
-region "$region"
================================================
FILE: DeploymentTools/DataFactory/PopulatePipelinesInDb.ps1
================================================
Param(
[Parameter(Mandatory)]
[string]$SqlServerName,
[Parameter(Mandatory)]
[string]$SqlDatabaseName,
[Parameter(Mandatory)]
[string]$SqlUser,
[Parameter(Mandatory)]
[string]$SqlPass,
[Parameter(Mandatory)]
[string]$resourceGroupName,
[Parameter(Mandatory)]
[string]$dataFactoryName,
[Parameter(Mandatory)]
[string]$region
)
$ErrorActionPreference = 'Stop'
#Install-Module -Name SqlServer -AllowClobber
Import-Module -Name SqlServer
$pipelines = Get-AzDataFactoryV2Pipeline -DataFactoryName $dataFactoryName -ResourceGroupName $resourceGroupName
foreach ($p in $pipelines) {
Write-Host $p.name
$query = "EXEC [procfwkHelpers].[AddPipelineViaPowerShell] '$resourceGroupName', '$dataFactoryName', '$($p.Name)';"
Invoke-Sqlcmd -ServerInstance "$SqlServerName" -Database "$SqlDatabaseName" -Query "$query" -Username "$SqlUser" -Password "$SqlPass"
}
Write-Host "List of ADF pipelines has been populated into database."
================================================
FILE: DeploymentTools/DataFactory/ProcFwkComponents.json
================================================
{
"linkedServices": [
"/linkedService/Keys.json",
"/linkedService/FrameworkFunctions.json",
"/linkedService/SupportDatabase.json"
],
"datasets": [
"/dataset/GetSetMetadata.json"
],
"pipelines": [
"/pipeline/Throw Exception.json",
"/pipeline/Check For Running Pipeline.json",
"/pipeline/Email Sender.json",
"/pipeline/04-Infant.json",
"/pipeline/03-Child.json",
"/pipeline/02-Parent.json",
"/pipeline/01-Grandparent.json"
],
"triggers": [
"/trigger/FunctionalTestingTrigger.json"
]
}
================================================
FILE: DeploymentTools/DataFactory/config-all.csv
================================================
type,name,path,value
linkedService,SupportDatabase,typeProperties.connectionString.secretName,$($Env:SQLDatabase)
================================================
FILE: DeploymentTools/Deployment.targets
================================================
Debug
AnyCPU
bin\$(Configuration)\
false
true
false
None
obj\
$(BaseIntermediateOutputPath)\
$(BaseIntermediateOutputPath)$(Configuration)\
$(IntermediateOutputPath)ProjectReferences
$(ProjectReferencesOutputPath)\
true
false
false
Always
Never
false
Build
_GetDeploymentProjectContent;
_CalculateContentOutputRelativePaths;
_GetReferencedProjectsOutput;
_CalculateArtifactStagingDirectory;
_CopyOutputToArtifactStagingDirectory;
Configuration=$(Configuration);Platform=$(Platform)
$([System.IO.Path]::GetFileNameWithoutExtension('%(ProjectReference.Identity)'))
$(OutDir)
$(OutputPath)
$(ArtifactStagingDirectory)\
$(ArtifactStagingDirectory)staging\
$(Build_StagingDirectory)
<_OriginalIdentity>%(DeploymentProjectContentOutput.Identity)
<_RelativePath>$(_OriginalIdentity.Replace('$(MSBuildProjectDirectory)', ''))
$(_RelativePath)
PrepareForRun
================================================
FILE: DeploymentTools/DeploymentTools.deployproj
================================================
Debug
AnyCPU
Release
AnyCPU
3aead846-dbe4-45ad-97dd-37e94be009fd
False
================================================
FILE: FactoryTesting/FactoryTesting.csproj
================================================
netcoreapp3.1
false
all
runtime; build; native; contentfiles; analyzers; buildtransitive
================================================
FILE: FactoryTesting/Helpers/CoverageHelper.cs
================================================
using FactoryTesting.Helpers;
using Microsoft.Azure.Management.DataFactory.Models;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace FactoryTesting.Helpers
{
public class CoverageHelper : DatabaseHelper where T : CoverageHelper
{
public new async Task RunPipeline(string pipelineName)
{
var callStack = new System.Diagnostics.StackTrace();
await base.RunPipeline(pipelineName);
if (ReportTestCoverage)
foreach (var ar in await GetActivityRuns())
RecordActivityRun(ar, callStack.ToString());
}
public new async Task RunPipelineAndCancel(string pipelineName)
{
var callStack = new System.Diagnostics.StackTrace();
await base.RunPipelineAndCancel(pipelineName);
}
public bool ReportTestCoverage
{
get
{
try
{
var measure = GetSetting("ReportTestCoverage");
if (measure == "true")
return true;
}
catch (Exception) { }
return false;
}
}
private void RecordActivityRun(ActivityRun ar, string context)
{
var parameters = new Dictionary
{
["@pipelineName"] = ar.PipelineName,
["@activityName"] = ar.ActivityName,
["@context"] = context
};
ExecuteStoredProcedure("test.RecordActivityRun", parameters);
}
}
}
[SetUpFixture]
public class CoverageHelperSetup : CoverageHelper
{
[OneTimeSetUp]
public async Task SetupCoverageHelper()
{
if (ReportTestCoverage)
{
WithEmptyTable("test.ActivityRun");
WithEmptyTable("test.PipelineActivity");
foreach (var p in await GetPipelines())
if (p.Activities != null)
foreach (var a in p.Activities)
RecordActivity(p.Name, a);
}
TearDown();
}
private void RecordActivity(string pipelineName, Activity act)
{
var parameters = new Dictionary
{
["@pipelineName"] = pipelineName,
["@activityName"] = act.Name
};
ExecuteStoredProcedure("test.RecordActivity", parameters);
if (act is ForEachActivity)
foreach (var a in ((ForEachActivity)act).Activities)
RecordActivity(pipelineName, a);
if (act is UntilActivity)
foreach (var a in ((UntilActivity)act).Activities)
RecordActivity(pipelineName, a);
if (act is IfConditionActivity)
{
foreach (var a in ((IfConditionActivity)act).IfTrueActivities)
RecordActivity(pipelineName, a);
foreach (var a in ((IfConditionActivity)act).IfFalseActivities)
RecordActivity(pipelineName, a);
}
if (act is SwitchActivity)
foreach (var c in ((SwitchActivity)act).Cases)
foreach (var a in c.Activities)
RecordActivity(pipelineName, a);
}
}
================================================
FILE: FactoryTesting/Helpers/DataFactoryHelper.cs
================================================
using Microsoft.Azure.Management.DataFactory;
using Microsoft.Azure.Management.DataFactory.Models;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using Microsoft.Rest;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
namespace FactoryTesting.Helpers
{
public class DataFactoryHelper : SettingsHelper where T : DataFactoryHelper
{
private readonly string _adfName;
private readonly string _rgName;
private DataFactoryManagementClient _adfClient;
private async Task InitialiseClient()
{
if (_adfClient != null)
return;
var context = new AuthenticationContext("https://login.windows.net/" + GetSetting("AZURE_TENANT_ID"));
var cc = new ClientCredential(GetSetting("AZURE_CLIENT_ID"), GetSetting("AZURE_CLIENT_SECRET"));
var authResult = await context.AcquireTokenAsync("https://management.azure.com/", cc);
var cred = new TokenCredentials(authResult.AccessToken);
_adfClient = new DataFactoryManagementClient(cred) { SubscriptionId = GetSetting("AZURE_SUBSCRIPTION_ID") };
}
public async Task TriggerPipeline(string pipelineName, IDictionary parameters)
{
await InitialiseClient();
var response = await _adfClient.Pipelines.CreateRunWithHttpMessagesAsync(_rgName, _adfName, pipelineName, parameters: parameters);
return response.Body.RunId;
}
public async Task> GetPipelines()
{
await InitialiseClient();
var page = await _adfClient.Pipelines.ListByFactoryAsync(_rgName, _adfName);
var pipelines = page.ToList();
while (!string.IsNullOrWhiteSpace(page.NextPageLink))
{
page = await _adfClient.Pipelines.ListByFactoryNextAsync(page.NextPageLink);
pipelines.AddRange(page.ToList());
}
return pipelines;
}
public async Task> GetActivityRuns(string pipelineRunId)
{
await InitialiseClient();
var filter = new RunFilterParameters(DateTime.MinValue, DateTime.UtcNow);
var arqr = await _adfClient.ActivityRuns.QueryByPipelineRunAsync(_rgName, _adfName, pipelineRunId, filter);
var activityRuns = arqr.Value.ToList();
while (!string.IsNullOrWhiteSpace(arqr.ContinuationToken))
{
filter.ContinuationToken = arqr.ContinuationToken;
arqr = await _adfClient.ActivityRuns.QueryByPipelineRunAsync(_rgName, _adfName, pipelineRunId, filter);
activityRuns.AddRange(arqr.Value);
}
return activityRuns;
}
public virtual void TearDown()
{
_adfClient?.Dispose();
}
public async Task GetRunStatus(string pipelineRunId)
{
await InitialiseClient();
var run = await _adfClient.PipelineRuns.GetAsync(_rgName, _adfName, pipelineRunId);
return run.Status;
}
public async Task GetRunStatus(string pipelineRunId, string adfName)
{
await InitialiseClient();
var run = await _adfClient.PipelineRuns.GetAsync(_rgName, adfName, pipelineRunId);
return run.Status;
}
public async Task IsInProgress(string pipelineRunId)
{
await InitialiseClient();
var status = await GetRunStatus(pipelineRunId);
return status == "Queued" || status == "InProgress" || status == "Cancelling";
}
public async Task IsInProgress(string pipelineRunId, string adfName)
{
await InitialiseClient();
var status = await GetRunStatus(pipelineRunId, adfName);
return status == "Queued" || status == "InProgress" || status == "Cancelling";
}
public async Task IsQueued(string pipelineRunId)
{
await InitialiseClient();
var status = await GetRunStatus(pipelineRunId);
return status == "Queued";
}
public async Task IsCancelling(string pipelineRunId)
{
await InitialiseClient();
var status = await GetRunStatus(pipelineRunId);
return status == "Cancelling" || status == "Canceling"; //microsoft typo
}
public async Task IsCancelling(string pipelineRunId, string adfName)
{
await InitialiseClient();
var status = await GetRunStatus(pipelineRunId, adfName);
return status == "Cancelling" || status == "Canceling"; //microsoft typo
}
public async Task CancelRunningPipeline(string pipelineRunId, bool recurseCancel = true)
{
await InitialiseClient();
if (await IsInProgress(pipelineRunId))
{
_adfClient.PipelineRuns.Cancel(_rgName, _adfName, pipelineRunId, recurseCancel);
while (await IsCancelling(pipelineRunId))
Thread.Sleep(2000);
}
else
{
throw new Exception("Pipeline is not in a state that can be cancelled.");
}
string status = await GetRunStatus(pipelineRunId);
return status;
}
public async Task CancelRunningPipeline(string pipelineRunId, string adfName, bool recurseCancel = true)
{
await InitialiseClient();
if (await IsInProgress(pipelineRunId, adfName))
{
_adfClient.PipelineRuns.Cancel(_rgName, adfName, pipelineRunId, recurseCancel);
while (await IsCancelling(pipelineRunId, adfName))
Thread.Sleep(2000);
}
else
{
throw new Exception("Pipeline is not in a state that can be cancelled.");
}
string status = await GetRunStatus(pipelineRunId, adfName);
return status;
}
public DataFactoryHelper()
{
_adfName = GetSetting("DataFactoryName");
_rgName = GetSetting("DataFactoryResourceGroup");
}
}
}
================================================
FILE: FactoryTesting/Helpers/DatabaseHelper.cs
================================================
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
namespace FactoryTesting.Helpers
{
public class DatabaseHelper : PipelineRunHelper where T : DatabaseHelper
{
public SqlConnection _conn;
public DatabaseHelper()
{
_conn = new SqlConnection(GetSetting(GetSetting("MetadataDbConnectionStringSecretName")));
_conn.Open();
}
public T WithEmptyTable(string tableName)
{
using (var cmd = new SqlCommand($"TRUNCATE TABLE {tableName}", _conn))
cmd.ExecuteNonQuery();
return (T)this;
}
public int RowCount(string tableName, string where = "", string equals = "")
{
using (var cmd = new SqlCommand($"SELECT COUNT(*) FROM {tableName}"
+ (where?.Length == 0 ? "" : $" WHERE {where} = '{equals.Replace("'", "''")}'")
, _conn))
using (var reader = cmd.ExecuteReader())
{
reader.Read();
return reader.GetInt32(0);
}
}
public string ColumnData(string tableName, string columnName, char separator = ',')
{
using (var cmd = new SqlCommand($"SELECT STRING_AGG([{columnName}],'{separator}') FROM {tableName}", _conn))
using (var reader = cmd.ExecuteReader())
{
reader.Read();
return reader.GetString(0);
}
}
public void ExecuteStoredProcedure(string spName, Dictionary parameters = null)
{
using (var cmd = new SqlCommand(spName, _conn))
{
cmd.CommandType = CommandType.StoredProcedure;
if (parameters != null)
foreach (string parameterName in parameters.Keys)
cmd.Parameters.Add(new SqlParameter(parameterName, parameters[parameterName]));
cmd.ExecuteNonQuery();
}
}
public void ExecuteNonQuery(string sql)
{
using (var cmd = new SqlCommand(sql, _conn))
cmd.ExecuteNonQuery();
}
public void AddTenantAndSubscription(string tenantId = null, string subscriptionId = null)
{
if (string.IsNullOrEmpty(tenantId)) tenantId = GetSetting("AZURE_TENANT_ID");
if (string.IsNullOrEmpty(subscriptionId)) subscriptionId = GetSetting("AZURE_SUBSCRIPTION_ID");
ExecuteNonQuery($"INSERT INTO[procfwk].[Tenants] ([TenantId],[Name],[Description]) VALUES ('{tenantId}', 'mrpaulandrew.com', NULL);");
ExecuteNonQuery($"INSERT INTO [procfwk].[Subscriptions] ([SubscriptionId],[Name],[Description],[TenantId]) VALUES ('{subscriptionId}', 'Microsoft Sponsored Subscription', NULL, '{tenantId}');");
ExecuteNonQuery($"UPDATE [procfwk].[Orchestrators] SET [SubscriptionId] = '{subscriptionId}';");
}
public void AddWorkerSPNStoredInDatabase(string workerFactoryName, string orchestratorType = "ADF")
{
ExecuteNonQuery("UPDATE [procfwk].[Properties] SET [PropertyValue] = 'StoreInDatabase' WHERE [PropertyName] = 'SPNHandlingMethod';");
var parameters = new Dictionary
{
["@OrchestratorName"] = workerFactoryName,
["@OrchestratorType"] = orchestratorType,
["@PrincipalIdValue"] = GetSetting("AZURE_CLIENT_ID"),
["@PrincipalSecretValue"] = GetSetting("AZURE_CLIENT_SECRET"),
["@PrincipalName"] = GetSetting("AZURE_CLIENT_NAME")
};
ExecuteStoredProcedure("[procfwkHelpers].[AddServicePrincipalWrapper]", parameters);
}
public void AddWorkerSPNStoredInKeyVault(string workerFactoryName, string orchestratorType = "ADF")
{
ExecuteNonQuery("UPDATE [procfwk].[Properties] SET [PropertyValue] = 'StoreInKeyVault' WHERE [PropertyName] = 'SPNHandlingMethod';");
var parameters = new Dictionary
{
["@OrchestratorName"] = workerFactoryName,
["@OrchestratorType"] = orchestratorType,
["@PrincipalIdValue"] = GetSetting("AZURE_CLIENT_ID_URL"),
["@PrincipalSecretValue"] = GetSetting("AZURE_CLIENT_SECRET_URL"),
["@PrincipalName"] = GetSetting("AZURE_CLIENT_NAME")
};
ExecuteStoredProcedure("[procfwkHelpers].[AddServicePrincipalWrapper]", parameters);
}
public void AddBasicMetadata()
{
ExecuteStoredProcedure("[procfwkTesting].[ResetMetadata]", null);
ExecuteNonQuery("UPDATE [procfwk].[Orchestrators] SET [IsFrameworkOrchestrator] = '0';");
ExecuteNonQuery($"UPDATE [procfwk].[Orchestrators] SET [IsFrameworkOrchestrator] = '1' WHERE [OrchestratorName] = '{GetSetting("DataFactoryName")}';");
}
public override void TearDown()
{
ExecuteStoredProcedure("[procfwkTesting].[CleanUpMetadata]", null);
_conn?.Dispose();
base.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Helpers/PipelineRunHelper.cs
================================================
using Microsoft.Azure.Management.DataFactory.Models;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
namespace FactoryTesting.Helpers
{
public class PipelineRunHelper : DataFactoryHelper where T : PipelineRunHelper
{
private readonly Dictionary _parameters;
private List _activityRuns;
private bool _hasRun;
public string RunId { get; private set; }
public string RunOutcome { get; private set; }
public PipelineRunHelper()
{
RunId = "Unknown";
RunOutcome = "Unknown";
_hasRun = false;
_parameters = new Dictionary();
}
public T WithParameter(string name, object value)
{
_parameters[name] = value;
return (T)this;
}
public async Task RunPipeline(string pipelineName)
{
if (_hasRun)
throw new Exception("RunPipeline() can only be called once per instance lifetime");
_hasRun = true;
RunId = await TriggerPipeline(pipelineName, _parameters);
while (await IsInProgress(RunId))
Thread.Sleep(2000);
RunOutcome = await GetRunStatus(RunId);
}
public async Task RunPipelineAndCancel(string pipelineName)
{
if (_hasRun)
throw new Exception("RunPipeline() can only be called once per instance lifetime");
_hasRun = true;
RunId = await TriggerPipeline(pipelineName, _parameters);
while (await IsQueued(RunId))
Thread.Sleep(2000);
await CancelRunningPipeline(RunId, true);
RunOutcome = await GetRunStatus(RunId);
}
public async Task> GetActivityRuns()
{
await InitialiseActivityRuns();
return _activityRuns;
}
public async Task GetActivityRunCount(string pattern = ".*")
{
await InitialiseActivityRuns();
Regex rgx = new Regex(pattern);
return _activityRuns.Where(ar => rgx.IsMatch(ar.ActivityName)).Count();
}
private async Task InitialiseActivityRuns()
{
if (_activityRuns == null)
_activityRuns = await GetActivityRuns(RunId);
}
public async Task GetActivityOutput(string activityName, string propertyPath = "$")
{
await InitialiseActivityRuns();
string output = _activityRuns.Where(ar => ar.ActivityName == activityName).FirstOrDefault().Output.ToString();
var obj = JObject.Parse(output);
return obj.SelectToken(propertyPath).ToString();
}
}
}
================================================
FILE: FactoryTesting/Helpers/SettingsHelper.cs
================================================
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
using NUnit.Framework;
using System;
namespace FactoryTesting.Helpers
{
public class SettingsHelper
{
public string GetSetting(string settingName)
{
// return environment variable "settingName", if present
var value = Environment.GetEnvironmentVariable(settingName);
if (value?.Length > 0)
return value;
// return value of runsettings parameter "settingName", if present
value = TestContext.Parameters[settingName];
if (value?.Length > 0)
return value;
// if a key vault is specified, return the value of secret "settingName", if present
if (_keyVaultClient != null)
{
value = _keyVaultClient.GetSecret(settingName).Value.Value;
if (value?.Length > 0)
return value;
}
throw new Exception($"Test setting '{settingName}' not found");
}
private readonly SecretClient _keyVaultClient;
public SettingsHelper()
{
var kvUrl = TestContext.Parameters["KeyVaultUrl"];
if (kvUrl?.Length > 0)
_keyVaultClient = new SecretClient(new Uri(kvUrl), new DefaultAzureCredential());
}
}
}
================================================
FILE: FactoryTesting/Pipelines/01-Grandparent/Given300WorkerPipelines.cs
================================================
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Threading.Tasks;
namespace FactoryTesting.Pipelines.Grandparent
{
public class Given300WorkerPipelines
{
private GrandparentHelper _helper;
[OneTimeSetUp]
public async Task WhenPipelineRun()
{
_helper = new GrandparentHelper()
.WithBasicMetadata()
.WithTenantAndSubscriptionIds()
.With300WorkerPipelinesEnabled()
.WithSPNInKeyVault("WorkersFactory");
await _helper.RunPipeline();
}
#region Integration tests
[Test]
public void ThenPipelineOutcomeIsSucceeded()
{
_helper.RunOutcome.Should().Be("Succeeded");
}
[Test]
public void ThenCurrentExecutionTableIsEmpty()
{
_helper.RowCount("procfwk.CurrentExecution").Should().Be(0);
}
[Test]
public void Then300ExecutionLogRecords()
{
_helper.RowCount("procfwk.ExecutionLog").Should().Be(300);
}
#endregion
[OneTimeTearDown]
public void TearDown()
{
_helper?.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Pipelines/01-Grandparent/Given600WorkerPipelineConcurrentBatches.cs
================================================
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Threading.Tasks;
namespace FactoryTesting.Pipelines.Grandparent
{
public class Given600WorkerPipelineConcurrentBatches
{
private GrandparentHelper _helperFirstBatch;
private GrandparentHelper _helperSecondBatch;
[OneTimeSetUp]
public async Task WhenPipelineRun()
{
_helperFirstBatch = new GrandparentHelper()
.WithBasicMetadata()
.WithTenantAndSubscriptionIds()
.With300WorkerPipelinesEnabled()
.WithBatchExecutionHandling()
.With300WorkerPipelineBatches()
.WithSPNInKeyVault("WorkersFactory")
.WithParameter("BatchName", "0to300");
_helperSecondBatch = new GrandparentHelper()
.WithParameter("BatchName", "301to600");
var firstBatch = _helperFirstBatch.RunPipeline();
var secondBatch = _helperSecondBatch.RunPipeline();
await Task.WhenAll(firstBatch, secondBatch);
}
#region Integration tests
[Test]
public void ThenFirstBatchPipelineOutcomeIsSucceeded()
{
_helperFirstBatch.RunOutcome.Should().Be("Succeeded");
}
[Test]
public void ThenSecondBatchPipelineOutcomeIsSucceeded()
{
_helperSecondBatch.RunOutcome.Should().Be("Succeeded");
}
[Test]
public void ThenTwoBatchExecutionSuccessRecords()
{
_helperFirstBatch.RowCount("procfwk.BatchExecution", where: "BatchStatus", equals: "Success").Should().Be(2);
}
[Test]
public void ThenCurrentExecutionTableIsEmpty()
{
_helperFirstBatch.RowCount("procfwk.CurrentExecution").Should().Be(0);
}
[Test]
public void Then300ExecutionLogRecords()
{
_helperFirstBatch.RowCount("procfwk.ExecutionLog").Should().Be(600);
}
#endregion
[OneTimeTearDown]
public void TearDown()
{
_helperFirstBatch?.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Pipelines/01-Grandparent/GivenOneWorkerPipeline.cs
================================================
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Threading.Tasks;
namespace FactoryTesting.Pipelines.Grandparent
{
public class GivenOneWorkerPipeline
{
private GrandparentHelper _helper;
[OneTimeSetUp]
public async Task WhenPipelineRun()
{
_helper = new GrandparentHelper()
.WithBasicMetadata()
.WithTenantAndSubscriptionIds()
.WithSPNInDatabase("FrameworkFactory")
.WithEmptyExecutionTables()
.WithSimpleFailureHandling()
.WithOneWorkerPipelineEnabled();
await _helper.RunPipeline();
}
#region Integration tests
[Test]
public void ThenPipelineOutcomeIsSucceeded()
{
_helper.RunOutcome.Should().Be("Succeeded");
}
#endregion
[OneTimeTearDown]
public void TearDown()
{
_helper?.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Pipelines/01-Grandparent/GrandparentHelper.cs
================================================
using FactoryTesting.Helpers;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace FactoryTesting.Pipelines.Grandparent
{
class GrandparentHelper : CoverageHelper
{
public async Task RunPipeline()
{
await RunPipeline("01-Grandparent");
}
public GrandparentHelper WithTenantAndSubscriptionIds()
{
AddTenantAndSubscription();
return this;
}
public GrandparentHelper WithSPNInDatabase(string workerFactoryName)
{
AddWorkerSPNStoredInDatabase(workerFactoryName);
return this;
}
public GrandparentHelper WithSPNInKeyVault(string workerFactoryName)
{
AddWorkerSPNStoredInKeyVault(workerFactoryName);
return this;
}
public GrandparentHelper WithBasicMetadata()
{
AddBasicMetadata();
return this;
}
public GrandparentHelper WithEmptyExecutionTables()
{
WithEmptyTable("procfwk.CurrentExecution");
WithEmptyTable("procfwk.ExecutionLog");
WithEmptyTable("procfwk.ErrorLog");
return this;
}
public GrandparentHelper WithBatchExecutionHandling()
{
ExecuteNonQuery(@$"UPDATE [procfwk].[Properties]
SET [PropertyValue] = '1'
WHERE [PropertyName] = 'UseExecutionBatches'");
return this;
}
public GrandparentHelper WithSimpleFailureHandling()
{
ExecuteNonQuery("UPDATE [procfwk].[Properties] SET [PropertyValue] = 'Simple' WHERE [PropertyName] = 'FailureHandling'");
return this;
}
public GrandparentHelper WithOneWorkerPipelineEnabled()
{
ExecuteNonQuery("UPDATE [procfwk].[Pipelines] SET [Enabled] = 0 WHERE [PipelineId] > 1");
return this;
}
public GrandparentHelper With300WorkerPipelinesEnabled()
{
ExecuteStoredProcedure("[procfwkTesting].[Add300WorkerPipelines]", null);
return this;
}
public GrandparentHelper With20BatchesFor1000WorkersEnabled()
{
ExecuteStoredProcedure("[procfwkTesting].[Add20BatchesFor1000Workers]", null);
return this;
}
public GrandparentHelper WithCustom()
{
ExecuteStoredProcedure("[dbo].[PaulTemp]", null);
return this;
}
public GrandparentHelper With300WorkerPipelineBatches()
{
ExecuteStoredProcedure("[procfwkTesting].[Add300WorkerPipelineBatches]", null);
return this;
}
}
}
================================================
FILE: FactoryTesting/Pipelines/02-Parent/Given20ConcurrentBatchesFor1000WorkerPipelines.cs
================================================
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Threading.Tasks;
namespace FactoryTesting.Pipelines.Parent
{
public class Given20ConcurrentBatchesFor1000WorkerPipelines
{
private ParentHelper _helperBatchOne;
private ParentHelper _helperBatchTwo;
private ParentHelper _helperBatchEleven;
private ParentHelper _helperBatchTwelve;
private ParentHelper _helperBatchTwenty;
private ParentHelper _helperBatchFifteen;
private ParentHelper _helperBatchSeven;
private ParentHelper _helperBatchNine;
private ParentHelper _helperBatchEight;
private ParentHelper _helperBatchSixteen;
private ParentHelper _helperBatchFive;
private ParentHelper _helperBatchSix;
private ParentHelper _helperBatchThirteen;
private ParentHelper _helperBatchNineteen;
private ParentHelper _helperBatchFour;
private ParentHelper _helperBatchEighteen;
private ParentHelper _helperBatchThree;
private ParentHelper _helperBatchFourteen;
private ParentHelper _helperBatchTen;
private ParentHelper _helperBatchSeventeen;
[OneTimeSetUp]
public async Task WhenPipelineRun()
{
/*
_helperBatchOne = new ParentHelper()
.WithBasicMetadata()
.WithTenantAndSubscriptionIds()
.WithBatchExecutionHandling()
.With20BatchesFor1000WorkersEnabled()
.WithSPNInKeyVault("WorkersFactory")
.WithParameter("BatchName", "One");
*/
_helperBatchOne = new ParentHelper()
.WithCustom()
.WithParameter("BatchName", "One");
_helperBatchTwo = new ParentHelper().WithParameter("BatchName", "Two");
_helperBatchEleven = new ParentHelper().WithParameter("BatchName", "Eleven");
_helperBatchTwelve = new ParentHelper().WithParameter("BatchName", "Twelve");
_helperBatchTwenty = new ParentHelper().WithParameter("BatchName", "Twenty");
_helperBatchFifteen = new ParentHelper().WithParameter("BatchName", "Fifteen");
_helperBatchSeven = new ParentHelper().WithParameter("BatchName", "Seven");
_helperBatchNine = new ParentHelper().WithParameter("BatchName", "Nine");
_helperBatchEight = new ParentHelper().WithParameter("BatchName", "Eight");
_helperBatchSixteen = new ParentHelper().WithParameter("BatchName", "Sixteen");
_helperBatchFive = new ParentHelper().WithParameter("BatchName", "Five");
_helperBatchSix = new ParentHelper().WithParameter("BatchName", "Six");
_helperBatchThirteen = new ParentHelper().WithParameter("BatchName", "Thirteen");
_helperBatchNineteen = new ParentHelper().WithParameter("BatchName", "Nineteen");
_helperBatchFour = new ParentHelper().WithParameter("BatchName", "Four");
_helperBatchEighteen = new ParentHelper().WithParameter("BatchName", "Eighteen");
_helperBatchThree = new ParentHelper().WithParameter("BatchName", "Three");
_helperBatchFourteen = new ParentHelper().WithParameter("BatchName", "Fourteen");
_helperBatchTen = new ParentHelper().WithParameter("BatchName", "Ten");
_helperBatchSeventeen = new ParentHelper().WithParameter("BatchName", "Seventeen");
var batchOne = _helperBatchOne.RunPipeline();
var batchTwo = _helperBatchTwo.RunPipeline();
var batchEleven = _helperBatchEleven.RunPipeline();
var batchTwelve = _helperBatchTwelve.RunPipeline();
var batchTwenty = _helperBatchTwenty.RunPipeline();
var batchFifteen = _helperBatchFifteen.RunPipeline();
var batchSeven = _helperBatchSeven.RunPipeline();
var batchNine = _helperBatchNine.RunPipeline();
var batchEight = _helperBatchEight.RunPipeline();
var batchSixteen = _helperBatchSixteen.RunPipeline();
var batchFive = _helperBatchFive.RunPipeline();
var batchSix = _helperBatchSix.RunPipeline();
var batchThirteen = _helperBatchThirteen.RunPipeline();
var batchNineteen = _helperBatchNineteen.RunPipeline();
var batchFour = _helperBatchFour.RunPipeline();
var batchEighteen = _helperBatchEighteen.RunPipeline();
var batchThree = _helperBatchThree.RunPipeline();
var batchFourteen = _helperBatchFourteen.RunPipeline();
var batchTen = _helperBatchTen.RunPipeline();
var batchSeventeen = _helperBatchSeventeen.RunPipeline();
//await _helperBatchOne.RunPipeline();
await Task.WhenAll(
batchOne,
batchTwo,
batchEleven,
batchTwelve,
batchTwenty,
batchFifteen,
batchSeven,
batchNine,
batchEight,
batchSixteen,
batchFive,
batchSix,
batchThirteen,
batchNineteen,
batchFour,
batchEighteen,
batchThree,
batchFourteen,
batchTen,
batchSeventeen
);
}
#region Integration tests
[Test]
public void ThenOneBatchPipelineOutcomeIsSucceeded()
{
_helperBatchOne.RunOutcome.Should().Be("Succeeded");
}
[Test]
public void ThenTwoBatchPipelineOutcomeIsSucceeded()
{
_helperBatchTwo.RunOutcome.Should().Be("Succeeded");
}
[Test]
public void ThenElevenBatchPipelineOutcomeIsSucceeded()
{
_helperBatchEleven.RunOutcome.Should().Be("Succeeded");
}
[Test]
public void ThenTwelveBatchPipelineOutcomeIsSucceeded()
{
_helperBatchTwelve.RunOutcome.Should().Be("Succeeded");
}
[Test]
public void ThenTwentyBatchPipelineOutcomeIsSucceeded()
{
_helperBatchTwenty.RunOutcome.Should().Be("Succeeded");
}
[Test]
public void ThenFifteenBatchPipelineOutcomeIsSucceeded()
{
_helperBatchFifteen.RunOutcome.Should().Be("Succeeded");
}
[Test]
public void ThenSevenBatchPipelineOutcomeIsSucceeded()
{
_helperBatchSeven.RunOutcome.Should().Be("Succeeded");
}
[Test]
public void ThenNineBatchPipelineOutcomeIsSucceeded()
{
_helperBatchNine.RunOutcome.Should().Be("Succeeded");
}
[Test]
public void ThenEightBatchPipelineOutcomeIsSucceeded()
{
_helperBatchEight.RunOutcome.Should().Be("Succeeded");
}
[Test]
public void ThenSixteenBatchPipelineOutcomeIsSucceeded()
{
_helperBatchSixteen.RunOutcome.Should().Be("Succeeded");
}
[Test]
public void ThenFiveBatchPipelineOutcomeIsSucceeded()
{
_helperBatchFive.RunOutcome.Should().Be("Succeeded");
}
[Test]
public void ThenSixBatchPipelineOutcomeIsSucceeded()
{
_helperBatchSix.RunOutcome.Should().Be("Succeeded");
}
[Test]
public void ThenThirteenBatchPipelineOutcomeIsSucceeded()
{
_helperBatchThirteen.RunOutcome.Should().Be("Succeeded");
}
[Test]
public void ThenNineteenBatchPipelineOutcomeIsSucceeded()
{
_helperBatchNineteen.RunOutcome.Should().Be("Succeeded");
}
[Test]
public void ThenFourBatchPipelineOutcomeIsSucceeded()
{
_helperBatchFour.RunOutcome.Should().Be("Succeeded");
}
[Test]
public void ThenEighteenBatchPipelineOutcomeIsSucceeded()
{
_helperBatchEighteen.RunOutcome.Should().Be("Succeeded");
}
[Test]
public void ThenThreeBatchPipelineOutcomeIsSucceeded()
{
_helperBatchThree.RunOutcome.Should().Be("Succeeded");
}
[Test]
public void ThenFourteenBatchPipelineOutcomeIsSucceeded()
{
_helperBatchFourteen.RunOutcome.Should().Be("Succeeded");
}
[Test]
public void ThenTenBatchPipelineOutcomeIsSucceeded()
{
_helperBatchTen.RunOutcome.Should().Be("Succeeded");
}
[Test]
public void ThenSeventeenBatchPipelineOutcomeIsSucceeded()
{
_helperBatchSeventeen.RunOutcome.Should().Be("Succeeded");
}
[Test]
public void Then1000ExecutionLogRecords()
{
_helperBatchOne.RowCount("procfwk.ExecutionLog").Should().Be(1000);
}
#endregion
/*
[OneTimeTearDown]
public void TearDown()
{
_helperBatchOne?.TearDown();
}
*/
}
}
================================================
FILE: FactoryTesting/Pipelines/02-Parent/GivenAlreadyRunning.cs
================================================
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Threading.Tasks;
namespace FactoryTesting.Pipelines.Parent
{
public class GivenAlreadyRunning
{
private ParentHelper _helperRunOne;
private ParentHelper _helperRunTwo;
[OneTimeSetUp]
public async Task WhenPipelineRun()
{
_helperRunOne = new ParentHelper()
.WithBasicMetadata()
.WithTenantAndSubscriptionIds()
.WithSPNInDatabase("FrameworkFactory")
.WithEmptyExecutionTables()
.WithoutSimulatedError()
.WithFailureHandling("Simple");
_helperRunTwo = new ParentHelper();
var firstRun = _helperRunOne.RunPipeline();
var secondRun = _helperRunTwo.RunPipeline(15000); //15 second delay in run
await Task.WhenAll(firstRun, secondRun);
}
[Test]
public void ThenFirstPipelineOutcomeIsSucceeded()
{
_helperRunOne.RunOutcome.Should().Be("Succeeded");
}
[Test]
public void ThenSecondPipelineOutcomeIsFailed()
{
_helperRunTwo.RunOutcome.Should().Be("Failed");
}
[Test]
public void ThenCurrentExecutionTableIsEmpty()
{
_helperRunOne.RowCount("procfwk.CurrentExecution").Should().Be(0);
}
[Test]
public void ThenElevenExecutionLogRecords()
{
_helperRunOne.RowCount("procfwk.ExecutionLog").Should().Be(11);
}
[OneTimeTearDown]
public void TearDown()
{
_helperRunOne?.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Pipelines/02-Parent/GivenBatchExecutionsForConcurrentBatches.cs
================================================
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Threading.Tasks;
namespace FactoryTesting.Pipelines.Parent
{
public class GivenBatchExecutionsForConcurrentBatches
{
private ParentHelper _helperFirstBatch;
private ParentHelper _helperSecondBatch;
[OneTimeSetUp]
public async Task WhenPipelineRun()
{
_helperFirstBatch = new ParentHelper()
.WithBasicMetadata()
.WithTenantAndSubscriptionIds()
.WithSPNInDatabase("FrameworkFactory")
.WithEmptyExecutionTables()
.WithBatchExecutionHandling()
.WithStagesEnabled()
.WithPipelinesEnabled()
.WithParameter("BatchName", "Hourly");
_helperSecondBatch = new ParentHelper()
.WithParameter("BatchName", "Daily");
var firstBatch = _helperFirstBatch.RunPipeline();
var secondBatch = _helperSecondBatch.RunPipeline();
await Task.WhenAll(firstBatch, secondBatch);
}
#region Integration tests
[Test]
public void ThenFirstBatchPipelineOutcomeIsSucceeded()
{
_helperFirstBatch.RunOutcome.Should().Be("Succeeded");
}
[Test]
public void ThenSecondBatchPipelineOutcomeIsSucceeded()
{
_helperSecondBatch.RunOutcome.Should().Be("Succeeded");
}
[Test]
public void ThenCurrentExecutionTableIsEmpty()
{
_helperFirstBatch.RowCount("procfwk.CurrentExecution").Should().Be(0);
}
[Test]
public void ThenFifteenExecutionLogSuccessRecords()
{
_helperFirstBatch.RowCount("procfwk.ExecutionLog", where: "PipelineStatus", equals: "Success").Should().Be(15);
}
[Test]
public void ThenTwoBatchExecutionSuccessRecords()
{
_helperFirstBatch.RowCount("procfwk.BatchExecution", where: "BatchStatus", equals: "Success").Should().Be(2);
}
#endregion
[OneTimeTearDown]
public void TearDown()
{
_helperFirstBatch?.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Pipelines/02-Parent/GivenBatchExecutionsForConcurrentBatchesAlreadyRunning.cs
================================================
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Threading.Tasks;
namespace FactoryTesting.Pipelines.Parent
{
public class GivenBatchExecutionsForConcurrentBatchesAlreadyRunning
{
private ParentHelper _helperFirstBatch;
private ParentHelper _helperSecondBatch;
[OneTimeSetUp]
public async Task WhenPipelineRun()
{
_helperFirstBatch = new ParentHelper()
.WithBasicMetadata()
.WithTenantAndSubscriptionIds()
.WithSPNInDatabase("FrameworkFactory")
.WithEmptyExecutionTables()
.WithBatchExecutionHandling()
.WithStagesEnabled()
.WithPipelinesEnabled()
.WithParameter("BatchName", "Hourly");
_helperSecondBatch = new ParentHelper()
.WithParameter("BatchName", "Hourly");
var firstBatch = _helperFirstBatch.RunPipeline();
var secondBatch = _helperSecondBatch.RunPipeline(15000); //15 second delay in run
await Task.WhenAll(firstBatch, secondBatch);
}
#region Integration tests
[Test]
public void ThenFirstBatchPipelineOutcomeIsSucceeded()
{
_helperFirstBatch.RunOutcome.Should().Be("Succeeded");
}
[Test]
public void ThenSecondBatchPipelineOutcomeIsFailed()
{
_helperSecondBatch.RunOutcome.Should().Be("Failed");
}
[Test]
public void ThenCurrentExecutionTableIsEmpty()
{
_helperFirstBatch.RowCount("procfwk.CurrentExecution").Should().Be(0);
}
[Test]
public void ThenFourExecutionLogSuccessRecords()
{
_helperFirstBatch.RowCount("procfwk.ExecutionLog", where: "PipelineStatus", equals: "Success").Should().Be(4);
}
[Test]
public void ThenOneBatchExecutionSuccessRecord()
{
_helperFirstBatch.RowCount("procfwk.BatchExecution", where: "BatchStatus", equals: "Success").Should().Be(1);
}
#endregion
[OneTimeTearDown]
public void TearDown()
{
_helperFirstBatch?.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Pipelines/02-Parent/GivenBatchExecutionsForConcurrentBatchesWithSimpleFailureHandling.cs
================================================
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Threading.Tasks;
namespace FactoryTesting.Pipelines.Parent
{
public class GivenBatchExecutionsForConcurrentBatchesWithSimpleFailureHandling
{
private ParentHelper _helperFirstBatch;
private ParentHelper _helperSecondBatch;
[OneTimeSetUp]
public async Task WhenPipelineRun()
{
_helperFirstBatch = new ParentHelper()
.WithBasicMetadata()
.WithTenantAndSubscriptionIds()
.WithSPNInDatabase("FrameworkFactory")
.WithEmptyExecutionTables()
.WithBatchExecutionHandling()
.WithStagesEnabled()
.WithPipelinesEnabled()
.WithParameter("BatchName", "Hourly");
_helperSecondBatch = new ParentHelper()
.WithSimulatedError()
.WithFailureHandling("Simple")
.WithParameter("BatchName", "Daily");
var firstBatch = _helperFirstBatch.RunPipeline();
var secondBatch = _helperSecondBatch.RunPipeline();
await Task.WhenAll(firstBatch, secondBatch);
}
#region Integration tests
//batch one - hourly:
[Test]
public void ThenFirstBatchPipelineOutcomeIsSucceeded()
{
_helperFirstBatch.RunOutcome.Should().Be("Succeeded");
}
[Test]
public void ThenOneBatchExecutionSuccessRecord()
{
_helperFirstBatch.RowCount("procfwk.BatchExecution", where: "BatchStatus", equals: "Success").Should().Be(1);
}
[Test]
public void ThenFourExecutionLogSuccessRecords()
{
_helperFirstBatch.RowCount("procfwk.ExecutionLog", where: "PipelineStatus", equals: "Success").Should().Be(4);
}
//batch two - daily:
[Test]
public void ThenSecondBatchPipelineOutcomeIsFailed()
{
_helperSecondBatch.RunOutcome.Should().Be("Failed");
}
[Test]
public void ThenOneBatchExecutionStoppedRecord()
{
_helperSecondBatch.RowCount("procfwk.BatchExecution", where: "BatchStatus", equals: "Stopped").Should().Be(1);
}
[Test]
public void ThenThreeExecutionsSucceeded()
{
_helperSecondBatch.RowCount("procfwk.CurrentExecution", where: "PipelineStatus", equals: "Success").Should().Be(3);
}
[Test]
public void ThenOneExecutionFailed()
{
_helperSecondBatch.RowCount("procfwk.CurrentExecution", where: "PipelineStatus", equals: "Failed").Should().Be(1);
}
[Test]
public void ThenSevenExecutionsBlocked()
{
_helperSecondBatch.RowCount("procfwk.CurrentExecution", where: "PipelineStatus", equals: "Blocked").Should().Be(7);
}
[Test]
public void ThenOneExecutionLogRecord()
{
_helperSecondBatch.RowCount("procfwk.ExecutionLog", where: "PipelineStatus", equals: "Failed").Should().Be(1);
}
[Test]
public void ThenTwoErrorLogRecords()
{
_helperSecondBatch.RowCount("procfwk.ErrorLog").Should().Be(2);
}
#endregion
[OneTimeTearDown]
public void TearDown()
{
_helperFirstBatch?.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Pipelines/02-Parent/GivenBatchExecutionsForConcurrentBatchesWithSimpleFailureHandlingAndRestart.cs
================================================
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Threading.Tasks;
namespace FactoryTesting.Pipelines.Parent
{
public class GivenBatchExecutionsForConcurrentBatchesWithSimpleFailureHandlingAndRestart
{
private ParentHelper _helperFirstBatch;
private ParentHelper _helperSecondBatch;
private ParentHelper _helperSecondBatchRestart;
private ParentHelper _helperThirdBatch;
[OneTimeSetUp]
public async Task WhenPipelineRun()
{
//first
_helperFirstBatch = new ParentHelper()
.WithBasicMetadata()
.WithTenantAndSubscriptionIds()
.WithSPNInDatabase("FrameworkFactory")
.WithEmptyExecutionTables()
.WithBatchExecutionHandling()
.WithStagesEnabled()
.WithPipelinesEnabled()
.WithParameter("BatchName", "Hourly");
_helperSecondBatch = new ParentHelper()
.WithSimulatedError()
.WithFailureHandling("Simple")
.WithParameter("BatchName", "Daily");
var firstBatch = _helperFirstBatch.RunPipeline();
var secondBatch = _helperSecondBatch.RunPipeline();
await Task.WhenAll(firstBatch, secondBatch);
//then
_helperSecondBatchRestart = new ParentHelper()
.WithoutSimulatedError()
.WithParameter("BatchName", "Daily");
_helperThirdBatch = new ParentHelper()
.WithParameter("BatchName", "Hourly");
var secondBatchRestart = _helperSecondBatchRestart.RunPipeline(10000); //10 second delay
var thirdBatch = _helperThirdBatch.RunPipeline();
await Task.WhenAll(secondBatchRestart, thirdBatch);
}
#region Integration tests
//batch one - hourly:
[Test]
public void ThenFirstBatchPipelineOutcomeIsSucceeded()
{
_helperFirstBatch.RunOutcome.Should().Be("Succeeded");
}
//batch two - daily:
[Test]
public void ThenSecondBatchPipelineOutcomeIsFailed()
{
_helperSecondBatch.RunOutcome.Should().Be("Failed");
}
//batch two restart - daily:
[Test]
public void ThenSecondBatchRestartPipelineOutcomeIsSucceeded()
{
_helperSecondBatchRestart.RunOutcome.Should().Be("Succeeded");
}
//batch three - hourly:
[Test]
public void ThenThirdBatchPipelineOutcomeIsSucceeded()
{
_helperThirdBatch.RunOutcome.Should().Be("Succeeded");
}
#endregion
#region Functional Tests
[Test]
public void ThenThreeBatchExecutionSuccessRecords()
{
_helperThirdBatch.RowCount("procfwk.BatchExecution", where: "BatchStatus", equals: "Success").Should().Be(3);
}
[Test]
public void ThenNineteenExecutionLogSuccessRecords()
{
_helperThirdBatch.RowCount("procfwk.ExecutionLog", where: "PipelineStatus", equals: "Success").Should().Be(19);
}
[Test]
public void ThenOneExecutionLogRecord()
{
_helperThirdBatch.RowCount("procfwk.ExecutionLog", where: "PipelineStatus", equals: "Failed").Should().Be(1);
}
[Test]
public void ThenTwoErrorLogRecords()
{
_helperThirdBatch.RowCount("procfwk.ErrorLog").Should().Be(2);
}
[Test]
public void ThenCurrentExecutionTableIsEmpty()
{
_helperThirdBatch.RowCount("procfwk.CurrentExecution").Should().Be(0);
}
#endregion
[OneTimeTearDown]
public void TearDown()
{
_helperThirdBatch?.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Pipelines/02-Parent/GivenBatchExecutionsForConcurrentBatchesWithSimpleFailureHandlingAndRestartOveride.cs
================================================
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Threading.Tasks;
namespace FactoryTesting.Pipelines.Parent
{
public class GivenBatchExecutionsForConcurrentBatchesWithSimpleFailureHandlingAndRestartOveride
{
private ParentHelper _helperFirstBatch;
private ParentHelper _helperSecondBatch;
private ParentHelper _helperSecondBatchRestart;
private ParentHelper _helperThirdBatch;
[OneTimeSetUp]
public async Task WhenPipelineRun()
{
//first
_helperFirstBatch = new ParentHelper()
.WithBasicMetadata()
.WithTenantAndSubscriptionIds()
.WithSPNInDatabase("FrameworkFactory")
.WithEmptyExecutionTables()
.WithBatchExecutionHandling()
.WithStagesEnabled()
.WithPipelinesEnabled()
.WithParameter("BatchName", "Hourly");
_helperSecondBatch = new ParentHelper()
.WithSimulatedError()
.WithFailureHandling("Simple")
.WithParameter("BatchName", "Daily");
var firstBatch = _helperFirstBatch.RunPipeline();
var secondBatch = _helperSecondBatch.RunPipeline();
await Task.WhenAll(firstBatch, secondBatch);
//then
_helperSecondBatchRestart = new ParentHelper()
.WithoutSimulatedError()
.WithOverideRestart(true)
.WithParameter("BatchName", "Daily");
_helperThirdBatch = new ParentHelper()
.WithParameter("BatchName", "Hourly");
var secondBatchRestart = _helperSecondBatchRestart.RunPipeline(10000); //10 second delay
var thirdBatch = _helperThirdBatch.RunPipeline();
await Task.WhenAll(secondBatchRestart, thirdBatch);
}
#region Integration tests
//batch one - hourly:
[Test]
public void ThenFirstBatchPipelineOutcomeIsSucceeded()
{
_helperFirstBatch.RunOutcome.Should().Be("Succeeded");
}
//batch two - daily:
[Test]
public void ThenSecondBatchPipelineOutcomeIsFailed()
{
_helperSecondBatch.RunOutcome.Should().Be("Failed");
}
//batch two restart - daily:
[Test]
public void ThenSecondBatchRestartPipelineOutcomeIsSucceeded()
{
_helperSecondBatchRestart.RunOutcome.Should().Be("Succeeded");
}
//batch three - hourly:
[Test]
public void ThenThirdBatchPipelineOutcomeIsSucceeded()
{
_helperThirdBatch.RunOutcome.Should().Be("Succeeded");
}
#endregion
#region Functional Tests
[Test]
public void ThenThreeBatchExecutionSuccessRecords()
{
_helperThirdBatch.RowCount("procfwk.BatchExecution", where: "BatchStatus", equals: "Success").Should().Be(3);
}
[Test]
public void ThenOneBatchExecutionAbandonedRecord()
{
_helperThirdBatch.RowCount("procfwk.BatchExecution", where: "BatchStatus", equals: "Abandoned").Should().Be(1);
}
[Test]
public void ThenTwentyTwoExecutionLogSuccessRecords()
{
_helperThirdBatch.RowCount("procfwk.ExecutionLog", where: "PipelineStatus", equals: "Success").Should().Be(22);
}
[Test]
public void ThenOneExecutionLogRecord()
{
_helperThirdBatch.RowCount("procfwk.ExecutionLog", where: "PipelineStatus", equals: "Failed").Should().Be(2);
}
[Test]
public void ThenSevenExecutionsBlocked()
{
_helperThirdBatch.RowCount("procfwk.ExecutionLog", where: "PipelineStatus", equals: "Blocked").Should().Be(7);
}
[Test]
public void ThenTwoErrorLogRecords()
{
_helperThirdBatch.RowCount("procfwk.ErrorLog").Should().Be(2);
}
[Test]
public void ThenCurrentExecutionTableIsEmpty()
{
_helperThirdBatch.RowCount("procfwk.CurrentExecution").Should().Be(0);
}
#endregion
[OneTimeTearDown]
public void TearDown()
{
_helperThirdBatch?.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Pipelines/02-Parent/GivenBatchExecutionsForSingleBatch.cs
================================================
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Threading.Tasks;
namespace FactoryTesting.Pipelines.Parent
{
public class GivenBatchExecutionsForSingleBatch
{
private ParentHelper _helper;
[OneTimeSetUp]
public async Task WhenPipelineRun()
{
_helper = new ParentHelper()
.WithBasicMetadata()
.WithTenantAndSubscriptionIds()
.WithSPNInDatabase("FrameworkFactory")
.WithEmptyExecutionTables()
.WithBatchExecutionHandling()
.WithStagesEnabled()
.WithPipelinesEnabled()
.WithParameter("BatchName", "Hourly");
await _helper.RunPipeline();
}
#region Functional tests
[Test]
public void ThenPipelineOutcomeIsSucceeded()
{
_helper.RunOutcome.Should().Be("Succeeded");
}
[Test]
public void ThenCurrentExecutionTableIsEmpty()
{
_helper.RowCount("procfwk.CurrentExecution").Should().Be(0);
}
[Test]
public void ThenFourExecutionLogSuccessRecords()
{
_helper.RowCount("procfwk.ExecutionLog", where: "PipelineStatus", equals: "Success").Should().Be(4);
}
[Test]
public void ThenOneBatchExecutionSuccessRecord()
{
_helper.RowCount("procfwk.BatchExecution", where: "BatchStatus", equals: "Success").Should().Be(1);
}
#endregion
[OneTimeTearDown]
public void TearDown()
{
_helper?.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Pipelines/02-Parent/GivenCancelledWorkerAndRestart.cs
================================================
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Threading.Tasks;
namespace FactoryTesting.Pipelines.Parent
{
public class GivenCancelledWorkerAndRestart
{
private ParentHelper _helperFirstRun;
private ParentHelper _helperRestartRun;
[OneTimeSetUp]
public async Task WhenPipelineRun()
{
_helperFirstRun = new ParentHelper()
.WithBasicMetadata()
.WithTenantAndSubscriptionIds()
.WithSPNInDatabase("FrameworkFactory")
.WithEmptyExecutionTables()
.WithoutPrecursorObject() //done to ensure 2min waits are used, not example precursor waits
.With2MinWaitsOnWorkers() //to ensure the cancel call has enough time
.WithCancelledWorkersBlock(true)
.WithFailureHandling("Simple");
var runOrchestrator = _helperFirstRun.RunPipeline();
var cancelWorker = _helperFirstRun.CancelAnyWorkerPipeline();
await Task.WhenAll(runOrchestrator, cancelWorker);
_helperRestartRun = new ParentHelper();
await _helperRestartRun.RunPipeline();
}
#region Integration tests
[Test]
public void ThenPipelineOutcomeIsSucceeded()
{
_helperRestartRun.RunOutcome.Should().Be("Succeeded");
}
[Test]
public void ThenOneExecutionLogRecord()
{
_helperRestartRun.RowCount("procfwk.ExecutionLog", where: "PipelineStatus", equals: "Cancelled").Should().Be(1);
}
[Test]
public void ThenElevenExecutionsSucceeded()
{
_helperRestartRun.RowCount("procfwk.ExecutionLog", where: "PipelineStatus", equals: "Success").Should().Be(11);
}
#endregion
[OneTimeTearDown]
public void TearDown()
{
_helperRestartRun?.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Pipelines/02-Parent/GivenCancelledWorkerInOneExecutionStage.cs
================================================
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Threading.Tasks;
namespace FactoryTesting.Pipelines.Parent
{
public class GivenCancelledWorkerInOneExecutionStage
{
private ParentHelper _helper;
[OneTimeSetUp]
public async Task WhenPipelineRun()
{
_helper = new ParentHelper()
.WithBasicMetadata()
.WithTenantAndSubscriptionIds()
.WithSPNInDatabase("FrameworkFactory")
.WithEmptyExecutionTables()
.WithoutPrecursorObject() //done to ensure 2min waits are used, not example precursor waits
.With2MinWaitsOnWorkers() //to ensure the cancel call has enough time
.WithCancelledWorkersBlock(false)
.WithOnlyStageOneEnabled();
var runOrchestrator = _helper.RunPipeline();
var cancelWorker = _helper.CancelAnyWorkerPipeline(); //any worker
await Task.WhenAll(runOrchestrator, cancelWorker);
}
#region Integration tests
[Test]
public void ThenPipelineOutcomeIsFailed()
{
_helper.RunOutcome.Should().Be("Failed");
}
[Test]
public void ThenOneExecutionsCancelled()
{
_helper.RowCount("procfwk.CurrentExecution", where: "PipelineStatus", equals: "Cancelled").Should().Be(1);
}
[Test]
public void ThenOneExecutionLogRecord()
{
_helper.RowCount("procfwk.ExecutionLog", where: "PipelineStatus", equals: "Cancelled").Should().Be(1);
}
[Test]
public void ThenThreeExecutionsSucceeded()
{
_helper.RowCount("procfwk.CurrentExecution", where: "PipelineStatus", equals: "Success").Should().Be(3);
}
#endregion
[OneTimeTearDown]
public void TearDown()
{
_helper?.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Pipelines/02-Parent/GivenCancelledWorkerThatBlocks.cs
================================================
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Threading.Tasks;
namespace FactoryTesting.Pipelines.Parent
{
public class GivenCancelledWorkerThatBlocks
{
private ParentHelper _helper;
[OneTimeSetUp]
public async Task WhenPipelineRun()
{
_helper = new ParentHelper()
.WithBasicMetadata()
.WithTenantAndSubscriptionIds()
.WithSPNInDatabase("FrameworkFactory")
.WithEmptyExecutionTables()
.WithoutPrecursorObject() //done to ensure 2min waits are used, not example precursor waits
.With2MinWaitsOnWorkers() //to ensure the cancel call has enough time
.WithCancelledWorkersBlock(true)
.WithFailureHandling("Simple");
var runOrchestrator = _helper.RunPipeline();
var cancelWorker = _helper.CancelIntentionalErrorWorkerPipeline(); //specific worker
await Task.WhenAll(runOrchestrator, cancelWorker);
}
#region Integration tests
[Test]
public void ThenPipelineOutcomeIsFailed()
{
_helper.RunOutcome.Should().Be("Failed");
}
[Test]
public void ThenOneExecutionsCancelled()
{
_helper.RowCount("procfwk.CurrentExecution", where: "PipelineStatus", equals: "Cancelled").Should().Be(1);
}
[Test]
public void ThenOneExecutionLogRecord()
{
_helper.RowCount("procfwk.ExecutionLog", where: "PipelineStatus", equals: "Cancelled").Should().Be(1);
}
[Test]
public void ThenThreeExecutionsSucceeded()
{
_helper.RowCount("procfwk.CurrentExecution", where: "PipelineStatus", equals: "Success").Should().Be(3);
}
[Test]
public void ThenSevenExecutionsBlocked()
{
_helper.RowCount("procfwk.CurrentExecution", where: "PipelineStatus", equals: "Blocked").Should().Be(7);
}
#endregion
[OneTimeTearDown]
public void TearDown()
{
_helper?.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Pipelines/02-Parent/GivenCancelledWorkerThatDoesntBlock.cs
================================================
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Threading.Tasks;
namespace FactoryTesting.Pipelines.Parent
{
public class GivenCancelledWorkerThatDoesntBlock
{
private ParentHelper _helper;
[OneTimeSetUp]
public async Task WhenPipelineRun()
{
_helper = new ParentHelper()
.WithBasicMetadata()
.WithTenantAndSubscriptionIds()
.WithSPNInDatabase("FrameworkFactory")
.WithEmptyExecutionTables()
.WithoutPrecursorObject() //done to ensure 2min waits are used, not example precursor waits
.With2MinWaitsOnWorkers() //to ensure the cancel call has enough time
.WithCancelledWorkersBlock(false)
.WithFailureHandling("Simple");
var runOrchestrator = _helper.RunPipeline();
var cancelWorker = _helper.CancelIntentionalErrorWorkerPipeline(); //specific worker
await Task.WhenAll(runOrchestrator, cancelWorker);
}
#region Integration tests
[Test]
public void ThenPipelineOutcomeIsFailed()
{
_helper.RunOutcome.Should().Be("Failed");
}
[Test]
public void ThenOneExecutionsCancelled()
{
_helper.RowCount("procfwk.CurrentExecution", where: "PipelineStatus", equals: "Cancelled").Should().Be(1);
}
[Test]
public void ThenOneExecutionLogRecord()
{
_helper.RowCount("procfwk.ExecutionLog", where: "PipelineStatus", equals: "Cancelled").Should().Be(1);
}
[Test]
public void ThenTenExecutionsSucceeded()
{
_helper.RowCount("procfwk.CurrentExecution", where: "PipelineStatus", equals: "Success").Should().Be(10);
}
#endregion
[OneTimeTearDown]
public void TearDown()
{
_helper?.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Pipelines/02-Parent/GivenCleanUpForCancelledWorkerAndRestart.cs
================================================
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Threading.Tasks;
namespace FactoryTesting.Pipelines.Parent
{
public class GivenCleanUpForCancelledWorkerAndRestart
{
private ParentHelper _helperFirstRun;
private ParentHelper _helperRestartRun;
[OneTimeSetUp]
public async Task WhenPipelineRun()
{
_helperFirstRun = new ParentHelper()
.WithBasicMetadata()
.WithTenantAndSubscriptionIds()
.WithSPNInDatabase("FrameworkFactory")
.WithEmptyExecutionTables()
.WithoutPrecursorObject() //done to ensure 2min waits are used, not example precursor waits
.With2MinWaitsOnWorkers() //to ensure the cancel call has enough time
.WithCancelledWorkersBlock(true)
.WithFailureHandling("Simple");
var runOrchestrator = _helperFirstRun.RunPipeline();
var cancelWorker = _helperFirstRun.CancelAnyWorkerPipeline();
await Task.WhenAll(runOrchestrator, cancelWorker);
_helperRestartRun = new ParentHelper()
.WithPrecursorObject()
.WithRunningPipelineStatusInPlaceOf("Cancelled");
await _helperRestartRun.RunPipeline();
}
#region Integration tests
[Test]
public void ThenPipelineOutcomeIsSucceeded()
{
_helperRestartRun.RunOutcome.Should().Be("Succeeded");
}
[Test]
public async Task ThenActivityShouldReturnOneRowForCleanUp()
{
var count = await _helperRestartRun.GetActivityOutput("Check Previous Execution", "$.count");
int.Parse(count).Should().Be(1);
}
[Test]
public void ThenOneExecutionLogRecord()
{
_helperRestartRun.RowCount("procfwk.ExecutionLog", where: "PipelineStatus", equals: "Cancelled").Should().Be(1);
}
[Test]
public void ThenElevenExecutionsSucceeded()
{
_helperRestartRun.RowCount("procfwk.ExecutionLog", where: "PipelineStatus", equals: "Success").Should().Be(11);
}
#endregion
[OneTimeTearDown]
public void TearDown()
{
_helperRestartRun?.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Pipelines/02-Parent/GivenCleanUpForSuccessfulWorkersAndRestart.cs
================================================
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Threading.Tasks;
namespace FactoryTesting.Pipelines.Parent
{
public class GivenCleanUpForSuccessfulWorkersAndRestart
{
private ParentHelper _helperFirstRun;
private ParentHelper _helperRestartRun;
[OneTimeSetUp]
public async Task WhenPipelineRun()
{
_helperFirstRun = new ParentHelper()
.WithBasicMetadata()
.WithTenantAndSubscriptionIds()
.WithSPNInDatabase("FrameworkFactory")
.WithEmptyExecutionTables()
.WithoutPrecursorObject() //done to ensure 2min waits are used, not example precursor waits
.With2MinWaitsOnWorkers() //to ensure the cancel call has enough time
.WithCancelledWorkersBlock(true)
.WithFailureHandling("Simple");
var runOrchestrator = _helperFirstRun.RunPipeline();
var cancelWorker = _helperFirstRun.CancelAnyWorkerPipeline();
await Task.WhenAll(runOrchestrator, cancelWorker);
_helperRestartRun = new ParentHelper()
.WithPrecursorObject()
.WithRunningPipelineStatusInPlaceOf("Success");
await _helperRestartRun.RunPipeline();
}
[Test]
public void ThenPipelineOutcomeIsSucceeded()
{
_helperRestartRun.RunOutcome.Should().Be("Succeeded");
}
[Test]
public async Task ThenActivityShouldReturnThreeRowsForCleanUp()
{
var count = await _helperRestartRun.GetActivityOutput("Check Previous Execution", "$.count");
int.Parse(count).Should().Be(3);
}
[Test]
public void ThenOneExecutionLogRecord()
{
_helperRestartRun.RowCount("procfwk.ExecutionLog", where: "PipelineStatus", equals: "Cancelled").Should().Be(1);
}
[Test]
public void ThenElevenExecutionsSucceeded()
{
_helperRestartRun.RowCount("procfwk.ExecutionLog", where: "PipelineStatus", equals: "Success").Should().Be(11);
}
[OneTimeTearDown]
public void TearDown()
{
_helperRestartRun?.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Pipelines/02-Parent/GivenDependencyChainFailureHandling.cs
================================================
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Threading.Tasks;
namespace FactoryTesting.Pipelines.Parent
{
public class GivenDependencyChainFailureHandling
{
private ParentHelper _helper;
[OneTimeSetUp]
public async Task WhenPipelineRun()
{
_helper = new ParentHelper()
.WithBasicMetadata()
.WithTenantAndSubscriptionIds()
.WithSPNInDatabase("FrameworkFactory")
.WithEmptyExecutionTables()
.WithSimulatedError()
.WithFailureHandling("DependencyChain");
await _helper.RunPipeline();
}
#region Functional tests
[Test, Order(1)]
public void ThenPipelineOutcomeIsFailed()
{
_helper.RunOutcome.Should().Be("Failed");
}
[Test, Order(2)]
public void ThenSixExecutionsSucceeded()
{
_helper.RowCount("procfwk.CurrentExecution", where: "PipelineStatus", equals: "Success").Should().Be(6);
}
[Test, Order(3)]
public void ThenOneExecutionFailed()
{
_helper.RowCount("procfwk.CurrentExecution", where: "PipelineStatus", equals: "Failed").Should().Be(1);
}
[Test, Order(4)]
public void ThenFourExecutionsBlocked()
{
_helper.RowCount("procfwk.CurrentExecution", where: "PipelineStatus", equals: "Blocked").Should().Be(4);
}
[Test, Order(5)]
public void ThenOneExecutionLogRecord()
{
_helper.RowCount("procfwk.ExecutionLog", where: "PipelineStatus", equals: "Failed").Should().Be(1);
}
[Test, Order(6)]
public void ThenTwoErrorLogRecords()
{
_helper.RowCount("procfwk.ErrorLog").Should().Be(2);
}
#endregion
[OneTimeTearDown]
public void TearDown()
{
_helper?.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Pipelines/02-Parent/GivenDependencyChainFailureHandlingAndRestart.cs
================================================
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Threading.Tasks;
namespace FactoryTesting.Pipelines.Parent
{
public class GivenDependencyChainFailureHandlingAndRestart
{
private ParentHelper _helperFirstRun;
private ParentHelper _helperRestartRun;
[OneTimeSetUp]
public async Task WhenPipelineRun()
{
_helperFirstRun = new ParentHelper()
.WithBasicMetadata()
.WithTenantAndSubscriptionIds()
.WithSPNInDatabase("FrameworkFactory")
.WithEmptyExecutionTables()
.WithSimulatedError()
.WithFailureHandling("DependencyChain");
await _helperFirstRun.RunPipeline();
_helperRestartRun = new ParentHelper()
.WithoutSimulatedError();
await _helperRestartRun.RunPipeline();
}
#region Functional tests
[Test]
public void ThenPipelineOutcomeIsSucceeded()
{
_helperRestartRun.RunOutcome.Should().Be("Succeeded");
}
[Test]
public void ThenOneExecutionLogFailedRecord()
{
_helperRestartRun.RowCount("procfwk.ExecutionLog", where: "PipelineStatus", equals: "Failed").Should().Be(1);
}
[Test]
public void ThenElevenExecutionLogSuccessRecord()
{
_helperRestartRun.RowCount("procfwk.ExecutionLog", where: "PipelineStatus", equals: "Success").Should().Be(11);
}
[Test]
public void ThenTwoErrorLogRecords()
{
_helperRestartRun.RowCount("procfwk.ErrorLog").Should().Be(2);
}
#endregion
[OneTimeTearDown]
public void TearDown()
{
_helperFirstRun?.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Pipelines/02-Parent/GivenDisabledBatches.cs
================================================
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Threading.Tasks;
namespace FactoryTesting.Pipelines.Parent
{
public class GivenDisabledBatches
{
private ParentHelper _helper;
[OneTimeSetUp]
public async Task WhenPipelineRun()
{
_helper = new ParentHelper()
.WithBasicMetadata()
.WithTenantAndSubscriptionIds()
.WithSPNInDatabase("FrameworkFactory")
.WithEmptyExecutionTables()
.WithBatchExecutionHandling()
.WithBatchesDisabled();
await _helper.RunPipeline();
}
#region Integration tests
[Test]
public void ThenPipelineOutcomeIsFailed()
{
_helper.RunOutcome.Should().Be("Failed");
}
#endregion
[OneTimeTearDown]
public void TearDown()
{
_helper?.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Pipelines/02-Parent/GivenDisabledPipelines.cs
================================================
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Threading.Tasks;
namespace FactoryTesting.Pipelines.Parent
{
class GivenDisabledPipelines
{
private ParentHelper _helper;
[OneTimeSetUp]
public async Task WhenPipelineRun()
{
_helper = new ParentHelper()
.WithBasicMetadata()
.WithTenantAndSubscriptionIds()
.WithSPNInDatabase("FrameworkFactory")
.WithEmptyExecutionTables()
.WithPipelinesDisabled();
await _helper.RunPipeline();
}
#region Integration tests
[Test, Order(1)]
public void ThenPipelineOutcomeIsFailed()
{
_helper.RunOutcome.Should().Be("Failed");
}
#endregion
[OneTimeTearDown]
public void TearDown()
{
_helper?.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Pipelines/02-Parent/GivenDisabledStages.cs
================================================
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Threading.Tasks;
namespace FactoryTesting.Pipelines.Parent
{
public class GivenDisabledStages
{
private ParentHelper _helper;
[OneTimeSetUp]
public async Task WhenPipelineRun()
{
_helper = new ParentHelper()
.WithBasicMetadata()
.WithTenantAndSubscriptionIds()
.WithSPNInDatabase("FrameworkFactory")
.WithEmptyExecutionTables()
.WithStagesDisabled();
await _helper.RunPipeline();
}
#region Integration tests
[Test, Order(1)]
public void ThenPipelineOutcomeIsFailed()
{
_helper.RunOutcome.Should().Be("Failed");
}
#endregion
[OneTimeTearDown]
public void TearDown()
{
_helper?.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Pipelines/02-Parent/GivenNoErrorsAndSPNStoredInDatabase.cs
================================================
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Threading.Tasks;
namespace FactoryTesting.Pipelines.Parent
{
public class GivenNoErrorsAndSPNStoredInDatabase
{
private ParentHelper _helper;
[OneTimeSetUp]
public async Task WhenPipelineRun()
{
_helper = new ParentHelper()
.WithBasicMetadata()
.WithTenantAndSubscriptionIds()
.WithSPNInDatabase("FrameworkFactory")
.WithEmptyExecutionTables()
.WithoutSimulatedError()
.WithFailureHandling("Simple");
await _helper.RunPipeline();
}
#region Integration tests
[Test]
public void ThenPipelineOutcomeIsSucceeded()
{
_helper.RunOutcome.Should().Be("Succeeded");
}
#endregion
#region Functional tests
[Test]
public void ThenCurrentExecutionTableIsEmpty()
{
_helper.RowCount("procfwk.CurrentExecution").Should().Be(0);
}
[Test]
public void ThenElevenExecutionLogRecords()
{
_helper.RowCount("procfwk.ExecutionLog").Should().Be(11);
}
#endregion
[OneTimeTearDown]
public void TearDown()
{
_helper?.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Pipelines/02-Parent/GivenNoErrorsAndSPNStoredInKeyVault.cs
================================================
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Threading.Tasks;
namespace FactoryTesting.Pipelines.Parent
{
public class GivenNoErrorsAndSPNStoredInKeyVault
{
private ParentHelper _helper;
[OneTimeSetUp]
public async Task WhenPipelineRun()
{
_helper = new ParentHelper()
.WithBasicMetadata()
.WithTenantAndSubscriptionIds()
.WithSPNInKeyVault("FrameworkFactory")
.WithEmptyExecutionTables()
.WithoutSimulatedError()
.WithFailureHandling("Simple");
await _helper.RunPipeline();
}
#region Integration tests
[Test, Order(1)]
public void ThenPipelineOutcomeIsSucceeded()
{
_helper.RunOutcome.Should().Be("Succeeded");
}
#endregion
#region Functional tests
[Test, Order(2)]
public void ThenCurrentExecutionTableIsEmpty()
{
_helper.RowCount("procfwk.CurrentExecution").Should().Be(0);
}
[Test, Order(3)]
public void ThenElevenExecutionLogRecords()
{
_helper.RowCount("procfwk.ExecutionLog").Should().Be(11);
}
#endregion
[OneTimeTearDown]
public void TearDown()
{
_helper?.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Pipelines/02-Parent/GivenNoFailureHandling.cs
================================================
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Threading.Tasks;
namespace FactoryTesting.Pipelines.Parent
{
public class GivenNoFailureHandling
{
private ParentHelper _helper;
[OneTimeSetUp]
public async Task WhenPipelineRun()
{
_helper = new ParentHelper()
.WithBasicMetadata()
.WithTenantAndSubscriptionIds()
.WithSPNInDatabase("FrameworkFactory")
.WithEmptyExecutionTables()
.WithSimulatedError()
.WithFailureHandling("None");
await _helper.RunPipeline();
}
#region Functional tests
[Test, Order(1)]
public void ThenPipelineOutcomeIsFailed()
{
_helper.RunOutcome.Should().Be("Failed");
}
[Test, Order(2)]
public void ThenTenExecutionsSucceeded()
{
_helper.RowCount("procfwk.CurrentExecution", where: "PipelineStatus", equals: "Success").Should().Be(10);
}
[Test, Order(3)]
public void ThenOneExecutionFailed()
{
_helper.RowCount("procfwk.CurrentExecution", where: "PipelineStatus", equals: "Failed").Should().Be(1);
}
[Test, Order(4)]
public void ThenOneExecutionLogRecord()
{
_helper.RowCount("procfwk.ExecutionLog", where: "PipelineStatus", equals: "Failed").Should().Be(1);
}
[Test, Order(5)]
public void ThenTwoErrorLogRecords()
{
_helper.RowCount("procfwk.ErrorLog").Should().Be(2);
}
#endregion
[OneTimeTearDown]
public void TearDown()
{
_helper?.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Pipelines/02-Parent/GivenNoPipelineParameters.cs
================================================
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Threading.Tasks;
namespace FactoryTesting.Pipelines.Parent
{
class GivenNoPipelineParameters
{
private ParentHelper _helper;
[OneTimeSetUp]
public async Task WhenPipelineRun()
{
_helper = new ParentHelper()
.WithBasicMetadata()
.WithTenantAndSubscriptionIds()
.WithSPNInDatabase("FrameworkFactory")
.WithEmptyExecutionTables()
.WithoutSimulatedError()
.WithFailureHandling("Simple"); ;
await _helper.RunPipeline();
}
#region Integration tests
[Test]
public void ThenPipelineOutcomeIsSucceeded()
{
_helper.RunOutcome.Should().Be("Succeeded");
}
#endregion
#region Functional tests
#endregion
[OneTimeTearDown]
public void TearDown()
{
_helper?.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Pipelines/02-Parent/GivenOneExecutionStage.cs
================================================
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Threading.Tasks;
namespace FactoryTesting.Pipelines.Parent
{
class GivenOneExecutionStage
{
private ParentHelper _helper;
[OneTimeSetUp]
public async Task WhenPipelineRun()
{
_helper = new ParentHelper()
.WithBasicMetadata()
.WithTenantAndSubscriptionIds()
.WithSPNInDatabase("FrameworkFactory")
.WithEmptyExecutionTables()
.WithoutSimulatedError()
.WithFailureHandling("Simple")
.WithSingleExecutionStage();
await _helper.RunPipeline();
}
#region Integration tests
[Test]
public void ThenPipelineOutcomeIsSucceeded()
{
_helper.RunOutcome.Should().Be("Succeeded");
}
#endregion
[OneTimeTearDown]
public void TearDown()
{
_helper?.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Pipelines/02-Parent/GivenSimpleFailureHandling.cs
================================================
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Threading.Tasks;
namespace FactoryTesting.Pipelines.Parent
{
public class GivenSimpleFailureHandling
{
private ParentHelper _helper;
[OneTimeSetUp]
public async Task WhenPipelineRun()
{
_helper = new ParentHelper()
.WithBasicMetadata()
.WithTenantAndSubscriptionIds()
.WithSPNInDatabase("FrameworkFactory")
.WithEmptyExecutionTables()
.WithSimulatedError()
.WithFailureHandling("Simple");
await _helper.RunPipeline();
}
#region Functional tests
[Test, Order(1)]
public void ThenPipelineOutcomeIsFailed()
{
_helper.RunOutcome.Should().Be("Failed");
}
[Test, Order(2)]
public void ThenThreeExecutionsSucceeded()
{
_helper.RowCount("procfwk.CurrentExecution", where: "PipelineStatus", equals: "Success").Should().Be(3);
}
[Test, Order(3)]
public void ThenOneExecutionFailed()
{
_helper.RowCount("procfwk.CurrentExecution", where: "PipelineStatus", equals: "Failed").Should().Be(1);
}
[Test, Order(4)]
public void ThenSevenExecutionsBlocked()
{
_helper.RowCount("procfwk.CurrentExecution", where: "PipelineStatus", equals: "Blocked").Should().Be(7);
}
[Test, Order(5)]
public void ThenOneExecutionLogRecord()
{
_helper.RowCount("procfwk.ExecutionLog", where: "PipelineStatus", equals: "Failed").Should().Be(1);
}
[Test, Order(6)]
public void ThenTwoErrorLogRecords()
{
_helper.RowCount("procfwk.ErrorLog").Should().Be(2);
}
#endregion
[OneTimeTearDown]
public void TearDown()
{
_helper?.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Pipelines/02-Parent/GivenSimpleFailureHandlingAndRestart.cs
================================================
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Threading.Tasks;
namespace FactoryTesting.Pipelines.Parent
{
public class GivenSimpleFailureHandlingAndRestart
{
private ParentHelper _helperFirstRun;
private ParentHelper _helperRestartRun;
[OneTimeSetUp]
public async Task WhenPipelineRun()
{
_helperFirstRun = new ParentHelper()
.WithBasicMetadata()
.WithTenantAndSubscriptionIds()
.WithSPNInDatabase("FrameworkFactory")
.WithEmptyExecutionTables()
.WithSimulatedError()
.WithFailureHandling("Simple");
await _helperFirstRun.RunPipeline();
_helperRestartRun = new ParentHelper()
.WithoutSimulatedError();
await _helperRestartRun.RunPipeline();
}
#region Functional tests
[Test]
public void ThenPipelineOutcomeIsSucceeded()
{
_helperRestartRun.RunOutcome.Should().Be("Succeeded");
}
[Test]
public void ThenOneExecutionLogFailedRecord()
{
_helperRestartRun.RowCount("procfwk.ExecutionLog", where: "PipelineStatus", equals: "Failed").Should().Be(1);
}
[Test]
public void ThenElevenExecutionLogSuccessRecord()
{
_helperRestartRun.RowCount("procfwk.ExecutionLog", where: "PipelineStatus", equals: "Success").Should().Be(11);
}
[Test]
public void ThenTwoErrorLogRecords()
{
_helperRestartRun.RowCount("procfwk.ErrorLog").Should().Be(2);
}
#endregion
[OneTimeTearDown]
public void TearDown()
{
_helperRestartRun?.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Pipelines/02-Parent/GivenSimpleFailureHandlingAndRestartOveride.cs
================================================
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Threading.Tasks;
namespace FactoryTesting.Pipelines.Parent
{
public class GivenSimpleFailureHandlingAndRestartOveride
{
private ParentHelper _helperFirstRun;
private ParentHelper _helperRestartRun;
[OneTimeSetUp]
public async Task WhenPipelineRun()
{
_helperFirstRun = new ParentHelper()
.WithBasicMetadata()
.WithTenantAndSubscriptionIds()
.WithSPNInDatabase("FrameworkFactory")
.WithEmptyExecutionTables()
.WithSimulatedError()
.WithFailureHandling("Simple");
await _helperFirstRun.RunPipeline();
_helperRestartRun = new ParentHelper()
.WithoutSimulatedError()
.WithOverideRestart(true);
await _helperRestartRun.RunPipeline();
}
#region Functional tests
[Test]
public void ThenPipelineOutcomeIsSucceeded()
{
_helperRestartRun.RunOutcome.Should().Be("Succeeded");
}
[Test]
public void ThenOneExecutionLogFailedRecord()
{
_helperRestartRun.RowCount("procfwk.ExecutionLog", where: "PipelineStatus", equals: "Failed").Should().Be(2);
}
[Test]
public void ThenFourthteenExecutionLogSuccessRecord()
{
_helperRestartRun.RowCount("procfwk.ExecutionLog", where: "PipelineStatus", equals: "Success").Should().Be(14);
}
[Test]
public void ThenSevenExecutionsBlocked()
{
_helperRestartRun.RowCount("procfwk.ExecutionLog", where: "PipelineStatus", equals: "Blocked").Should().Be(7);
}
[Test]
public void ThenTwoErrorLogRecords()
{
_helperRestartRun.RowCount("procfwk.ErrorLog").Should().Be(2);
}
#endregion
[OneTimeTearDown]
public void TearDown()
{
_helperRestartRun?.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Pipelines/02-Parent/ParentHelper.cs
================================================
using FactoryTesting.Helpers;
using System;
using System.Data.SqlClient;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
namespace FactoryTesting.Pipelines.Parent
{
class ParentHelper : CoverageHelper
{
public async Task RunPipeline()
{
await RunPipeline("02-Parent");
}
public async Task RunPipeline(int fakeDelayMilliseconds)
{
Thread.Sleep(fakeDelayMilliseconds);
await RunPipeline("02-Parent");
}
public async Task CancelAnyWorkerPipeline()
{
await CancelRunningPipeline(GetWorkerRunId(), GetSetting("WorkersDataFactoryName"));
}
public async Task CancelIntentionalErrorWorkerPipeline()
{
await CancelRunningPipeline(GetWorkerRunId("Intentional Error"), GetSetting("WorkersDataFactoryName"));
}
public virtual Task RunAsync()
{
return Task.CompletedTask;
}
public ParentHelper WithTenantAndSubscriptionIds()
{
AddTenantAndSubscription();
return this;
}
public ParentHelper WithSPNInDatabase(string workerFactoryName)
{
AddWorkerSPNStoredInDatabase(workerFactoryName);
return this;
}
public ParentHelper WithSPNInKeyVault(string workerFactoryName)
{
AddWorkerSPNStoredInKeyVault(workerFactoryName);
return this;
}
public ParentHelper WithBasicMetadata()
{
AddBasicMetadata();
return this;
}
public ParentHelper WithEmptyExecutionTables()
{
WithEmptyTable("procfwk.CurrentExecution");
WithEmptyTable("procfwk.ExecutionLog");
WithEmptyTable("procfwk.ErrorLog");
return this;
}
public ParentHelper WithRunningPipelineStatusInPlaceOf(string statusToOveride)
{
SetFalsePipelineStatus("Running", "PipelineStatus", statusToOveride);
return this;
}
public ParentHelper WithSimulatedError()
{
SimulateError(true);
return this;
}
public ParentHelper WithoutSimulatedError()
{
SimulateError(false);
return this;
}
public ParentHelper WithBatchesDisabled()
{
EnableDisableMetadata("Batches", false);
return this;
}
public ParentHelper WithStagesDisabled()
{
EnableDisableMetadata("Stages", false);
return this;
}
public ParentHelper WithStagesEnabled()
{
EnableDisableMetadata("Stages", true);
return this;
}
public ParentHelper WithOnlyStageOneEnabled()
{
EnableDisableMetadata("Stages", false, "StageId", "2");
EnableDisableMetadata("Stages", false, "StageId", "3");
EnableDisableMetadata("Stages", false, "StageId", "4");
EnableDisableMetadata("Stages", false, "StageId", "5");
return this;
}
public ParentHelper WithPipelinesDisabled()
{
EnableDisableMetadata("Pipelines", false);
return this;
}
public ParentHelper WithPipelinesEnabled()
{
EnableDisableMetadata("Pipelines", true);
return this;
}
public ParentHelper With2MinWaitsOnWorkers()
{
SetParameterValue("120", "ParameterName", "WaitTime");
return this;
}
public ParentHelper WithBatchExecutionHandling()
{
ExecuteNonQuery(@$"UPDATE [procfwk].[Properties]
SET [PropertyValue] = '1'
WHERE [PropertyName] = 'UseExecutionBatches'");
return this;
}
public ParentHelper WithoutBatchExecutionHandling()
{
ExecuteNonQuery(@$"UPDATE [procfwk].[Properties]
SET [PropertyValue] = '0'
WHERE [PropertyName] = 'UseExecutionBatches'");
return this;
}
public ParentHelper WithFailureHandling(string mode)
{
ExecuteNonQuery(@$"UPDATE [procfwk].[Properties]
SET [PropertyValue] = '{mode}'
WHERE [PropertyName] = 'FailureHandling'");
return this;
}
public ParentHelper WithCancelledWorkersBlock(bool mode)
{
string modeString = mode ? "1" : "0";
ExecuteNonQuery(@$"UPDATE [procfwk].[Properties]
SET [PropertyValue] = '{modeString}'
WHERE [PropertyName] = 'CancelledWorkerResultBlocks'");
return this;
}
public ParentHelper WithOverideRestart(bool mode)
{
string modeString = mode ? "1" : "0";
ExecuteNonQuery(@$"UPDATE [procfwk].[Properties]
SET [PropertyValue] = '{modeString}'
WHERE [PropertyName] = 'OverideRestart'");
return this;
}
public ParentHelper WithoutPrecursorObject()
{
ExecuteNonQuery(@$"UPDATE [procfwk].[Properties]
SET [PropertyValue] = '[dbo].[none]'
WHERE [PropertyName] = 'ExecutionPrecursorProc'");
return this;
}
public ParentHelper WithPrecursorObject()
{
ExecuteNonQuery(@$"UPDATE [procfwk].[Properties]
SET [PropertyValue] = '[dbo].[ExampleCustomExecutionPrecursor]'
WHERE [PropertyName] = 'ExecutionPrecursorProc'");
return this;
}
public ParentHelper WithSingleExecutionStage()
{
ExecuteNonQuery("UPDATE [procfwk].[Pipelines] SET [StageId] = 1");
return this;
}
public ParentHelper WithCustom()
{
ExecuteStoredProcedure("[dbo].[PaulTemp]", null);
return this;
}
private ParentHelper SetFalsePipelineStatus(string falseStatus, string where, string equals)
{
ExecuteNonQuery($"UPDATE [procfwk].[CurrentExecution] SET [PipelineStatus] = '{falseStatus}' WHERE {where} = '{equals.Replace("'", "''")}'");
return this;
}
private string GetWorkerRunId(string pipelineName = null)
{
string PipelineRunId;
using (var cmd = new SqlCommand("procfwkTesting.GetRunIdWhenAvailable", _conn))
{
cmd.CommandTimeout = 600;
cmd.CommandType = System.Data.CommandType.StoredProcedure;
if (pipelineName != null) cmd.Parameters.Add(new SqlParameter("@PipelineName", pipelineName));
using var reader = cmd.ExecuteReader();
reader.Read();
PipelineRunId = reader.GetString(0).ToLower();
}
return PipelineRunId;
}
private void EnableDisableMetadata(string table, bool state)
{
string paramValue = state ? "true" : "false";
ExecuteNonQuery(@$"UPDATE [procfwk].[{table}] SET [Enabled] = '{paramValue}'");
}
private void EnableDisableMetadata(string table, bool state, string where, string equals)
{
string paramValue = state ? "true" : "false";
ExecuteNonQuery(@$"UPDATE [procfwk].[{table}] SET [Enabled] = '{paramValue}' WHERE {where} = '{equals.Replace("'", "''")}'");
}
private void SetParameterValue(string value, string where, string equals)
{
string sqlStatement = @$"UPDATE [procfwk].[PipelineParameters] SET [ParameterValue] = '{value.Replace("'", "''")}' WHERE {where} = '{equals.Replace("'", "''")}'";
ExecuteNonQuery(sqlStatement);
}
private void SimulateError(bool simulate)
{
string paramValue = simulate ? "true" : "false";
ExecuteNonQuery(@$"UPDATE pp
SET [ParameterValue] = '{paramValue}'
FROM [procfwk].[PipelineParameters] pp
INNER JOIN [procfwk].[Pipelines] p ON pp.[PipelineId] = p.[PipelineId]
WHERE p.[PipelineName] = 'Intentional Error' AND pp.[ParameterName] = 'RaiseErrors'");
}
public override void TearDown()
{
base.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Pipelines/Utilities/GivenCheckForRunningPipeline.cs
================================================
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Threading.Tasks;
using FactoryTesting.Helpers;
namespace FactoryTesting.Pipelines.Utilities
{
public class GivenCheckForRunningPipeline
{
private UtilitiesHelper _helper;
[OneTimeSetUp]
public async Task WhenPipelineRun()
{
_helper = new UtilitiesHelper()
.WithBasicMetadata()
.WithTenantAndSubscriptionIds()
.WithParameter("PipelineName", "Check For Running Pipeline");
await _helper.RunPipeline("Check For Running Pipeline");
}
[Test]
public void ThenPipelineOutcomeIsFailed()
{
_helper.RunOutcome.Should().Be("Failed");
}
[Test]
public async Task ThenActivityShouldReturnOneFilteredItemCount()
{
var filteredCount = await _helper.GetActivityOutput("Filter Running Pipelines", "$.FilteredItemsCount");
int.Parse(filteredCount).Should().Be(1);
}
[Test]
public async Task ThenActivityShouldReturnMatchingSubscriptionId()
{
string subSetting = _helper.GetSetting("AZURE_SUBSCRIPTION_ID");
var subscriptionId = await _helper.GetActivityOutput("Set Subscription Id", "$.value");
subscriptionId.Should().Equals(subSetting.ToString());
}
[Test]
public async Task ThenActivityShouldReturnMatchingResourceGroup()
{
string rgSsetting = _helper.GetSetting("DataFactoryResourceGroup");
var resourceGroupName = await _helper.GetActivityOutput("Set Resource Group Name", "$.value");
resourceGroupName.Should().Equals(rgSsetting.ToString());
}
[OneTimeTearDown]
public void TearDown()
{
_helper?.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Pipelines/Utilities/GivenEmailSender.cs
================================================
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Threading.Tasks;
namespace FactoryTesting.Pipelines.Utilities
{
public class GivenEmailSender
{
private UtilitiesHelper _helper;
[OneTimeSetUp]
public async Task WhenPipelineRun()
{
_helper = new UtilitiesHelper()
.WithParameter("Recipients", "paul@mrpaulandrew.com")
.WithParameter("Subject", "NUnit Test")
.WithParameter("Body", "NUnit Test"); ;
await _helper.RunPipeline("Email Sender");
}
[Test]
public void ThenPipelineOutcomeIsSucceeded()
{
_helper.RunOutcome.Should().Be("Succeeded");
}
[Test]
public async Task ThenActivityShouldReturnEmailSentTrue()
{
var sentState = await _helper.GetActivityOutput("Send Email", "$.EmailSent");
bool.Parse(sentState).Should().Be(true);
}
[OneTimeTearDown]
public void TearDown()
{
_helper?.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Pipelines/Utilities/GivenThrowException.cs
================================================
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Threading.Tasks;
namespace FactoryTesting.Pipelines.Utilities
{
public class GivenThrowException
{
private UtilitiesHelper _helper;
[OneTimeSetUp]
public async Task WhenPipelineRun()
{
_helper = new UtilitiesHelper()
.WithParameter("Message","NUnit Test");
await _helper.RunPipeline("Throw Exception");
}
[Test]
public void ThenPipelineOutcomeIsFailed()
{
_helper.RunOutcome.Should().Be("Failed");
}
[OneTimeTearDown]
public void TearDown()
{
_helper?.TearDown();
}
}
}
================================================
FILE: FactoryTesting/Pipelines/Utilities/UtilitiesHelper.cs
================================================
using FactoryTesting.Helpers;
using System;
using System.Data.SqlClient;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
namespace FactoryTesting.Pipelines.Utilities
{
class UtilitiesHelper : CoverageHelper
{
public UtilitiesHelper WithBasicMetadata()
{
AddBasicMetadata();
return this;
}
public UtilitiesHelper WithTenantAndSubscriptionIds()
{
AddTenantAndSubscription();
return this;
}
public override void TearDown()
{
base.TearDown();
}
}
}
================================================
FILE: FactoryTesting/dev.runsettings
================================================
================================================
FILE: FactoryTesting/multi.runsettings
================================================
================================================
FILE: FactoryTesting/test.runsettings
================================================
================================================
FILE: Functions/.vscode/extensions.json
================================================
{
"recommendations": [
"ms-azuretools.vscode-azurefunctions",
"ms-dotnettools.csharp"
]
}
================================================
FILE: Functions/.vscode/launch.json
================================================
{
"version": "0.2.0",
"configurations": [
{
"name": "Attach to .NET Functions",
"type": "coreclr",
"request": "attach",
"processId": "${command:azureFunctions.pickProcess}"
}
]
}
================================================
FILE: Functions/.vscode/settings.json
================================================
{
"azureFunctions.deploySubpath": "bin/Release/netcoreapp3.1/publish",
"azureFunctions.projectLanguage": "C#",
"azureFunctions.projectRuntime": "~3",
"debug.internalConsoleOptions": "neverOpen",
"azureFunctions.preDeployTask": "publish"
}
================================================
FILE: Functions/.vscode/tasks.json
================================================
{
"version": "2.0.0",
"tasks": [
{
"label": "clean",
"command": "dotnet",
"args": [
"clean",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"type": "process",
"problemMatcher": "$msCompile"
},
{
"label": "build",
"command": "dotnet",
"args": [
"build",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"type": "process",
"dependsOn": "clean",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": "$msCompile"
},
{
"label": "clean release",
"command": "dotnet",
"args": [
"clean",
"--configuration",
"Release",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"type": "process",
"problemMatcher": "$msCompile"
},
{
"label": "publish",
"command": "dotnet",
"args": [
"publish",
"--configuration",
"Release",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"type": "process",
"dependsOn": "clean release",
"problemMatcher": "$msCompile"
},
{
"type": "func",
"dependsOn": "build",
"options": {
"cwd": "${workspaceFolder}/bin/Debug/netcoreapp3.1"
},
"command": "host start",
"isBackground": true,
"problemMatcher": "$func-watch"
}
]
}
================================================
FILE: Functions/Functions/CancelPipeline.cs
================================================
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using mrpaulandrew.azure.procfwk.Helpers;
using mrpaulandrew.azure.procfwk.Services;
namespace mrpaulandrew.azure.procfwk
{
public static class CancelPipeline
{
[FunctionName("CancelPipeline")]
public static async Task Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest httpRequest,
ILogger logger)
{
logger.LogInformation("CancelPipeline Function triggered by HTTP request.");
logger.LogInformation("Parsing body from request.");
PipelineRunRequest request = await new BodyReader(httpRequest).GetRunRequestBodyAsync();
request.Validate(logger);
using (var service = PipelineService.GetServiceForRequest(request, logger))
{
PipelineRunStatus result = service.CancelPipeline(request);
logger.LogInformation("CancelPipeline Function complete.");
return new OkObjectResult(JsonConvert.SerializeObject(result));
}
}
}
}
================================================
FILE: Functions/Functions/CheckPipelineStatus.cs
================================================
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using mrpaulandrew.azure.procfwk.Helpers;
using mrpaulandrew.azure.procfwk.Services;
namespace mrpaulandrew.azure.procfwk
{
public static class CheckPipelineStatus
{
[FunctionName("CheckPipelineStatus")]
public static async Task Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest httpRequest,
ILogger logger)
{
logger.LogInformation("CheckPipelineStatus Function triggered by HTTP request.");
logger.LogInformation("Parsing body from request.");
PipelineRunRequest request = await new BodyReader(httpRequest).GetRunRequestBodyAsync();
request.Validate(logger);
using (var service = PipelineService.GetServiceForRequest(request, logger))
{
PipelineRunStatus result = service.GetPipelineRunStatus(request);
logger.LogInformation("CheckPipelineStatus Function complete.");
return new OkObjectResult(JsonConvert.SerializeObject(result));
}
}
}
}
================================================
FILE: Functions/Functions/ExecutePipeline.cs
================================================
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using mrpaulandrew.azure.procfwk.Helpers;
using mrpaulandrew.azure.procfwk.Services;
namespace mrpaulandrew.azure.procfwk
{
public static class ExecutePipeline
{
[FunctionName("ExecutePipeline")]
public static async Task Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest httpRequest,
ILogger logger)
{
logger.LogInformation("ExecutePipeline Function triggered by HTTP request.");
logger.LogInformation("Parsing body from request.");
PipelineRequest request = await new BodyReader(httpRequest).GetRequestBodyAsync();
request.Validate(logger);
using (var service = PipelineService.GetServiceForRequest(request, logger))
{
PipelineRunStatus result = service.ExecutePipeline(request);
logger.LogInformation("ExecutePipeline Function complete.");
return new OkObjectResult(JsonConvert.SerializeObject(result));
}
}
}
}
================================================
FILE: Functions/Functions/GetActivityErrors.cs
================================================
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using mrpaulandrew.azure.procfwk.Helpers;
using mrpaulandrew.azure.procfwk.Services;
namespace mrpaulandrew.azure.procfwk
{
public static class GetActivityErrors
{
[FunctionName("GetActivityErrors")]
public static async Task Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest httpRequest,
ILogger logger)
{
logger.LogInformation("GetActivityErrors Function triggered by HTTP request.");
logger.LogInformation("Parsing body from request.");
PipelineRunRequest request = await new BodyReader(httpRequest).GetRunRequestBodyAsync();
request.Validate(logger);
using (var service = PipelineService.GetServiceForRequest(request, logger))
{
PipelineErrorDetail result = service.GetPipelineRunActivityErrors(request);
logger.LogInformation("GetActivityErrors Function complete.");
return new OkObjectResult(JsonConvert.SerializeObject(result));
}
}
}
}
================================================
FILE: Functions/Functions/SendEmail.cs
================================================
using System;
using System.IO;
using System.Threading.Tasks;
using System.Net.Mail;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using mrpaulandrew.azure.procfwk.Helpers;
using System.Linq;
namespace mrpaulandrew.azure.procfwk
{
public static class SendEmail
{
[FunctionName("SendEmail")]
public static async Task Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("SendEmail Function triggered by HTTP request.");
#region ParseRequestBody
log.LogInformation("Parsing body from request.");
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
string outputString = string.Empty;
JObject outputJson;
string toRecipients = data?.emailRecipients;
string ccRecipients = data?.emailCcRecipients;
string bccRecipients = data?.emailBccRecipients;
string subject = data?.emailSubject;
string message = data?.emailBody;
string passedImportance = data?.emailImportance ?? ""; //Set normal importance if not provided.
#endregion
#region ValidateRequestBody
//Check for minimum mailing values in request body
if (subject == null || message == null)
{
log.LogInformation("Invalid body - Subject/Body.");
outputString = "{ \"EmailSent\": false, \"Details\": \"Email subject or body values missing.\"}";
outputJson = JObject.Parse(outputString);
return new BadRequestObjectResult(outputJson);
}
if (
(toRecipients == null && ccRecipients == null && bccRecipients == null) ||
(string.IsNullOrEmpty(toRecipients) && string.IsNullOrEmpty(ccRecipients) && string.IsNullOrEmpty(bccRecipients))
)
{
log.LogInformation("Invalid body - To/CC/BCC.");
outputString = "{ \"EmailSent\": false, \"Details\": \"No email recipients provided as To/CC/BCC.\"}";
outputJson = JObject.Parse(outputString);
return new BadRequestObjectResult(outputJson);
}
#endregion
//Create email client
log.LogInformation("Creating smtp client.");
using (var client = SMTPClient.CreateSMTPClient())
{
#region CreateMail
MailAddress from = new MailAddress(SMTPClient.FromEmail);
MailMessage mail = new MailMessage
{
From = from,
IsBodyHtml = true,
Subject = subject,
Body = message
};
//Set mail importance
if (passedImportance.ToUpper() == "HIGH")
{
mail.Priority = MailPriority.High;
}
else if (passedImportance.ToUpper() == "LOW")
{
mail.Priority = MailPriority.Low;
}
else
{
mail.Priority = MailPriority.Normal;
}
#endregion
#region SetRecipients
//to recipients
if (!string.IsNullOrEmpty(toRecipients))
{
var allRecipients = toRecipients.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries);
foreach (var toAddress in allRecipients)
{
mail.To.Add(toAddress);
}
log.LogInformation("To Recipients Added: " + allRecipients.Count().ToString());
}
else
{
log.LogInformation("To Recipients Added: 0");
}
//cc recipients
if (!string.IsNullOrEmpty(ccRecipients))
{
var allCcRecipients = ccRecipients.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries);
foreach (var ccAddress in allCcRecipients)
{
mail.CC.Add(ccAddress);
}
log.LogInformation("CC Recipients Added: " + allCcRecipients.Count().ToString());
}
else
{
log.LogInformation("CC Recipients Added: 0");
}
//bcc recipients
if (!string.IsNullOrEmpty(bccRecipients))
{
var allBccRecipients = bccRecipients.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries);
foreach (var bccAddress in allBccRecipients)
{
mail.Bcc.Add(bccAddress);
}
log.LogInformation("BCC Recipients Added: " + allBccRecipients.Count().ToString());
}
else
{
log.LogInformation("BCC Recipients Added: 0");
}
#endregion
#region SendEmail
try
{
log.LogInformation("Sending email.");
client.Send(mail);
outputString = "{ \"EmailSent\": true }";
log.LogInformation("Sent email.");
}
catch (SmtpException smtpEx)
{
outputString = "{ \"EmailSent\": false, \"Details\": \"SMTP exception caught and logged to error output.\"}";
log.LogError(smtpEx.Message);
log.LogInformation("Message has not been sent. Check Azure Function Logs for more information.");
}
catch (Exception ex)
{
outputString = "{ \"EmailSent\": false, \"Details\": \"Other exception caught and logged to error output.\"}";
log.LogError(ex.Message);
log.LogInformation("Message has not been sent. Check Azure Function Logs for more information.");
}
#endregion
}
outputJson = JObject.Parse(outputString);
log.LogInformation("SendEmail Function complete.");
return new OkObjectResult(outputJson);
}
}
}
================================================
FILE: Functions/Functions/ValidatePipeline.cs
================================================
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using mrpaulandrew.azure.procfwk.Helpers;
using mrpaulandrew.azure.procfwk.Services;
namespace mrpaulandrew.azure.procfwk
{
public static class ValidatePipeline
{
[FunctionName("ValidatePipeline")]
public static async Task Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest httpRequest,
ILogger logger)
{
logger.LogInformation("ValidatePipeline Function triggered by HTTP request.");
logger.LogInformation("Parsing body from request.");
PipelineRequest request = await new BodyReader(httpRequest).GetRequestBodyAsync();
request.Validate(logger);
using (var service = PipelineService.GetServiceForRequest(request, logger))
{
PipelineDescription result = service.ValidatePipeline(request);
logger.LogInformation("ValidatePipeline Function complete.");
return new OkObjectResult(JsonConvert.SerializeObject(result));
}
}
}
}
================================================
FILE: Functions/Functions.csproj
================================================
netcoreapp3.1
v3
mrpaulandrew.azure.procfwk
mrpaulandrew.azure.procfwk
PreserveNewest
Always
================================================
FILE: Functions/Helpers/BodyReader.cs
================================================
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace mrpaulandrew.azure.procfwk.Helpers
{
public class BodyReader
{
public string Body;
public BodyReader(HttpRequest httpRequest)
{
Body = new StreamReader(httpRequest.Body).ReadToEnd();
}
public Task GetRequestBody()
{
PipelineRequest request = JsonConvert.DeserializeObject(Body);
return Task.FromResult(request);
}
public async Task GetRequestBodyAsync()
{
PipelineRequest request = await GetRequestBody();
return request;
}
public Task GetRunRequestBody()
{
PipelineRunRequest request = JsonConvert.DeserializeObject(Body);
return Task.FromResult(request);
}
public async Task GetRunRequestBodyAsync()
{
PipelineRunRequest request = await GetRunRequestBody();
return request;
}
}
}
================================================
FILE: Functions/Helpers/InvalidRequestException.cs
================================================
using System;
using System.Runtime.Serialization;
namespace mrpaulandrew.azure.procfwk.Helpers
{
[Serializable]
internal class InvalidRequestException : Exception
{
public InvalidRequestException()
{
}
public InvalidRequestException(string message) : base(message)
{
}
public InvalidRequestException(string message, Exception innerException) : base(message, innerException)
{
}
protected InvalidRequestException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
}
}
================================================
FILE: Functions/Helpers/KeyVaultClient.cs
================================================
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
using System;
namespace mrpaulandrew.azure.procfwk.Helpers
{
internal class KeyVaultClient
{
private static readonly DefaultAzureCredential defaultCred = new DefaultAzureCredential();
public static string GetSecretFromUri(string secretString)
{
return GetSecretFromUri(new Uri(secretString));
}
public static string GetSecretFromUri(Uri secretUri)
{
string keyVaultURL = "https://" + secretUri.Host.ToString();
string secretName = secretUri.LocalPath.ToString().Replace("secrets/", "").Replace("/", "");
return CreateKeyVaultClient(keyVaultURL).GetSecret(secretName).Value.Value;
}
public static string GetSecretFromName(string keyVaultURL, string secretName)
{
return CreateKeyVaultClient(keyVaultURL).GetSecret(secretName).Value.Value;
}
private static SecretClient CreateKeyVaultClient(string keyVaultURL)
{
return new SecretClient(new Uri(keyVaultURL), defaultCred);
}
}
}
================================================
FILE: Functions/Helpers/PipelineRequest.cs
================================================
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
namespace mrpaulandrew.azure.procfwk.Helpers
{
public class PipelineRequest
{
public string TenantId { get; set; }
public string ApplicationId { get; set; }
public string AuthenticationKey { get; set; }
public string SubscriptionId { get; set; }
public string ResourceGroupName { get; set; }
public string OrchestratorName { get; set; }
public string PipelineName { get; set; }
public PipelineServiceType? OrchestratorType { get; set; }
public Dictionary PipelineParameters;
public virtual void Validate(ILogger logger)
{
// ensure properties not null
if (
TenantId == null ||
ApplicationId == null ||
AuthenticationKey == null ||
SubscriptionId == null ||
ResourceGroupName == null ||
OrchestratorType == null ||
OrchestratorName == null ||
PipelineName == null
)
ReportInvalidBody(logger);
//other validation
if (!CheckGuid(TenantId)) ReportInvalidBody(logger, "Expected Tenant Id to be a GUID.");
if (!CheckGuid(SubscriptionId)) ReportInvalidBody(logger, "Expected Subscription Id to be a GUID.");
// resolve key vault values
if (!CheckGuid(ApplicationId) && CheckUri(ApplicationId))
{
logger.LogInformation("Getting applicationId from Key Vault");
ApplicationId = KeyVaultClient.GetSecretFromUri(ApplicationId);
}
if (CheckUri(AuthenticationKey))
{
logger.LogInformation("Getting authenticationKey from Key Vault");
AuthenticationKey = KeyVaultClient.GetSecretFromUri(AuthenticationKey);
}
}
private bool CheckUri(string uriValue)
{
bool result = Uri.TryCreate(uriValue, UriKind.Absolute, out Uri uriResult)
&& (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps);
return result;
}
public bool CheckGuid(string idValue)
{
bool result = Guid.TryParse(idValue, out _);
return result;
}
protected void ReportInvalidBody(ILogger logger)
{
var msg = "Invalid body.";
logger.LogError(msg);
throw new InvalidRequestException(msg);
}
protected void ReportInvalidBody(ILogger logger, string additions)
{
var msg = "Invalid body. " + additions;
logger.LogError(msg);
throw new InvalidRequestException(msg);
}
public Dictionary ParametersAsObjects
{
get
{
if (PipelineParameters == null)
return null;
var dictionary = new Dictionary();
foreach (var key in PipelineParameters.Keys)
dictionary.Add(key, PipelineParameters[key]);
return dictionary;
}
}
}
}
================================================
FILE: Functions/Helpers/PipelineRunRequest.cs
================================================
using System;
using Microsoft.Extensions.Logging;
namespace mrpaulandrew.azure.procfwk.Helpers
{
public class PipelineRunRequest : PipelineRequest
{
public string RunId { get; set; }
public bool RecursivePipelineCancel = true; //might provide this as part of the request later
public DateTime ActivityQueryStart = DateTime.Now.AddDays(-7); //max duration for eventual RunFilterParameters
public DateTime ActivityQueryEnd = DateTime.Now;
public override void Validate(ILogger logger)
{
base.Validate(logger);
// ensure properties not null
if (RunId == null)
ReportInvalidBody(logger);
//other validation
if (!CheckGuid(RunId)) ReportInvalidBody(logger, "Expected Run Id to be a GUID.");
}
}
}
================================================
FILE: Functions/Helpers/SMTPClient.cs
================================================
using System;
using System.Net.Mail;
namespace mrpaulandrew.azure.procfwk.Helpers
{
internal class SMTPClient
{
public static string FromEmail { get; set; }
public static SmtpClient CreateSMTPClient()
{
string smtpHost = Environment.GetEnvironmentVariable("AppSettingSmtpHost");
int smtpPort = int.Parse(Environment.GetEnvironmentVariable("AppSettingSmtpPort"));
string smtpUser = Environment.GetEnvironmentVariable("AppSettingSmtpUser");
string smtpPass = Environment.GetEnvironmentVariable("AppSettingSmtpPass");
FromEmail = Environment.GetEnvironmentVariable("AppSettingFromEmail");
SmtpClient emailClient = new SmtpClient
{
EnableSsl = true,
UseDefaultCredentials = false, //order properties are set is important
Credentials = new System.Net.NetworkCredential(smtpUser, smtpPass),
DeliveryMethod = SmtpDeliveryMethod.Network,
Host = smtpHost,
Port = smtpPort
};
return emailClient;
}
}
}
================================================
FILE: Functions/Properties/ServiceDependencies/FrameworkSupportFunctions - Zip Deploy/profile.arm.json
================================================
{
"$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"metadata": {
"_dependencyType": "function.windows.consumption"
},
"parameters": {
"resourceGroupName": {
"type": "string",
"defaultValue": "ADF.procfwk",
"metadata": {
"description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking."
}
},
"resourceGroupLocation": {
"type": "string",
"defaultValue": "uksouth",
"metadata": {
"description": "Location of the resource group. Resource groups could have different location than resources, however by default we use API versions from latest hybrid profile which support all locations for resource types we support."
}
},
"resourceName": {
"type": "string",
"defaultValue": "FrameworkSupportFunctions",
"metadata": {
"description": "Name of the main resource to be created by this template."
}
},
"resourceLocation": {
"type": "string",
"defaultValue": "[parameters('resourceGroupLocation')]",
"metadata": {
"description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there."
}
}
},
"resources": [
{
"type": "Microsoft.Resources/resourceGroups",
"name": "[parameters('resourceGroupName')]",
"location": "[parameters('resourceGroupLocation')]",
"apiVersion": "2019-10-01"
},
{
"type": "Microsoft.Resources/deployments",
"name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]",
"resourceGroup": "[parameters('resourceGroupName')]",
"apiVersion": "2019-10-01",
"dependsOn": [
"[parameters('resourceGroupName')]"
],
"properties": {
"mode": "Incremental",
"expressionEvaluationOptions": {
"scope": "inner"
},
"parameters": {
"resourceGroupName": {
"value": "[parameters('resourceGroupName')]"
},
"resourceGroupLocation": {
"value": "[parameters('resourceGroupLocation')]"
},
"resourceName": {
"value": "[parameters('resourceName')]"
},
"resourceLocation": {
"value": "[parameters('resourceLocation')]"
}
},
"template": {
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"resourceGroupName": {
"type": "string"
},
"resourceGroupLocation": {
"type": "string"
},
"resourceName": {
"type": "string"
},
"resourceLocation": {
"type": "string"
}
},
"variables": {
"storage_name": "[toLower(concat('storage', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId))))]",
"storage_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Storage/storageAccounts/', variables('storage_name'))]",
"function_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Web/sites/', parameters('resourceName'))]"
},
"resources": [
{
"location": "[parameters('resourceGroupLocation')]",
"name": "[variables('storage_name')]",
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2017-10-01",
"tags": {
"[concat('hidden-related:', concat('/providers/Microsoft.Web/sites/', parameters('resourceName')))]": "empty"
},
"properties": {
"supportsHttpsTrafficOnly": true
},
"sku": {
"name": "Standard_LRS"
},
"kind": "Storage"
},
{
"location": "[parameters('resourceLocation')]",
"name": "[parameters('resourceName')]",
"type": "Microsoft.Web/sites",
"apiVersion": "2015-08-01",
"dependsOn": [
"[variables('storage_ResourceId')]"
],
"kind": "functionapp",
"properties": {
"name": "[parameters('resourceName')]",
"kind": "functionapp",
"httpsOnly": true,
"reserved": false
},
"identity": {
"type": "SystemAssigned"
},
"resources": [
{
"name": "appsettings",
"type": "config",
"apiVersion": "2015-08-01",
"dependsOn": [
"[variables('function_ResourceId')]"
],
"properties": {
"WEBSITE_CONTENTAZUREFILECONNECTIONSTRING": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storage_name'), ';AccountKey=', listKeys(variables('storage_ResourceId'), '2017-10-01').keys[0].value, ';EndpointSuffix=', 'core.windows.net')]",
"WEBSITE_CONTENTSHARE": "[toLower(parameters('resourceName'))]",
"AzureWebJobsDashboard": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storage_name'), ';AccountKey=', listKeys(variables('storage_ResourceId'), '2017-10-01').keys[0].value, ';EndpointSuffix=', 'core.windows.net')]",
"AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storage_name'), ';AccountKey=', listKeys(variables('storage_ResourceId'), '2017-10-01').keys[0].value, ';EndpointSuffix=', 'core.windows.net')]",
"FUNCTIONS_EXTENSION_VERSION": "~3",
"FUNCTIONS_WORKER_RUNTIME": "dotnet"
}
}
]
}
]
}
}
}
]
}
================================================
FILE: Functions/Properties/ServiceDependencies/FrameworkSupportFunctionsBig - Web Deploy/profile.arm.json
================================================
{
"$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"metadata": {
"_dependencyType": "appService.windows"
},
"parameters": {
"resourceGroupName": {
"type": "string",
"defaultValue": "ADF.procfwkStressTest",
"metadata": {
"description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking."
}
},
"resourceGroupLocation": {
"type": "string",
"defaultValue": "uksouth",
"metadata": {
"description": "Location of the resource group. Resource groups could have different location than resources, however by default we use API versions from latest hybrid profile which support all locations for resource types we support."
}
},
"resourceName": {
"type": "string",
"defaultValue": "FrameworkSupportFunctionsBig",
"metadata": {
"description": "Name of the main resource to be created by this template."
}
},
"resourceLocation": {
"type": "string",
"defaultValue": "[parameters('resourceGroupLocation')]",
"metadata": {
"description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there."
}
}
},
"variables": {
"appServicePlan_name": "[concat('Plan', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]",
"appServicePlan_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Web/serverFarms/', variables('appServicePlan_name'))]"
},
"resources": [
{
"type": "Microsoft.Resources/resourceGroups",
"name": "[parameters('resourceGroupName')]",
"location": "[parameters('resourceGroupLocation')]",
"apiVersion": "2019-10-01"
},
{
"type": "Microsoft.Resources/deployments",
"name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]",
"resourceGroup": "[parameters('resourceGroupName')]",
"apiVersion": "2019-10-01",
"dependsOn": [
"[parameters('resourceGroupName')]"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"location": "[parameters('resourceLocation')]",
"name": "[parameters('resourceName')]",
"type": "Microsoft.Web/sites",
"apiVersion": "2015-08-01",
"tags": {
"[concat('hidden-related:', variables('appServicePlan_ResourceId'))]": "empty"
},
"dependsOn": [
"[variables('appServicePlan_ResourceId')]"
],
"kind": "app",
"properties": {
"name": "[parameters('resourceName')]",
"kind": "app",
"httpsOnly": true,
"reserved": false,
"serverFarmId": "[variables('appServicePlan_ResourceId')]",
"siteConfig": {
"metadata": [
{
"name": "CURRENT_STACK",
"value": "dotnetcore"
}
]
}
},
"identity": {
"type": "SystemAssigned"
}
},
{
"location": "[parameters('resourceLocation')]",
"name": "[variables('appServicePlan_name')]",
"type": "Microsoft.Web/serverFarms",
"apiVersion": "2015-08-01",
"sku": {
"name": "S1",
"tier": "Standard",
"family": "S",
"size": "S1"
},
"properties": {
"name": "[variables('appServicePlan_name')]"
}
}
]
}
}
}
]
}
================================================
FILE: Functions/Services/AzureDataFactoryService.cs
================================================
using System;
using System.Threading;
using Newtonsoft.Json;
using Microsoft.Rest;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using Microsoft.Azure.Management.DataFactory;
using Microsoft.Azure.Management.DataFactory.Models;
using mrpaulandrew.azure.procfwk.Helpers;
namespace mrpaulandrew.azure.procfwk.Services
{
public class AzureDataFactoryService : PipelineService
{
private readonly DataFactoryManagementClient _adfManagementClient;
private readonly ILogger _logger;
public AzureDataFactoryService(PipelineRequest request, ILogger logger)
{
_logger = logger;
_logger.LogInformation("Creating ADF connectivity clients.");
//Auth details
var context = new AuthenticationContext("https://login.windows.net/" + request.TenantId);
var cc = new ClientCredential(request.ApplicationId, request.AuthenticationKey);
var result = context.AcquireTokenAsync("https://management.azure.com/", cc).Result;
var cred = new TokenCredentials(result.AccessToken);
//Management Client
_adfManagementClient = new DataFactoryManagementClient(cred)
{
SubscriptionId = request.SubscriptionId
};
}
public override PipelineDescription ValidatePipeline(PipelineRequest request)
{
_logger.LogInformation("Validating ADF pipeline.");
try
{
var pipelineResource = _adfManagementClient.Pipelines.Get
(
request.ResourceGroupName,
request.OrchestratorName,
request.PipelineName
);
_logger.LogInformation(pipelineResource.Id.ToString());
return new PipelineDescription()
{
PipelineExists = "True",
PipelineName = pipelineResource.Name,
PipelineId = pipelineResource.Id,
PipelineType = pipelineResource.Type,
ActivityCount = pipelineResource.Activities.Count
};
}
catch (Microsoft.Rest.Azure.CloudException) //expected exception when pipeline doesnt exist
{
return new PipelineDescription()
{
PipelineExists = "False",
PipelineName = request.PipelineName,
PipelineId = "Unknown",
PipelineType = "Unknown",
ActivityCount = 0
};
}
catch (Exception ex) //other unknown issue
{
_logger.LogInformation(ex.Message);
_logger.LogInformation(ex.GetType().ToString());
throw new InvalidRequestException("Failed to validate pipeline. ", ex);
}
}
public override PipelineRunStatus ExecutePipeline(PipelineRequest request)
{
if (request.PipelineParameters == null)
_logger.LogInformation("Calling pipeline without parameters.");
else
_logger.LogInformation("Calling pipeline with parameters.");
var runResponse = _adfManagementClient.Pipelines.CreateRunWithHttpMessagesAsync
(
request.ResourceGroupName,
request.OrchestratorName,
request.PipelineName,
parameters: request.ParametersAsObjects
).Result.Body;
_logger.LogInformation("Pipeline run ID: " + runResponse.RunId);
//Wait and check for pipeline to start...
PipelineRun pipelineRun;
_logger.LogInformation("Checking ADF pipeline status.");
while (true)
{
pipelineRun = _adfManagementClient.PipelineRuns.Get
(
request.ResourceGroupName,
request.OrchestratorName,
runResponse.RunId
);
_logger.LogInformation("Waiting for pipeline to start, current status: " + pipelineRun.Status);
if (pipelineRun.Status != "Queued")
break;
Thread.Sleep(internalWaitDuration);
}
return new PipelineRunStatus()
{
PipelineName = request.PipelineName,
RunId = runResponse.RunId,
ActualStatus = pipelineRun.Status
};
}
public override PipelineRunStatus CancelPipeline(PipelineRunRequest request)
{
_logger.LogInformation("Getting ADF pipeline current status.");
PipelineRun pipelineRun;
pipelineRun = _adfManagementClient.PipelineRuns.Get
(
request.ResourceGroupName,
request.OrchestratorName,
request.RunId
);
//Defensive check
PipelineNameCheck(request.PipelineName, pipelineRun.PipelineName);
if (pipelineRun.Status == "InProgress" || pipelineRun.Status == "Queued")
{
_logger.LogInformation("Attempting to cancel ADF pipeline.");
_adfManagementClient.PipelineRuns.Cancel
(
request.ResourceGroupName,
request.OrchestratorName,
request.RunId,
isRecursive : request.RecursivePipelineCancel
);
}
else
{
_logger.LogInformation("ADF pipeline status: " + pipelineRun.Status);
throw new InvalidRequestException("Target pipeline is not in a state that can be cancelled.");
}
//wait for cancelled state
_logger.LogInformation("Checking ADF pipeline status after cancel request.");
while (true)
{
pipelineRun = _adfManagementClient.PipelineRuns.Get
(
request.ResourceGroupName,
request.OrchestratorName,
request.RunId
);
_logger.LogInformation("Waiting for pipeline to cancel, current status: " + pipelineRun.Status);
if (pipelineRun.Status == "Cancelled")
break;
Thread.Sleep(internalWaitDuration);
}
//Final return detail
return new PipelineRunStatus()
{
PipelineName = request.PipelineName,
RunId = request.RunId,
ActualStatus = pipelineRun.Status.Replace("Canceling", "Cancelling") //microsoft typo
};
}
public override PipelineRunStatus GetPipelineRunStatus(PipelineRunRequest request)
{
_logger.LogInformation("Checking ADF pipeline status.");
//Get pipeline status with provided run id
PipelineRun pipelineRun;
pipelineRun = _adfManagementClient.PipelineRuns.Get
(
request.ResourceGroupName,
request.OrchestratorName,
request.RunId
);
//Defensive check
PipelineNameCheck(request.PipelineName, pipelineRun.PipelineName);
_logger.LogInformation("ADF pipeline status: " + pipelineRun.Status);
//Defensive check
PipelineNameCheck(request.PipelineName, pipelineRun.PipelineName);
//Final return detail
return new PipelineRunStatus()
{
PipelineName = request.PipelineName,
RunId = pipelineRun.RunId,
ActualStatus = pipelineRun.Status.Replace("Canceling", "Cancelling") //microsoft typo
};
}
public override PipelineErrorDetail GetPipelineRunActivityErrors(PipelineRunRequest request)
{
PipelineRun pipelineRun = _adfManagementClient.PipelineRuns.Get
(
request.ResourceGroupName,
request.OrchestratorName,
request.RunId
);
//Defensive check
PipelineNameCheck(request.PipelineName, pipelineRun.PipelineName);
_logger.LogInformation("Create pipeline Activity Runs query filters.");
RunFilterParameters filterParams = new RunFilterParameters
(
request.ActivityQueryStart,
request.ActivityQueryEnd
);
_logger.LogInformation("Querying ADF pipeline for Activity Runs.");
ActivityRunsQueryResponse queryResponse = _adfManagementClient.ActivityRuns.QueryByPipelineRun
(
request.ResourceGroupName,
request.OrchestratorName,
request.RunId,
filterParams
);
//Create initial output content
PipelineErrorDetail output = new PipelineErrorDetail()
{
PipelineName = request.PipelineName,
ActualStatus = pipelineRun.Status,
RunId = request.RunId,
ResponseCount = queryResponse.Value.Count
};
_logger.LogInformation("Pipeline status: " + pipelineRun.Status);
_logger.LogInformation("Activities found in pipeline response: " + queryResponse.Value.Count.ToString());
//Loop over activities in pipeline run
foreach (ActivityRun activity in queryResponse.Value)
{
if (activity.Error == null)
{
continue; //only want errors
}
//Parse error output to customise output
dynamic outputBlockInner = JsonConvert.DeserializeObject(activity.Error.ToString());
string errorCode = outputBlockInner?.errorCode;
string errorType = outputBlockInner?.failureType;
string errorMessage = outputBlockInner?.message;
_logger.LogInformation("Activity run id: " + activity.ActivityRunId);
_logger.LogInformation("Activity name: " + activity.ActivityName);
_logger.LogInformation("Activity type: " + activity.ActivityType);
_logger.LogInformation("Error message: " + errorMessage);
output.Errors.Add(new FailedActivity()
{
ActivityRunId = activity.ActivityRunId,
ActivityName = activity.ActivityName,
ActivityType = activity.ActivityType,
ErrorCode = errorCode,
ErrorType = errorType,
ErrorMessage = errorMessage
});
}
return output;
}
public override void Dispose()
{
_adfManagementClient?.Dispose();
}
}
}
================================================
FILE: Functions/Services/AzureSynapseService.cs
================================================
using System;
using System.Threading;
using System.Collections.Generic;
using Newtonsoft.Json;
using Microsoft.Rest;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using Microsoft.Azure.Management.Synapse;
using Azure.Core;
using Azure.Identity;
using Azure.Analytics.Synapse.Artifacts;
using Azure.Analytics.Synapse.Artifacts.Models;
using mrpaulandrew.azure.procfwk.Helpers;
namespace mrpaulandrew.azure.procfwk.Services
{
public class AzureSynapseService : PipelineService
{
private readonly SynapseManagementClient _synManagementClient;
private readonly PipelineClient _pipelineClient;
private readonly PipelineRunClient _pipelineRunClient;
private readonly ILogger _logger;
public AzureSynapseService(PipelineRequest request, ILogger logger)
{
_logger = logger;
_logger.LogInformation("Creating SYN connectivity clients.");
//Auth details
var context = new AuthenticationContext("https://login.windows.net/" + request.TenantId);
var cc = new ClientCredential(request.ApplicationId, request.AuthenticationKey);
var result = context.AcquireTokenAsync("https://management.azure.com/", cc).Result;
var cred = new TokenCredentials(result.AccessToken);
//Management Client
_synManagementClient = new SynapseManagementClient(cred)
{
SubscriptionId = request.SubscriptionId
};
//Pipeline Clients
Uri synapseDevEndpoint = new Uri("https://" + request.OrchestratorName.ToLower() + ".dev.azuresynapse.net");
TokenCredential token = new ClientSecretCredential
(
request.TenantId,
request.ApplicationId,
request.AuthenticationKey
);
_pipelineClient = new PipelineClient(synapseDevEndpoint, token);
_pipelineRunClient = new PipelineRunClient(synapseDevEndpoint, token);
}
public override PipelineDescription ValidatePipeline(PipelineRequest request)
{
_logger.LogInformation("Validating SYN pipeline.");
PipelineResource pipelineResource;
try
{
pipelineResource = _pipelineClient.GetPipeline
(
request.PipelineName
);
_logger.LogInformation(pipelineResource.Id.ToString());
return new PipelineDescription()
{
PipelineExists = "True",
PipelineName = pipelineResource.Name,
PipelineId = pipelineResource.Id,
PipelineType = pipelineResource.Type,
ActivityCount = pipelineResource.Activities.Count
};
}
catch (System.InvalidOperationException) //for bug in underlying activity classes, pipeline does exist
{
return new PipelineDescription()
{
PipelineExists = "True",
PipelineName = request.PipelineName,
PipelineId = "Unknown",
PipelineType = "Unknown",
ActivityCount = 0
};
}
catch (Azure.RequestFailedException) //expected exception when pipeline doesnt exist
{
return new PipelineDescription()
{
PipelineExists = "False",
PipelineName = request.PipelineName,
PipelineId = "Unknown",
PipelineType = "Unknown",
ActivityCount = 0
};
}
catch (Exception ex) //other unknown issue
{
_logger.LogInformation(ex.Message);
_logger.LogInformation(ex.GetType().ToString());
throw new InvalidRequestException("Failed to validate pipeline. ", ex);
}
}
public override PipelineRunStatus ExecutePipeline(PipelineRequest request)
{
if (request.PipelineParameters == null)
_logger.LogInformation("Calling pipeline without parameters.");
else
_logger.LogInformation("Calling pipeline with parameters.");
CreateRunResponse runResponse;
runResponse = _pipelineClient.CreatePipelineRun
(
request.PipelineName,
parameters: request.ParametersAsObjects
);
_logger.LogInformation("Pipeline run ID: " + runResponse.RunId);
//Wait and check for pipeline to start...
PipelineRun pipelineRun;
_logger.LogInformation("Checking ADF pipeline status.");
while (true)
{
pipelineRun = _pipelineRunClient.GetPipelineRun
(
runResponse.RunId
);
_logger.LogInformation("Waiting for pipeline to start, current status: " + pipelineRun.Status);
if (pipelineRun.Status != "Queued")
break;
Thread.Sleep(internalWaitDuration);
}
return new PipelineRunStatus()
{
PipelineName = request.PipelineName,
RunId = runResponse.RunId,
ActualStatus = pipelineRun.Status
};
}
public override PipelineRunStatus CancelPipeline(PipelineRunRequest request)
{
_logger.LogInformation("Getting SYN pipeline current status.");
PipelineRun pipelineRun;
pipelineRun = _pipelineRunClient.GetPipelineRun
(
request.RunId
);
//Defensive check
PipelineNameCheck(request.PipelineName, pipelineRun.PipelineName);
if (pipelineRun.Status == "InProgress" || pipelineRun.Status == "Queued")
{
_logger.LogInformation("Attempting to cancel SYN pipeline.");
_pipelineRunClient.CancelPipelineRun
(
request.RunId,
isRecursive: request.RecursivePipelineCancel
);
}
else
{
_logger.LogInformation("ADF pipeline status: " + pipelineRun.Status);
throw new InvalidRequestException("Target pipeline is not in a state that can be cancelled.");
}
//wait for cancelled state
_logger.LogInformation("Checking ADF pipeline status after cancel request.");
while (true)
{
pipelineRun = _pipelineRunClient.GetPipelineRun
(
request.RunId
);
_logger.LogInformation("Waiting for pipeline to cancel, current status: " + pipelineRun.Status);
if (pipelineRun.Status == "Cancelled")
break;
Thread.Sleep(internalWaitDuration);
}
//Final return detail
return new PipelineRunStatus()
{
PipelineName = request.PipelineName,
RunId = request.RunId,
ActualStatus = pipelineRun.Status
};
}
public override PipelineRunStatus GetPipelineRunStatus(PipelineRunRequest request)
{
_logger.LogInformation("Getting SYN pipeline status.");
//Get pipeline status with provided run id
PipelineRun pipelineRun;
pipelineRun = _pipelineRunClient.GetPipelineRun
(
request.RunId
);
//Defensive check
PipelineNameCheck(request.PipelineName, pipelineRun.PipelineName);
_logger.LogInformation("SYN pipeline status: " + pipelineRun.Status);
//Final return detail
return new PipelineRunStatus()
{
PipelineName = request.PipelineName,
RunId = pipelineRun.RunId,
ActualStatus = pipelineRun.Status.Replace("Canceling", "Cancelling") //microsoft typo
};
}
public override PipelineErrorDetail GetPipelineRunActivityErrors(PipelineRunRequest request)
{
PipelineRun pipelineRun = _pipelineRunClient.GetPipelineRun
(
request.RunId
);
//Defensive check
PipelineNameCheck(request.PipelineName, pipelineRun.PipelineName);
_logger.LogInformation("Create pipeline Activity Runs query filters.");
RunFilterParameters filterParams = new RunFilterParameters
(
request.ActivityQueryStart,
request.ActivityQueryEnd
);
_logger.LogInformation("Querying SYN pipeline for Activity Runs.");
ActivityRunsQueryResponse queryResponse = _pipelineRunClient.QueryActivityRuns
(
request.PipelineName,
request.RunId,
filterParams
);
//Create initial output content
PipelineErrorDetail output = new PipelineErrorDetail()
{
PipelineName = request.PipelineName,
ActualStatus = pipelineRun.Status,
RunId = request.RunId,
ResponseCount = queryResponse.Value.Count
};
_logger.LogInformation("Pipeline status: " + pipelineRun.Status);
_logger.LogInformation("Activities found in pipeline response: " + queryResponse.Value.Count.ToString());
//Loop over activities in pipeline run
foreach (ActivityRun activity in queryResponse.Value)
{
if (activity.Error == null)
{
continue; //only want errors
}
//Parse error output to customise output
var json = JsonConvert.SerializeObject(activity.Error);
Dictionary errorContent = JsonConvert.DeserializeObject>(json);
_logger.LogInformation("Activity run id: " + activity.ActivityRunId);
_logger.LogInformation("Activity name: " + activity.ActivityName);
_logger.LogInformation("Activity type: " + activity.ActivityType);
_logger.LogInformation("Error message: " + errorContent["message"].ToString());
output.Errors.Add(new FailedActivity()
{
ActivityRunId = activity.ActivityRunId,
ActivityName = activity.ActivityName,
ActivityType = activity.ActivityType,
ErrorCode = errorContent["errorCode"].ToString(),
ErrorType = errorContent["failureType"].ToString(),
ErrorMessage = errorContent["message"].ToString()
});
}
return output;
}
public override void Dispose()
{
_synManagementClient?.Dispose();
//_pipelineClient?.Dispose(); not yet supported
//_pipelineRunClient?.Dispose(); not yet supported
}
}
}
================================================
FILE: Functions/Services/PipelineService.cs
================================================
using mrpaulandrew.azure.procfwk.Helpers;
using Microsoft.Extensions.Logging;
using System;
namespace mrpaulandrew.azure.procfwk.Services
{
public abstract class PipelineService : IDisposable
{
public const int internalWaitDuration = 5000; //ms
public static PipelineService GetServiceForRequest(PipelineRequest pr, ILogger logger)
{
if (pr.OrchestratorType == PipelineServiceType.ADF)
return new AzureDataFactoryService(pr, logger);
if (pr.OrchestratorType == PipelineServiceType.SYN)
return new AzureSynapseService(pr, logger);
throw new InvalidRequestException ("Unsupported orchestrator type: " + (pr.OrchestratorType?.ToString() ?? ""));
}
public abstract PipelineDescription ValidatePipeline(PipelineRequest request);
public abstract PipelineRunStatus ExecutePipeline(PipelineRequest request);
public abstract PipelineRunStatus CancelPipeline(PipelineRunRequest request);
public abstract PipelineRunStatus GetPipelineRunStatus(PipelineRunRequest request);
public abstract PipelineErrorDetail GetPipelineRunActivityErrors(PipelineRunRequest request);
protected void PipelineNameCheck(string requestName, string foundName)
{
if (requestName.ToUpper() != foundName.ToUpper())
{
throw new InvalidRequestException($"Pipeline name mismatch. Provided pipeline name does not match the provided Run Id. Expected name: {foundName}");
}
}
public abstract void Dispose();
}
}
================================================
FILE: Functions/Services/PipelineServiceType.cs
================================================
namespace mrpaulandrew.azure.procfwk
{
public enum PipelineServiceType
{
ADF, SYN
}
}
================================================
FILE: Functions/Services/Returns/PipelineDescription.cs
================================================
namespace mrpaulandrew.azure.procfwk.Services
{
public class PipelineDescription
{
public string PipelineExists { get; set; }
public string PipelineName { get; set; }
public string PipelineId { get; set; }
public string PipelineType { get; set; }
public int ActivityCount { get; set; }
}
}
================================================
FILE: Functions/Services/Returns/PipelineErrorDetail.cs
================================================
using System.Collections.Generic;
namespace mrpaulandrew.azure.procfwk.Services
{
public class PipelineErrorDetail : PipelineRunStatus
{
public PipelineErrorDetail()
{
Errors = new List();
}
public int ResponseCount { get; set; }
public int ResponseErrorCount
{
get
{
return Errors.Count;
}
}
public List Errors { get; }
}
public class FailedActivity
{
public string ActivityRunId { get; internal set; }
public string ActivityName { get; internal set; }
public string ActivityType { get; internal set; }
public string ErrorCode { get; internal set; }
public string ErrorType { get; internal set; }
public string ErrorMessage { get; internal set; }
}
}
================================================
FILE: Functions/Services/Returns/PipelineRunStatus.cs
================================================
using System.Collections.Generic;
namespace mrpaulandrew.azure.procfwk.Services
{
public class PipelineRunStatus
{
private const string Running = "Running";
private const string Complete = "Complete";
public string PipelineName { get; set; }
public string RunId { get; set; }
public string ActualStatus { get; set; }
public string SimpleStatus
{
get
{
return ConvertPipelineStatus(ActualStatus);
}
}
private string ConvertPipelineStatus(string actualStatus)
{
string simpleStatus = actualStatus switch
{
"Queued" => Running,
"InProgress" => Running,
"Canceling" => Running, //microsoft typo
"Cancelling" => Running,
_ => Complete,
};
return simpleStatus;
}
}
}
================================================
FILE: Functions/host.json
================================================
{
"version": "2.0"
}
================================================
FILE: Functions/template_local.settings.json
================================================
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"AppSettingSmtpHost": "my.smtpservice.com",
"AppSettingSmtpPort": 1234,
"AppSettingSmtpUser": "AlertMailboxUser",
"AppSettingSmtpPass": "Passw0rd123!",
"AppSettingFromEmail": "noreply@adfprocfwk.com"
}
}
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2020 Paul Andrew (mrpaulandrew.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
THE SOFTWARE IS ALSO IN NO WAY ASOCIATED WITH OR SUPPORTED BY:
- Altius Consulting Limited
- Cloudpoint Limited
- Farah Bidco Limited
- Farah Midco Limited
- Farah Topco Limited
- Avanade UK Ltd
- Avanade Europe Services Ltd
- Avanade Europe Holdings Ltd
- Avanade International Corporation
================================================
FILE: MetadataDB/MetadataDB.refactorlog
================================================
================================================
FILE: MetadataDB/MetadataDB.sqlproj
================================================
Debug
AnyCPU
MetadataDB
2.0
4.1
{202ebf84-a56b-4999-92a3-10f7ffe4ef25}
Microsoft.Data.Tools.Schema.Sql.SqlAzureV12DatabaseSchemaProvider
Database
MetadataDB
MetadataDB
1033,CI
BySchemaAndSchemaType
True
v4.7.2
CS
Properties
False
True
True
SQL_Latin1_General_CP1_CI_AS
PRIMARY
procfwk
bin\Release\
$(MSBuildProjectName).sql
False
pdbonly
true
false
true
prompt
4
bin\Debug\
$(MSBuildProjectName).sql
false
true
full
false
true
true
prompt
4
11.0
True
11.0
$(DacPacRootPath)\Extensions\Microsoft\SQLDB\Extensions\SqlServer\AzureV12\SqlSchemas\master.dacpac
False
master
================================================
FILE: MetadataDB/Scripts/Alter Database Scale.sql
================================================
ALTER DATABASE [FrameworkMetadataDev] MODIFY (EDITION ='Standard', SERVICE_OBJECTIVE = 'S2', MAXSIZE = 50 GB);
================================================
FILE: MetadataDB/Scripts/Handy Selects.sql
================================================
SELECT * FROM [procfwk].[BatchExecution]
SELECT * FROM [procfwk].[CurrentExecution]
SELECT * FROM [procfwkReporting].[CurrentExecutionSummary]
SELECT * FROM [procfwk].[CurrentProperties]
SELECT * FROM [procfwk].[Batches]
SELECT * FROM [procfwk].[BatchStageLink]
SELECT * FROM [procfwk].[Orchestrators]
SELECT * FROM [procfwk].[Stages]
SELECT * FROM [procfwk].[Pipelines]
--SELECT * FROM [procfwk].[PipelineParameters]
SELECT * FROM [procfwk].[ExecutionLog]
SELECT * FROM [procfwk].[ErrorLog]
--SELECT * FROM [dbo].[ServicePrincipals]
================================================
FILE: MetadataDB/Scripts/LogData/ErrorLogBackup.sql
================================================
IF OBJECT_ID(N'[dbo].[ErrorLogBackup]') IS NOT NULL DROP TABLE [dbo].[ErrorLogBackup];
IF OBJECT_ID(N'[procfwk].[ErrorLog]') IS NOT NULL --check for new deployments
BEGIN
SELECT
*
INTO
[dbo].[ErrorLogBackup]
FROM
[procfwk].[ErrorLog];
END;
================================================
FILE: MetadataDB/Scripts/LogData/ErrorLogRestore.sql
================================================
DECLARE @ErrColumns VARCHAR(MAX) = '';
DECLARE @ErrValues VARCHAR(MAX) = '';
DECLARE @ErrSQL VARCHAR(MAX) = '';
IF EXISTS
(
SELECT
*
FROM
sys.objects o
INNER JOIN sys.schemas s
ON o.[schema_id] = s.[schema_id]
WHERE
o.[name] = 'ErrorLog'
AND s.[name] = 'procfwk'
)
AND EXISTS
(
SELECT
*
FROM
sys.objects o
INNER JOIN sys.schemas s
ON o.[schema_id] = s.[schema_id]
WHERE
o.[name] = 'ErrorLogBackup'
AND s.[name] = 'dbo'
)
BEGIN
;WITH oldTableColumns AS
(
SELECT
c.[name] AS 'ColName'
FROM
sys.objects o
INNER JOIN sys.schemas s
ON o.[schema_id] = s.[schema_id]
INNER JOIN sys.columns c
ON o.[object_id] = c.[object_id]
WHERE
s.[name] = 'dbo'
AND o.[name] = 'ErrorLogBackup'
AND c.[name] != 'LogId'
),
newTableColumns AS
(
SELECT
c.[column_id] AS 'ColId',
c.[name] AS 'ColName'
FROM
sys.objects o
INNER JOIN sys.schemas s
ON o.[schema_id] = s.[schema_id]
INNER JOIN sys.columns c
ON o.[object_id] = c.[object_id]
WHERE
s.[name] = 'procfwk'
AND o.[name] = 'ErrorLog'
AND c.[name] != 'LogId'
)
SELECT
@ErrColumns += QUOTENAME(newTableColumns.[ColName]) + ',' + CHAR(13),
@ErrValues += ISNULL(QUOTENAME(oldTableColumns.[ColName]),'NULL AS ''' + newTableColumns.[ColName] + '''' ) + ',' + CHAR(13)
FROM
newTableColumns
LEFT OUTER JOIN oldTableColumns
ON newTableColumns.[ColName] = oldTableColumns.[ColName];
SET @ErrColumns = LEFT(@ErrColumns,LEN(@ErrColumns)-2);
SET @ErrValues = LEFT(@ErrValues,LEN(@ErrValues)-2);
SET @ErrSQL =
'
INSERT INTO [procfwk].[ErrorLog]
(
' + @ErrColumns + '
)
SELECT
' + @ErrValues + '
FROM
[dbo].[ErrorLogBackup]
';
PRINT @ErrSQL;
EXEC(@ErrSQL);
DECLARE @ErrBefore INT = (SELECT COUNT(0) FROM [dbo].[ErrorLogBackup]);
DECLARE @ErrAfter INT = (SELECT COUNT(0) FROM [procfwk].[ErrorLog]);
IF (@ErrBefore = @ErrAfter)
BEGIN
DROP TABLE [dbo].[ErrorLogBackup]
END;
END
================================================
FILE: MetadataDB/Scripts/LogData/ExecutionLogBackup.sql
================================================
IF OBJECT_ID(N'[dbo].[ExecutionLogBackup]') IS NOT NULL DROP TABLE [dbo].[ExecutionLogBackup];
IF OBJECT_ID(N'[procfwk].[ExecutionLog]') IS NOT NULL --check for new deployments
BEGIN
SELECT
*
INTO
[dbo].[ExecutionLogBackup]
FROM
[procfwk].[ExecutionLog];
END;
================================================
FILE: MetadataDB/Scripts/LogData/ExecutionLogRestore.sql
================================================
DECLARE @Columns VARCHAR(MAX) = '';
DECLARE @Values VARCHAR(MAX) = '';
DECLARE @SQL VARCHAR(MAX) = '';
IF EXISTS
(
SELECT
*
FROM
sys.objects o
INNER JOIN sys.schemas s
ON o.[schema_id] = s.[schema_id]
WHERE
o.[name] = 'ExecutionLog'
AND s.[name] = 'procfwk'
)
AND EXISTS
(
SELECT
*
FROM
sys.objects o
INNER JOIN sys.schemas s
ON o.[schema_id] = s.[schema_id]
WHERE
o.[name] = 'ExecutionLogBackup'
AND s.[name] = 'dbo'
)
BEGIN
;WITH oldTableColumns AS
(
SELECT
c.[name] AS ColName
FROM
sys.objects o
INNER JOIN sys.schemas s
ON o.[schema_id] = s.[schema_id]
INNER JOIN sys.columns c
ON o.[object_id] = c.[object_id]
WHERE
s.[name] = 'dbo'
AND o.[name] = 'ExecutionLogBackup'
AND c.[name] <> 'LogId'
),
newTableColumns AS
(
SELECT
c.[column_id] AS ColId,
c.[name] AS ColName
FROM
sys.objects o
INNER JOIN sys.schemas s
ON o.[schema_id] = s.[schema_id]
INNER JOIN sys.columns c
ON o.[object_id] = c.[object_id]
WHERE
s.[name] = 'procfwk'
AND o.[name] = 'ExecutionLog'
AND c.[name] <> 'LogId'
)
SELECT
@Columns += QUOTENAME(newTableColumns.[ColName]) + ',' + CHAR(13),
@Values += ISNULL(QUOTENAME(oldTableColumns.[ColName]),'NULL AS ''' + newTableColumns.[ColName] + '''' ) + ',' + CHAR(13)
FROM
newTableColumns
LEFT OUTER JOIN oldTableColumns
ON newTableColumns.[ColName] = oldTableColumns.[ColName];
SET @Columns = LEFT(@Columns,LEN(@Columns)-2);
SET @Values = LEFT(@Values,LEN(@Values)-2);
SET @SQL =
'
INSERT INTO [procfwk].[ExecutionLog]
(
' + @Columns + '
)
SELECT
' + @Values + '
FROM
[dbo].[ExecutionLogBackup]
';
PRINT @SQL;
EXEC(@SQL);
DECLARE @Before INT = (SELECT COUNT(0) FROM [dbo].[ExecutionLogBackup]);
DECLARE @After INT = (SELECT COUNT(0) FROM [procfwk].[ExecutionLog]);
IF (@Before = @After)
BEGIN
DROP TABLE [dbo].[ExecutionLogBackup]
END;
END;
================================================
FILE: MetadataDB/Scripts/Metadata/AlertOutcomes.sql
================================================
EXEC [procfwkHelpers].[SetDefaultAlertOutcomes];
================================================
FILE: MetadataDB/Scripts/Metadata/DeleteAll.sql
================================================
--BatchExecution
IF OBJECT_ID(N'[procfwk].[BatchExecution]') IS NOT NULL
BEGIN
TRUNCATE TABLE [procfwk].[BatchExecution];
END;
--CurrentExecution
IF OBJECT_ID(N'[procfwk].[CurrentExecution]') IS NOT NULL
BEGIN
TRUNCATE TABLE [procfwk].[CurrentExecution];
END;
--ExecutionLog
IF OBJECT_ID(N'[procfwk].[ExecutionLog]') IS NOT NULL
BEGIN
TRUNCATE TABLE [procfwk].[ExecutionLog];
END
--ErrorLog
IF OBJECT_ID(N'[procfwk].[ExecutionLog]') IS NOT NULL
BEGIN
TRUNCATE TABLE [procfwk].[ErrorLog];
END
--BatchStageLink
IF OBJECT_ID(N'[procfwk].[BatchStageLink]') IS NOT NULL
BEGIN
DELETE FROM [procfwk].[BatchStageLink];
END;
--Batches
IF OBJECT_ID(N'[procfwk].[Batches]') IS NOT NULL
BEGIN
DELETE FROM [procfwk].[Batches];
END;
--PipelineDependencies
IF OBJECT_ID(N'[procfwk].[PipelineDependencies]') IS NOT NULL
BEGIN
DELETE FROM [procfwk].[PipelineDependencies];
DBCC CHECKIDENT ('[procfwk].[PipelineDependencies]', RESEED, 0);
END;
--PipelineAlertLink
IF OBJECT_ID(N'[procfwk].[PipelineAlertLink]') IS NOT NULL
BEGIN
DELETE FROM [procfwk].[PipelineAlertLink];
DBCC CHECKIDENT ('[procfwk].[PipelineAlertLink]', RESEED, 0);
END;
--Recipients
IF OBJECT_ID(N'[procfwk].[Recipients]') IS NOT NULL
BEGIN
DELETE FROM [procfwk].[Recipients];
DBCC CHECKIDENT ('[procfwk].[Recipients]', RESEED, 0);
END;
--AlertOutcomes
IF OBJECT_ID(N'[procfwk].[AlertOutcomes]') IS NOT NULL
BEGIN
TRUNCATE TABLE [procfwk].[AlertOutcomes];
END;
--PipelineAuthLink
IF OBJECT_ID(N'[procfwk].[PipelineAuthLink]') IS NOT NULL
BEGIN
DELETE FROM [procfwk].[PipelineAuthLink];
DBCC CHECKIDENT ('[procfwk].[PipelineAuthLink]', RESEED, 0);
END;
--ServicePrincipals
IF OBJECT_ID(N'[dbo].[ServicePrincipals]') IS NOT NULL
BEGIN
DELETE FROM [dbo].[ServicePrincipals];
DBCC CHECKIDENT ('[dbo].[ServicePrincipals]', RESEED, 0);
END;
--Properties
IF OBJECT_ID(N'[procfwk].[Properties]') IS NOT NULL
BEGIN
DELETE FROM [procfwk].[Properties];
DBCC CHECKIDENT ('[procfwk].[Properties]', RESEED, 0);
END;
--PipelineParameters
IF OBJECT_ID(N'[procfwk].[PipelineParameters]') IS NOT NULL
BEGIN
DELETE FROM [procfwk].[PipelineParameters];
DBCC CHECKIDENT ('[procfwk].[PipelineParameters]', RESEED, 0);
END;
--Pipelines
IF OBJECT_ID(N'[procfwk].[Pipelines]') IS NOT NULL
BEGIN
DELETE FROM [procfwk].[Pipelines];
DBCC CHECKIDENT ('[procfwk].[Pipelines]', RESEED, 0);
END;
--Orchestrators
IF EXISTS
(
SELECT
*
FROM
sys.objects o
INNER JOIN sys.schemas s
ON o.[schema_id] = s.[schema_id]
WHERE
o.[name] = 'DataFactorys'
AND s.[name] = 'procfwk'
AND o.[type] = 'U' --Check for tables as created synonyms to support backwards compatability
)
BEGIN
DELETE FROM [procfwk].[DataFactorys];
END;
IF OBJECT_ID(N'[procfwk].[Orchestrators]') IS NOT NULL
BEGIN
DELETE FROM [procfwk].[Orchestrators];
DBCC CHECKIDENT ('[procfwk].[Orchestrators]', RESEED, 0);
END;
--Stages
IF OBJECT_ID(N'[procfwk].[Stages]') IS NOT NULL
BEGIN
DELETE FROM [procfwk].[Stages];
DBCC CHECKIDENT ('[procfwk].[Stages]', RESEED, 0);
END;
--Subscriptions
IF OBJECT_ID(N'[procfwk].[Subscriptions]') IS NOT NULL
BEGIN
DELETE FROM [procfwk].[Subscriptions];
END;
--Tenants
IF OBJECT_ID(N'[procfwk].[Tenants]') IS NOT NULL
BEGIN
DELETE FROM [procfwk].[Tenants];
END;
================================================
FILE: MetadataDB/Scripts/Metadata/DropLegacyObjects.sql
================================================
IF OBJECT_ID(N'tempdb..#DropLegacyObjects') IS NOT NULL DROP PROCEDURE #DropLegacyObjects;
GO
CREATE PROCEDURE #DropLegacyObjects
(
@ObjectName NVARCHAR(128),
@ObjectType CHAR(2)
)
AS
BEGIN
DECLARE @DDLType NVARCHAR(128)
IF EXISTS
(
SELECT
*
FROM
sys.objects o
INNER JOIN sys.schemas s
ON o.[schema_id] = s.[schema_id]
WHERE
o.[Name] = @ObjectName
AND s.[name] = 'procfwk'
AND o.[type] = @ObjectType
)
BEGIN
SELECT
@DDLType = CASE @ObjectType
WHEN 'P' THEN 'PROCEDURE'
WHEN 'V' THEN 'VIEW'
WHEN 'FN' THEN 'FUNCTION'
END;
EXEC('DROP ' + @DDLType + ' [procfwk].[' + @ObjectName + '];')
END;
END;
GO
EXEC #DropLegacyObjects 'AddProperty', 'P';
EXEC #DropLegacyObjects 'GetExecutionDetails', 'P';
EXEC #DropLegacyObjects 'AddRecipientPipelineAlerts', 'P';
EXEC #DropLegacyObjects 'DeleteRecipientAlerts', 'P';
EXEC #DropLegacyObjects 'CheckStageAndPiplineIntegrity', 'P';
EXEC #DropLegacyObjects 'AddPipelineDependant', 'P';
EXEC #DropLegacyObjects 'AddServicePrincipalWrapper', 'P';
EXEC #DropLegacyObjects 'AddServicePrincipalUrls', 'P';
EXEC #DropLegacyObjects 'AddServicePrincipal', 'P';
EXEC #DropLegacyObjects 'DeleteServicePrincipal', 'P';
EXEC #DropLegacyObjects 'CheckForValidURL', 'FN';
EXEC #DropLegacyObjects 'PipelineDependencyChains', 'V';
EXEC #DropLegacyObjects 'AverageStageDuration', 'V';
EXEC #DropLegacyObjects 'CompleteExecutionErrorLog', 'V';
EXEC #DropLegacyObjects 'CompleteExecutionLog', 'V';
EXEC #DropLegacyObjects 'CurrentExecutionSummary', 'V';
EXEC #DropLegacyObjects 'LastExecution', 'V';
EXEC #DropLegacyObjects 'LastExecutionSummary', 'V';
EXEC #DropLegacyObjects 'WorkerParallelismOverTime', 'V';
--replaced with new precursor concept in v1.8.5:
IF OBJECT_ID(N'[dbo].[SetRandomWaitValues]') IS NOT NULL DROP PROCEDURE [dbo].[SetRandomWaitValues];
================================================
FILE: MetadataDB/Scripts/Metadata/DropLegacyTables.sql
================================================
--PipelineProcesses
IF EXISTS
(
SELECT
*
FROM
sys.objects o
INNER JOIN sys.schemas s
ON o.[schema_id] = s.[schema_id]
WHERE
o.[name] = 'PipelineProcesses'
AND s.[name] = 'procfwk'
AND o.[type] = 'U' --Check for tables as created synonyms to support backwards compatability
)
BEGIN
--drop just to avoid constraints
IF OBJECT_ID(N'[procfwk].[PipelineParameters]') IS NOT NULL DROP TABLE [procfwk].[PipelineParameters];
IF OBJECT_ID(N'[procfwk].[PipelineAuthLink]') IS NOT NULL DROP TABLE [procfwk].[PipelineAuthLink];
SELECT * INTO [dbo].[zz_PipelineProcesses] FROM [procfwk].[PipelineProcesses];
DROP TABLE [procfwk].[PipelineProcesses];
END
--ProcessingStageDetails
IF EXISTS
(
SELECT
*
FROM
sys.objects o
INNER JOIN sys.schemas s
ON o.[schema_id] = s.[schema_id]
WHERE
o.[name] = 'ProcessingStageDetails'
AND s.[name] = 'procfwk'
AND o.[type] = 'U' --Check for tables as created synonyms to support backwards compatability
)
BEGIN
SELECT * INTO [dbo].[zz_ProcessingStageDetails] FROM [procfwk].[ProcessingStageDetails];
DROP TABLE [procfwk].[ProcessingStageDetails];
END;
--DataFactoryDetails
IF EXISTS
(
SELECT
*
FROM
sys.objects o
INNER JOIN sys.schemas s
ON o.[schema_id] = s.[schema_id]
WHERE
o.[name] = 'DataFactoryDetails'
AND s.[name] = 'procfwk'
AND o.[type] = 'U' --Check for tables as created synonyms to support backwards compatability
)
BEGIN
SELECT * INTO [dbo].[zz_DataFactoryDetails] FROM [procfwk].[DataFactoryDetails];
DROP TABLE [procfwk].[DataFactoryDetails];
END;
--DataFactorys
IF EXISTS
(
SELECT
*
FROM
sys.objects o
INNER JOIN sys.schemas s
ON o.[schema_id] = s.[schema_id]
WHERE
o.[name] = 'DataFactorys'
AND s.[name] = 'procfwk'
AND o.[type] = 'U' --Check for tables as created synonyms to support backwards compatability
)
BEGIN
SELECT * INTO [dbo].[zz_DataFactorys] FROM [procfwk].[DataFactorys];
END;
================================================
FILE: MetadataDB/Scripts/Metadata/Orchestrators.sql
================================================
EXEC [procfwkHelpers].[SetDefaultTenant];
EXEC [procfwkHelpers].[SetDefaultSubscription];
EXEC [procfwkHelpers].[SetDefaultOrchestrators];
================================================
FILE: MetadataDB/Scripts/Metadata/PipelineDependencies.sql
================================================
EXEC [procfwkHelpers].[SetDefaultPipelineDependants];
================================================
FILE: MetadataDB/Scripts/Metadata/PipelineParams.sql
================================================
EXEC [procfwkHelpers].[SetDefaultPipelineParameters];
================================================
FILE: MetadataDB/Scripts/Metadata/Pipelines.sql
================================================
EXEC [procfwkHelpers].[SetDefaultPipelines];
================================================
FILE: MetadataDB/Scripts/Metadata/Properties.sql
================================================
EXEC [procfwkHelpers].[SetDefaultProperties];
================================================
FILE: MetadataDB/Scripts/Metadata/RecipientAlertsLink.sql
================================================
EXEC [procfwkHelpers].[SetDefaultRecipientPipelineAlerts]
================================================
FILE: MetadataDB/Scripts/Metadata/Recipients.sql
================================================
EXEC [procfwkHelpers].[SetDefaultRecipients];
================================================
FILE: MetadataDB/Scripts/Metadata/ReplaceDataFactorys.sql
================================================
IF EXISTS
(
SELECT
*
FROM
sys.objects o
INNER JOIN sys.schemas s
ON o.[schema_id] = s.[schema_id]
WHERE
o.[name] = 'DataFactorys'
AND s.[name] = 'procfwk'
AND o.[type] = 'U' --Check for tables as created synonyms to support backwards compatability
)
BEGIN
DROP TABLE [procfwk].[DataFactorys];
EXEC('CREATE VIEW [procfwk].[DataFactorys]
AS
SELECT
[OrchestratorId] AS DataFactoryId,
[OrchestratorName] AS DataFactoryName,
[ResourceGroupName],
[SubscriptionId],
[Description]
FROM
[procfwk].[Orchestrators]
WHERE
[OrchestratorType] = ''ADF'';')
END;
================================================
FILE: MetadataDB/Scripts/Metadata/Stages.sql
================================================
EXEC [procfwkHelpers].[SetDefaultBatches];
EXEC [procfwkHelpers].[SetDefaultStages];
EXEC [procfwkHelpers].[SetDefaultBatchStageLink];
================================================
FILE: MetadataDB/Scripts/Metadata/TransferHelperObjects.sql
================================================
IF OBJECT_ID(N'tempdb..#TransferHelperObjects') IS NOT NULL DROP PROCEDURE #TransferHelperObjects;
GO
CREATE PROCEDURE #TransferHelperObjects
(
@ObjectName NVARCHAR(128),
@ObjectType CHAR(2)
)
AS
BEGIN
IF EXISTS
(
SELECT
*
FROM
sys.objects o
INNER JOIN sys.schemas s
ON o.[schema_id] = s.[schema_id]
WHERE
o.[Name] = @ObjectName
AND s.[name] = 'procfwk'
AND o.[type] = @ObjectType
)
BEGIN
PRINT 'Transferring: ' + @ObjectName;
EXEC('ALTER SCHEMA [procfwkHelpers] TRANSFER [procfwk].[' + @ObjectName + '];')
END;
END;
GO
EXEC #TransferHelperObjects 'AddProperty', 'P';
EXEC #TransferHelperObjects 'GetExecutionDetails', 'P';
EXEC #TransferHelperObjects 'AddRecipientPipelineAlerts', 'P';
EXEC #TransferHelperObjects 'DeleteRecipientAlerts', 'P';
EXEC #TransferHelperObjects 'CheckStageAndPiplineIntegrity', 'P';
EXEC #TransferHelperObjects 'AddPipelineDependant', 'P';
EXEC #TransferHelperObjects 'AddServicePrincipalWrapper', 'P';
EXEC #TransferHelperObjects 'AddServicePrincipalUrls', 'P';
EXEC #TransferHelperObjects 'AddServicePrincipal', 'P';
EXEC #TransferHelperObjects 'DeleteServicePrincipal', 'P';
EXEC #TransferHelperObjects 'CheckForValidURL', 'FN';
EXEC #TransferHelperObjects 'PipelineDependencyChains', 'V';
================================================
FILE: MetadataDB/Scripts/Metadata/TransferReportingObjects.sql
================================================
IF OBJECT_ID(N'tempdb..#TransferReportingObjects') IS NOT NULL DROP PROCEDURE #TransferReportingObjects;
GO
CREATE PROCEDURE #TransferReportingObjects
(
@ObjectName NVARCHAR(128),
@ObjectType CHAR(2)
)
AS
BEGIN
IF EXISTS
(
SELECT
*
FROM
sys.objects o
INNER JOIN sys.schemas s
ON o.[schema_id] = s.[schema_id]
WHERE
o.[Name] = @ObjectName
AND s.[name] = 'procfwk'
AND o.[type] = @ObjectType
)
BEGIN
PRINT 'Transferring: ' + @ObjectName;
EXEC('ALTER SCHEMA [procfwkHelpers] TRANSFER [procfwk].[' + @ObjectName + '];')
END;
END;
GO
EXEC #TransferReportingObjects 'PipelineDependencyChains', 'V';
================================================
FILE: MetadataDB/Scripts/Script.PostDeployment.sql
================================================
/*
Post-Deployment Script Template
--------------------------------------------------------------------------------------
This file contains SQL statements that will be appended to the build script.
Use SQLCMD syntax to include a file in the post-deployment script.
Example: :r .\myfile.sql
Use SQLCMD syntax to reference a variable in the post-deployment script.
Example: :setvar TableName MyTable
SELECT * FROM [$(TableName)]
--------------------------------------------------------------------------------------
*/
--load default metadata
:r .\Metadata\Properties.sql
:r .\Metadata\Orchestrators.sql
:r .\Metadata\Stages.sql
:r .\Metadata\Pipelines.sql
:r .\Metadata\PipelineParams.sql
:r .\Metadata\PipelineDependencies.sql
:r .\Metadata\Recipients.sql
:r .\Metadata\AlertOutcomes.sql
:r .\Metadata\RecipientAlertsLink.sql
--restore log data
:r .\LogData\ExecutionLogRestore.sql
:r .\LogData\ErrorLogRestore.sql
--object transfers
:r .\Metadata\TransferHelperObjects.sql
:r .\Metadata\TransferReportingObjects.sql
--replace old objects
:r .\Metadata\ReplaceDataFactorys.sql
================================================
FILE: MetadataDB/Scripts/Script.PreDeployment.sql
================================================
/*
Pre-Deployment Script Template
--------------------------------------------------------------------------------------
This file contains SQL statements that will be executed before the build script.
Use SQLCMD syntax to include a file in the pre-deployment script.
Example: :r .\myfile.sql
Use SQLCMD syntax to reference a variable in the pre-deployment script.
Example: :setvar TableName MyTable
SELECT * FROM [$(TableName)]
--------------------------------------------------------------------------------------
*/
--data
:r .\LogData\ExecutionLogBackup.sql
:r .\LogData\ErrorLogBackup.sql
--delete all
:r .\Metadata\DropLegacyTables.sql
:r .\Metadata\DropLegacyObjects.sql
:r .\Metadata\DeleteAll.sql
================================================
FILE: MetadataDB/Scripts/Script.SetLocalAuthenticationDetails.sql
================================================
--Run in SQLCMD mode to use environment variables.
--Optional script used to setup function testing for processing framework parts post deployment.
PRINT 'TenantId: ' + '$(AZURE_TENANT_ID)'
PRINT 'SubscriptionId: ' + '$(AZURE_SUBSCRIPTION_ID)'
--add my tenant
INSERT INTO [procfwk].[Tenants]
(
[TenantId],
[Name],
[Description]
)
VALUES
('$(AZURE_TENANT_ID)', 'mrpaulandrew.com', NULL);
--add my subscription
INSERT INTO [procfwk].[Subscriptions]
(
[SubscriptionId],
[Name],
[Description],
[TenantId]
)
VALUES
('$(AZURE_SUBSCRIPTION_ID)', 'Microsoft Sponsored Subscription', NULL, '$(AZURE_TENANT_ID)');
--update Orchestrator with new subscription
UPDATE
[procfwk].[Orchestrators]
SET
[SubscriptionId] = '$(AZURE_SUBSCRIPTION_ID)';
--remove default values
DELETE FROM [procfwk].[Subscriptions] WHERE [SubscriptionId] = '12345678-1234-1234-1234-012345678910';
DELETE FROM [procfwk].[Tenants] WHERE [TenantId] = '12345678-1234-1234-1234-012345678910';
/*
EXEC [procfwkHelpers].[AddProperty]
@PropertyName = N'SPNHandlingMethod',
@PropertyValue = N'StoreInKeyVault',
@Description = N'Accepted values: StoreInDatabase, StoreInKeyVault. See v1.8.2 release notes for full details.';
*/
IF (SELECT [procfwk].[GetPropertyValueInternal]('SPNHandlingMethod')) = 'StoreInDatabase'
BEGIN
--Add SPN for execution of all worker pipelines using database to store SPN values
EXEC [procfwkHelpers].[AddServicePrincipalWrapper]
@OrchestratorName = N'FrameworkFactory',
@OrchestratorType = 'ADF',
@PrincipalIdValue = '$(AZURE_CLIENT_ID)',
@PrincipalSecretValue = '$(AZURE_CLIENT_SECRET)',
@PrincipalName = '$(AZURE_CLIENT_NAME)';
EXEC [procfwkHelpers].[AddServicePrincipalWrapper]
@OrchestratorName = N'procfwkforsynapse',
@OrchestratorType = 'SYN',
@PrincipalIdValue = '$(AZURE_CLIENT_ID)',
@PrincipalSecretValue = '$(AZURE_CLIENT_SECRET)',
@PrincipalName = '$(AZURE_CLIENT_NAME)';
/*
--Add specific SPN for execution of Wait 1 pipeline (functional testing)
EXEC [procfwkHelpers].[DeleteServicePrincipal]
@OrchestratorName = N'FrameworkFactory',
@OrchestratorType = 'ADF',
@PrincipalIdValue = '$(AZURE_CLIENT_ID)',
@SpecificPipelineName = N'Wait 1';
EXEC [procfwkHelpers].[AddServicePrincipalWrapper]
@OrchestratorName = N'FrameworkFactory',
@OrchestratorType = 'ADF',
@PrincipalIdValue = '$(AZURE_CLIENT_ID_2)',
@PrincipalSecretValue = '$(AZURE_CLIENT_SECRET_2)',
@PrincipalName = '$(AZURE_CLIENT_NAME_2)',
@SpecificPipelineName = N'Wait 1';
*/
END
ELSE IF (SELECT [procfwk].[GetPropertyValueInternal]('SPNHandlingMethod')) = 'StoreInKeyVault'
BEGIN
--Add SPN for execution of all worker pipelines using database to store key vault URLs
EXEC [procfwkHelpers].[AddServicePrincipalWrapper]
@OrchestratorName = N'FrameworkFactory',
@OrchestratorType = 'ADF',
@PrincipalIdValue = '$(AZURE_CLIENT_ID_URL)',
@PrincipalSecretValue = '$(AZURE_CLIENT_SECRET_URL)',
@PrincipalName = '$(AZURE_CLIENT_NAME)';
END
ELSE
BEGIN
RAISERROR('Unknown SPN insert method.',16,1);
END;
SELECT * FROM [dbo].[ServicePrincipals];
================================================
FILE: MetadataDB/Security/procfwk.sql
================================================
CREATE SCHEMA [procfwk]
AUTHORIZATION [dbo];
================================================
FILE: MetadataDB/Security/procfwkHelpers.sql
================================================
CREATE SCHEMA [procfwkHelpers]
AUTHORIZATION [dbo];
================================================
FILE: MetadataDB/Security/procfwkReporting.sql
================================================
CREATE SCHEMA [procfwkReporting]
AUTHORIZATION [dbo];
================================================
FILE: MetadataDB/Security/procfwkTesting.sql
================================================
CREATE SCHEMA [procfwkTesting]
AUTHORIZATION [dbo];
================================================
FILE: MetadataDB/Security/procfwkuser Role.sql
================================================
/*
CREATE USER [##Data Factory Name (Managed Identity)##]
FROM EXTERNAL PROVIDER;
*/
CREATE ROLE [procfwkuser]
GO
GRANT
EXECUTE,
SELECT,
CONTROL,
ALTER
ON SCHEMA::[procfwk] TO [procfwkuser]
GO
/*
ALTER ROLE [procfwkuser]
ADD MEMBER [##Data Factory Name (Managed Identity)##];
*/
================================================
FILE: MetadataDB/dbo/Stored Procedures/DemoModePrecursor.sql
================================================
CREATE PROCEDURE [dbo].[DemoModePrecursor]
AS
BEGIN
--quick win
IF ([procfwk].[GetPropertyValueInternal]('ExecutionPrecursorProc')) <> '[dbo].[DemoModePrecursor]'
BEGIN
EXEC [procfwkHelpers].[AddProperty]
@PropertyName = N'ExecutionPrecursorProc',
@PropertyValue = N'[dbo].[DemoModePrecursor]';
END;
--reduce wait times
;WITH cte AS
(
SELECT
[PipelineId],
LEFT(ABS(CAST(CAST(NEWID() AS VARBINARY(192)) AS INT)),1) AS NewValue
FROM
[procfwk].[PipelineParameters]
)
UPDATE
pp
SET
pp.[ParameterValue] = cte.[NewValue]
FROM
[procfwk].[PipelineParameters] pp
INNER JOIN cte
ON pp.[PipelineId] = cte.[PipelineId]
INNER JOIN [procfwk].[Pipelines] p
ON pp.[PipelineId] = p.[PipelineId]
WHERE
pp.[ParameterName] LIKE 'Wait%'
AND p.[Enabled] = 1;
--for intentional error
IF NOT EXISTS
(
SELECT * FROM [procfwk].[CurrentExecution]
)
BEGIN
UPDATE
pp
SET
pp.[ParameterValue] = 'true'
FROM
[procfwk].[PipelineParameters] pp
INNER JOIN [procfwk].[Pipelines] p
ON pp.[PipelineId] = p.[PipelineId]
WHERE
p.[PipelineName] = 'Intentional Error'
AND pp.[ParameterName] = 'RaiseErrors';
END;
ELSE
BEGIN
UPDATE
pp
SET
pp.[ParameterValue] = 'false'
FROM
[procfwk].[PipelineParameters] pp
INNER JOIN [procfwk].[Pipelines] p
ON pp.[PipelineId] = p.[PipelineId]
WHERE
p.[PipelineName] = 'Intentional Error'
AND pp.[ParameterName] = 'RaiseErrors';
END;
--dependency chain failure handling
IF ([procfwk].[GetPropertyValueInternal]('FailureHandling')) <> 'DependencyChain'
BEGIN
EXEC [procfwkHelpers].[AddProperty]
@PropertyName = N'FailureHandling',
@PropertyValue = N'DependencyChain';
END;
--short infant iterations
IF ([procfwk].[GetPropertyValueInternal]('PipelineStatusCheckDuration')) <> '5'
BEGIN
EXEC [procfwkHelpers].[AddProperty]
@PropertyName = N'PipelineStatusCheckDuration',
@PropertyValue = N'5';
END;
END;
================================================
FILE: MetadataDB/dbo/Stored Procedures/ExampleCustomExecutionPrecursor.sql
================================================
CREATE PROCEDURE [dbo].[ExampleCustomExecutionPrecursor]
AS
BEGIN
--set random Worker pipeline parameter wait times for development environment
;WITH cte AS
(
SELECT
[PipelineId],
LEFT(ABS(CAST(CAST(NEWID() AS VARBINARY(192)) AS INT)),2) AS NewValue
FROM
[procfwk].[PipelineParameters]
)
UPDATE
pp
SET
pp.[ParameterValue] = cte.[NewValue]
FROM
[procfwk].[PipelineParameters] pp
INNER JOIN cte
ON pp.[PipelineId] = cte.[PipelineId]
INNER JOIN [procfwk].[Pipelines] p
ON pp.[PipelineId] = p.[PipelineId]
WHERE
pp.[ParameterName] LIKE 'Wait%'
AND p.[Enabled] = 1;
--disable certain Workers if running at the weekend...
-- YOUR CODE HERE
--enable certain Workers if running on the 10th day of the month...
-- YOUR CODE HERE
--disable certain Stages if running on Friday...
-- YOUR CODE HERE
--set Worker pipeline parameters to new value based on ______ ....
-- YOUR CODE HERE
--etc
END;
================================================
FILE: MetadataDB/dbo/Stored Procedures/FailProcedure.sql
================================================
CREATE PROCEDURE [dbo].[FailProcedure]
(
@RaiseError VARCHAR(50)
)
AS
BEGIN
IF(@RaiseError = 'true')
BEGIN
RAISERROR('The Stored Procedure intentionally failed.',16,1);
RETURN 0;
END
END;
================================================
FILE: MetadataDB/dbo/Tables/ServicePrincipals.sql
================================================
CREATE TABLE [dbo].[ServicePrincipals](
[CredentialId] INT IDENTITY(1,1) NOT NULL,
[PrincipalName] NVARCHAR(256) NULL,
[PrincipalId] UNIQUEIDENTIFIER NULL,
[PrincipalSecret] VARBINARY(256) NULL,
[PrincipalIdUrl] NVARCHAR(MAX) NULL,
[PrincipalSecretUrl] NVARCHAR(MAX) NULL,
CONSTRAINT [PK_ServicePrincipals] PRIMARY KEY CLUSTERED ([CredentialId] ASC)
)
GO
================================================
FILE: MetadataDB/procfwk/Functions/GetPropertyValueInternal.sql
================================================
CREATE FUNCTION [procfwk].[GetPropertyValueInternal]
(
@PropertyName VARCHAR(128)
)
RETURNS NVARCHAR(MAX)
AS
BEGIN
DECLARE @PropertyValue NVARCHAR(MAX)
SELECT
@PropertyValue = ISNULL([PropertyValue],'')
FROM
[procfwk].[CurrentProperties]
WHERE
[PropertyName] = @PropertyName
RETURN @PropertyValue
END;
================================================
FILE: MetadataDB/procfwk/Stored Procedures/BatchWrapper.sql
================================================
CREATE PROCEDURE [procfwk].[BatchWrapper]
(
@BatchId UNIQUEIDENTIFIER,
@LocalExecutionId UNIQUEIDENTIFIER OUTPUT
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @RestartStatus BIT
--get restart overide property
SELECT @RestartStatus = [procfwk].[GetPropertyValueInternal]('OverideRestart')
--check for running batch execution
IF EXISTS
(
SELECT 1 FROM [procfwk].[BatchExecution] WHERE [BatchId] = @BatchId AND ISNULL([BatchStatus],'') = 'Running'
)
BEGIN
SELECT
@LocalExecutionId = [ExecutionId]
FROM
[procfwk].[BatchExecution]
WHERE
[BatchId] = @BatchId;
--should never actually be called as handled within Orchestrator pipelines using the Pipeline Run Check utility
RAISERROR('There is already an batch execution run in progress. Stop the related parent pipeline via the Orchestrator first.',16,1);
RETURN 0;
END
ELSE IF EXISTS
(
SELECT 1 FROM [procfwk].[BatchExecution] WHERE [BatchId] = @BatchId AND ISNULL([BatchStatus],'') = 'Stopped'
)
AND @RestartStatus = 0
BEGIN
SELECT
@LocalExecutionId = [ExecutionId]
FROM
[procfwk].[BatchExecution]
WHERE
[BatchId] = @BatchId
AND ISNULL([BatchStatus],'') = 'Stopped';
RETURN 0;
END
ELSE IF EXISTS
(
SELECT 1 FROM [procfwk].[BatchExecution] WHERE [BatchId] = @BatchId AND ISNULL([BatchStatus],'') = 'Stopped'
)
AND @RestartStatus = 1
BEGIN
--clean up current execution table and abandon batch
SELECT
@LocalExecutionId = [ExecutionId]
FROM
[procfwk].[BatchExecution]
WHERE
[BatchId] = @BatchId
AND ISNULL([BatchStatus],'') = 'Stopped';
EXEC [procfwk].[UpdateExecutionLog]
@PerformErrorCheck = 0, --Special case when OverideRestart = 1;
@ExecutionId = @LocalExecutionId;
--abandon previous batch execution
UPDATE
[procfwk].[BatchExecution]
SET
[BatchStatus] = 'Abandoned'
WHERE
[BatchId] = @BatchId
AND ISNULL([BatchStatus],'') = 'Stopped';
SET @LocalExecutionId = NEWID();
--create new batch run record
INSERT INTO [procfwk].[BatchExecution]
(
[BatchId],
[ExecutionId],
[BatchName],
[BatchStatus],
[StartDateTime]
)
SELECT
[BatchId],
@LocalExecutionId,
[BatchName],
'Running',
GETUTCDATE()
FROM
[procfwk].[Batches]
WHERE
[BatchId] = @BatchId;
END
ELSE
BEGIN
SET @LocalExecutionId = NEWID();
--create new batch run record
INSERT INTO [procfwk].[BatchExecution]
(
[BatchId],
[ExecutionId],
[BatchName],
[BatchStatus],
[StartDateTime]
)
SELECT
[BatchId],
@LocalExecutionId,
[BatchName],
'Running',
GETUTCDATE()
FROM
[procfwk].[Batches]
WHERE
[BatchId] = @BatchId;
END;
END;
================================================
FILE: MetadataDB/procfwk/Stored Procedures/CheckForBlockedPipelines.sql
================================================
CREATE PROCEDURE [procfwk].[CheckForBlockedPipelines]
(
@ExecutionId UNIQUEIDENTIFIER,
@StageId INT
)
AS
BEGIN
SET NOCOUNT ON;
-- If any pipelines still have a status of running, mark as failed to block downstream processing, and add an error log
IF EXISTS
(
SELECT
*
FROM
[procfwk].[CurrentExecution]
WHERE
[LocalExecutionId] = @ExecutionId
AND [StageId] < @StageId
AND [PipelineStatus] = 'Running'
)
BEGIN
DECLARE @RunningPipelineId INT;
DECLARE @RunningPipelineStageId INT;
DECLARE @RunId UNIQUEIDENTIFIER;
DECLARE @ErrorJson NVARCHAR(MAX);
DECLARE @RunningCursor CURSOR ;
SET @RunningCursor = CURSOR FOR
SELECT
[PipelineId],
[StageId],
[PipelineRunId]
FROM
[procfwk].[CurrentExecution]
WHERE
[LocalExecutionId] = @ExecutionId
AND [StageId] < @StageId
AND [PipelineStatus] = 'Running'
OPEN @RunningCursor
FETCH NEXT FROM @RunningCursor INTO @RunningPipelineId, @RunningPipelineStageId, @RunId
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC [procfwk].SetLogPipelineFailed
@ExecutionId = @ExecutionId,
@StageId = @RunningPipelineStageId,
@PipelineId = @RunningPipelineId,
@RunId = @RunId;
SET @ErrorJson = '{ "RunId": "' + Cast(@RunId AS CHAR(36)) + '", "Errors": [ { "ActivityRunId": "00000000-0000-0000-0000-000000000000", "ActivityName": "Set Pipeline Result", "ActivityType": "Switch", "ErrorCode": "Unknown", "ErrorType": "Framework Error", "ErrorMessage": "Framework pipeline ''04-Infant'' failed to set the pipeline result, most likely due to a timeout or azure connectivity issue. Check the framework Data Factory monitor for more information." } ] }'
EXEC procfwk.SetErrorLogDetails @LocalExecutionId = @ExecutionId,
@JsonErrorDetails = @ErrorJson;
FETCH NEXT FROM @RunningCursor INTO @RunningPipelineId, @RunningPipelineStageId, @RunId;
END;
CLOSE @RunningCursor;
DEALLOCATE @RunningCursor;
END;
IF ([procfwk].[GetPropertyValueInternal]('FailureHandling')) = 'None'
BEGIN
--do nothing allow processing to carry on regardless
RETURN 0;
END;
ELSE IF ([procfwk].[GetPropertyValueInternal]('FailureHandling')) = 'Simple'
BEGIN
IF EXISTS
(
SELECT
*
FROM
[procfwk].[CurrentExecution]
WHERE
[LocalExecutionId] = @ExecutionId
AND [StageId] = @StageId
AND [IsBlocked] = 1
)
BEGIN
UPDATE
[procfwk].[BatchExecution]
SET
[EndDateTime] = GETUTCDATE(),
[BatchStatus] = 'Stopped'
WHERE
[ExecutionId] = @ExecutionId;
--Saves the infant pipeline and activities being called throwing the exception at this level.
RAISERROR('All pipelines are blocked. Stopping processing.',16,1);
--If not thrown here, the proc [procfwk].[UpdateExecutionLog] would eventually throw an exception.
RETURN 0;
END
END;
ELSE IF ([procfwk].[GetPropertyValueInternal]('FailureHandling')) = 'DependencyChain'
BEGIN
IF EXISTS
(
SELECT
*
FROM
[procfwk].[CurrentExecution]
WHERE
[LocalExecutionId] = @ExecutionId
AND [StageId] = @StageId
AND [IsBlocked] = 1
)
BEGIN
DECLARE @PipelineId INT;
DECLARE @Cursor CURSOR ;
SET @Cursor = CURSOR FOR
SELECT
[PipelineId]
FROM
[procfwk].[CurrentExecution]
WHERE
[LocalExecutionId] = @ExecutionId
AND [StageId] = @StageId
AND [IsBlocked] = 1
OPEN @Cursor
FETCH NEXT FROM @Cursor INTO @PipelineId
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC [procfwk].[SetExecutionBlockDependants]
@ExecutionId = @ExecutionId,
@PipelineId = @PipelineId;
FETCH NEXT FROM @Cursor INTO @PipelineId;
END;
CLOSE @Cursor;
DEALLOCATE @Cursor;
END;
END;
ELSE
BEGIN
RAISERROR('Unknown failure handling state.',16,1);
RETURN 0;
END;
END;
================================================
FILE: MetadataDB/procfwk/Stored Procedures/CheckForEmailAlerts.sql
================================================
CREATE PROCEDURE [procfwk].[CheckForEmailAlerts]
(
@PipelineId INT
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @SendAlerts BIT
DECLARE @AlertingEnabled BIT
--get property
SELECT
@AlertingEnabled = [procfwk].[GetPropertyValueInternal]('UseFrameworkEmailAlerting');
--based on global property
IF (@AlertingEnabled = 1)
BEGIN
--based on piplines to recipients link
IF EXISTS
(
SELECT pal.AlertId
FROM procfwk.CurrentExecution AS ce
INNER JOIN procfwk.AlertOutcomes AS ao
ON ao.PipelineOutcomeStatus = ce.PipelineStatus
INNER JOIN procfwk.PipelineAlertLink AS pal
ON pal.PipelineId = ce.PipelineId
INNER JOIN procfwk.Recipients AS r
ON r.RecipientId = pal.RecipientId
WHERE ce.PipelineId = @PipelineId
AND (
ao.BitValue & pal.OutcomesBitValue <> 0
OR pal.OutcomesBitValue & 1 <> 0 --all
)
AND pal.[Enabled] = 1
AND r.[Enabled] = 1
)
BEGIN
SET @SendAlerts = 1;
END;
ELSE
BEGIN
SET @SendAlerts = 0;
END;
END
ELSE
BEGIN
SET @SendAlerts = 0;
END;
SELECT @SendAlerts AS SendAlerts
END;
================================================
FILE: MetadataDB/procfwk/Stored Procedures/CheckMetadataIntegrity.sql
================================================
CREATE PROCEDURE [procfwk].[CheckMetadataIntegrity]
(
@DebugMode BIT = 0,
@BatchName VARCHAR(255) = NULL
)
AS
BEGIN
SET NOCOUNT ON;
/*
Check 1 - Are there execution stages enabled in the metadata?
Check 2 - Are there pipelines enabled in the metadata?
Check 3 - Are there any service principals available to run the processing pipelines?
Check 4 - Is there at least one TenantId available?
Check 5 - Is there at least one SubscriptionId available?
Check 6 - Is there a current OverideRestart property available?
Check 7 - Are there any enabled pipelines configured without a service principal?
Check 8 - Are any Orchestrators set to use the default subscription value?
Check 9 - Are any Subscription set to use the default tenant value?
Check 10 - Is there a current PipelineStatusCheckDuration property available?
Check 11 - Is there a current UseFrameworkEmailAlerting property available?
Check 12 - Is there a current EmailAlertBodyTemplate property available?
Check 13 - Does the total size of the request body for the pipeline parameters added exceed the Azure Functions size limit when the Worker execute pipeline body is created?
Check 14 - Is there a current FailureHandling property available?
Check 15 - Does the FailureHandling property have a valid value?
Check 16 - When using DependencyChain failure handling, are there any dependants in the same execution stage of the predecessor?
Check 17 - Does the SPNHandlingMethod property have a valid value?
Check 18 - Does the Service Principal table contain both types of SPN handling for a single credential?
Check 19 - Is there a current UseExecutionBatches property available?
Check 20 - Is there a current FrameworkFactoryResourceGroup property available?
Check 21 - Is there a current PreviousPipelineRunsQueryRange property available?
--Batch execution checks:
Check 22 - If using batch executions, is the requested batch name enabled?
Check 23 - If using batch executions, does the requested batch have links to execution stages?
Check 24 - Have batch executions been enabled after a none batch execution run?
Check 25 - Has the execution failed due to an invalid pipeline name? If so, attend to update this before the next run.
Check 26 - Is there more than one framework orchestrator set?
Check 27 - Has a framework orchestrator been set for any orchestrators?
*/
DECLARE @BatchId UNIQUEIDENTIFIER
DECLARE @ErrorDetails VARCHAR(500)
DECLARE @MetadataIntegrityIssues TABLE
(
[CheckNumber] INT NOT NULL,
[IssuesFound] VARCHAR(MAX) NOT NULL
)
/*
Checks:
*/
--Check 1:
IF NOT EXISTS
(
SELECT 1 FROM [procfwk].[Stages] WHERE [Enabled] = 1
)
BEGIN
INSERT INTO @MetadataIntegrityIssues
VALUES
(
1,
'No execution stages are enabled within the metadatabase. Orchestrator has nothing to run.'
)
END;
--Check 2:
IF NOT EXISTS
(
SELECT 1 FROM [procfwk].[Pipelines] WHERE [Enabled] = 1
)
BEGIN
INSERT INTO @MetadataIntegrityIssues
VALUES
(
2,
'No execution pipelines are enabled within the metadatabase. Orchestrator has nothing to run.'
)
END;
--Check 3:
IF NOT EXISTS
(
SELECT 1 FROM [dbo].[ServicePrincipals]
)
BEGIN
INSERT INTO @MetadataIntegrityIssues
VALUES
(
3,
'No service principal details have been added to the metadata. Orchestrator cannot authorise pipeline executions.'
)
END;
--Check 4:
IF NOT EXISTS
(
SELECT * FROM [procfwk].[Tenants]
)
BEGIN
INSERT INTO @MetadataIntegrityIssues
VALUES
(
4,
'TenantId value is missing from the [procfwk].[Tenants] table.'
)
END;
--Check 5:
IF NOT EXISTS
(
SELECT * FROM [procfwk].[Subscriptions]
)
BEGIN
INSERT INTO @MetadataIntegrityIssues
VALUES
(
5,
'SubscriptionId value is missing from the [procfwk].[Subscriptions] table.'
)
END;
--Check 6:
IF NOT EXISTS
(
SELECT * FROM [procfwk].[CurrentProperties] WHERE [PropertyName] = 'OverideRestart'
)
BEGIN
INSERT INTO @MetadataIntegrityIssues
VALUES
(
6,
'A current OverideRestart value is missing from the properties table.'
)
END;
--Check 7:
IF EXISTS
(
SELECT
*
FROM
[procfwk].[Pipelines] p
LEFT OUTER JOIN [procfwk].[PipelineAuthLink] al
ON p.[PipelineId] = al.[PipelineId]
WHERE
p.[Enabled] = 1
AND al.[PipelineId] IS NULL
)
BEGIN
INSERT INTO @MetadataIntegrityIssues
VALUES
(
7,
'Enabled pipelines are missing a valid Service Principal link.'
)
END;
--Check 8:
IF EXISTS
(
SELECT * FROM [procfwk].[Orchestrators] WHERE [SubscriptionId] = '12345678-1234-1234-1234-012345678910'
)
BEGIN
INSERT INTO @MetadataIntegrityIssues
VALUES
(
8,
'Orchestrator still set to use the default subscription value of 12345678-1234-1234-1234-012345678910.'
)
END;
--Check 9:
IF EXISTS
(
SELECT * FROM [procfwk].[Subscriptions] WHERE [TenantId] = '12345678-1234-1234-1234-012345678910' AND [SubscriptionId] <> '12345678-1234-1234-1234-012345678910'
)
BEGIN
INSERT INTO @MetadataIntegrityIssues
VALUES
(
9,
'None default subscription still set to use the default tenant value of 12345678-1234-1234-1234-012345678910.'
)
END;
--Check 10:
IF NOT EXISTS
(
SELECT * FROM [procfwk].[CurrentProperties] WHERE [PropertyName] = 'PipelineStatusCheckDuration'
)
BEGIN
INSERT INTO @MetadataIntegrityIssues
VALUES
(
10,
'A current PipelineStatusCheckDuration value is missing from the properties table.'
)
END;
--Check 11:
IF NOT EXISTS
(
SELECT * FROM [procfwk].[CurrentProperties] WHERE [PropertyName] = 'UseFrameworkEmailAlerting'
)
BEGIN
INSERT INTO @MetadataIntegrityIssues
VALUES
(
11,
'A current UseFrameworkEmailAlerting value is missing from the properties table.'
)
END;
--Check 12:
IF (
SELECT
[PropertyValue]
FROM
[procfwk].[CurrentProperties]
WHERE
[PropertyName] = 'UseFrameworkEmailAlerting'
) = 1
BEGIN
IF NOT EXISTS
(
SELECT * FROM [procfwk].[CurrentProperties] WHERE [PropertyName] = 'EmailAlertBodyTemplate'
)
BEGIN
INSERT INTO @MetadataIntegrityIssues
VALUES
(
12,
'A current EmailAlertBodyTemplate value is missing from the properties table.'
)
END;
END;
--Check 13:
IF EXISTS
(
SELECT * FROM [procfwk].[PipelineParameterDataSizes] WHERE [Size] > 9
/*
Azure Function request limit is 10MB.
https://docs.microsoft.com/en-us/azure/azure-functions/functions-scale
9MB to allow for other content in execute pipeline body request.
*/
)
BEGIN
INSERT INTO @MetadataIntegrityIssues
VALUES
(
13,
'The pipeline parameters entered exceed the Azure Function request body maximum of 10MB. Query view [procfwk].[PipelineParameterDataSizes] for details.'
)
END;
--Check 14:
IF NOT EXISTS
(
SELECT * FROM [procfwk].[CurrentProperties] WHERE [PropertyName] = 'FailureHandling'
)
BEGIN
INSERT INTO @MetadataIntegrityIssues
VALUES
(
14,
'A current FailureHandling value is missing from the properties table.'
)
END;
--Check 15:
IF NOT EXISTS
(
SELECT
*
FROM
[procfwk].[CurrentProperties]
WHERE
[PropertyName] = 'FailureHandling'
AND [PropertyValue] IN ('None','Simple','DependencyChain')
)
BEGIN
INSERT INTO @MetadataIntegrityIssues
VALUES
(
15,
'The property FailureHandling does not have a supported value.'
)
END;
--Check 16:
IF ([procfwk].[GetPropertyValueInternal]('FailureHandling')) = 'DependencyChain'
BEGIN
IF EXISTS
(
SELECT
pd.[DependencyId]
FROM
[procfwk].[PipelineDependencies] pd
INNER JOIN [procfwk].[Pipelines] pp
ON pd.[PipelineId] = pp.[PipelineId]
INNER JOIN [procfwk].[Pipelines] dp
ON pd.[DependantPipelineId] = dp.[PipelineId]
WHERE
pp.[StageId] = dp.[StageId]
)
BEGIN
INSERT INTO @MetadataIntegrityIssues
VALUES
(
16,
'A dependant pipeline and its upstream predecessor exist in the same execution stage. Fix this dependency chain to allow correct failure handling.'
)
END;
END;
--Check 17:
IF NOT EXISTS
(
SELECT
*
FROM
[procfwk].[CurrentProperties]
WHERE
[PropertyName] = 'SPNHandlingMethod'
AND [PropertyValue] IN ('StoreInDatabase','StoreInKeyVault')
)
BEGIN
INSERT INTO @MetadataIntegrityIssues
VALUES
(
17,
'The property SPNHandlingMethod does not have a supported value.'
)
END;
--Check 18:
IF EXISTS
(
SELECT
*
FROM
[dbo].[ServicePrincipals]
WHERE
(
[PrincipalId] IS NOT NULL
OR [PrincipalSecret] IS NOT NULL
)
AND
(
[PrincipalIdUrl] IS NOT NULL
OR [PrincipalSecretUrl] IS NOT NULL
)
)
BEGIN
INSERT INTO @MetadataIntegrityIssues
VALUES
(
18,
'The table [dbo].[ServicePrincipals] can only have one method of SPN details sorted per credential ID.'
)
END;
--Check 19:
IF NOT EXISTS
(
SELECT * FROM [procfwk].[CurrentProperties] WHERE [PropertyName] = 'UseExecutionBatches'
)
BEGIN
INSERT INTO @MetadataIntegrityIssues
VALUES
(
19,
'A current UseExecutionBatches value is missing from the properties table.'
)
END;
--Check 20:
IF NOT EXISTS
(
SELECT * FROM [procfwk].[CurrentProperties] WHERE [PropertyName] = 'FrameworkFactoryResourceGroup'
)
BEGIN
INSERT INTO @MetadataIntegrityIssues
VALUES
(
20,
'A current FrameworkFactoryResourceGroup value is missing from the properties table.'
)
END;
--Check 21:
IF NOT EXISTS
(
SELECT * FROM [procfwk].[CurrentProperties] WHERE [PropertyName] = 'PreviousPipelineRunsQueryRange'
)
BEGIN
INSERT INTO @MetadataIntegrityIssues
VALUES
(
21,
'A current PreviousPipelineRunsQueryRange value is missing from the properties table.'
)
END;
--batch execution checks
IF ([procfwk].[GetPropertyValueInternal]('UseExecutionBatches')) = '1'
BEGIN
IF @BatchName IS NULL
BEGIN
RAISERROR('A NULL batch name cannot be passed when the UseExecutionBatches property is set to 1 (true).',16,1);
RETURN 0;
END
SELECT
@BatchId = [BatchId]
FROM
[procfwk].[Batches]
WHERE
[BatchName] = @BatchName;
--Check 22:
IF EXISTS
(
SELECT 1 FROM [procfwk].[Batches] WHERE [BatchId] = @BatchId AND [Enabled] = 0
)
BEGIN
INSERT INTO @MetadataIntegrityIssues
VALUES
(
22,
'The requested execution batch is currently disabled. Enable the batch before proceeding.'
)
END;
--Check 23:
IF NOT EXISTS
(
SELECT 1 FROM [procfwk].[BatchStageLink] WHERE [BatchId] = @BatchId
)
BEGIN
INSERT INTO @MetadataIntegrityIssues
VALUES
(
23,
'The requested execution batch does not have any linked execution stages. See table [procfwk].[BatchStageLink] for details.'
)
END;
--Check 24:
IF EXISTS
(
SELECT
*
FROM
[procfwk].[CurrentExecution] c
LEFT OUTER JOIN [procfwk].[BatchExecution] b
ON c.[LocalExecutionId] = b.[ExecutionId]
WHERE
b.[ExecutionId] IS NULL
)
BEGIN
INSERT INTO @MetadataIntegrityIssues
VALUES
(
24,
'Execution records exist in the [procfwk].[CurrentExecution] table that do not have a record in [procfwk].[BatchExecution] table. Has batch excutions been enabed after an incomplete none batch run?'
)
END;
END; --end batch checks
--Check 25:
IF EXISTS
(
SELECT 1 FROM [procfwk].[CurrentExecution] WHERE [PipelineStatus] = 'InvalidPipelineNameError'
)
BEGIN
UPDATE
ce
SET
ce.[PipelineName] = p.[PipelineName]
FROM
[procfwk].[CurrentExecution] ce
INNER JOIN [procfwk].[Pipelines] p
ON ce.[PipelineId] = p.[PipelineId]
AND ce.[StageId] = p.[StageId]
WHERE
ce.[PipelineStatus] = 'InvalidPipelineNameError'
END;
--Check 26:
IF (SELECT COUNT(0) FROM [procfwk].[Orchestrators] WHERE [IsFrameworkOrchestrator] = 1) > 1
BEGIN
INSERT INTO @MetadataIntegrityIssues
VALUES
(
26,
'There is more than one FrameworkOrchestrator set in the table [procfwk].[Orchestrators]. Only one is supported.'
)
END
--Check 27:
IF NOT EXISTS
(
SELECT 1 FROM [procfwk].[Orchestrators] WHERE [IsFrameworkOrchestrator] = 1
)
BEGIN
INSERT INTO @MetadataIntegrityIssues
VALUES
(
27,
'A FrameworkOrchestrator has not been set in the table [procfwk].[Orchestrators]. Only one is supported.'
)
END
/*
Integrity Checks Outcome:
*/
--throw runtime error if checks fail
IF EXISTS
(
SELECT * FROM @MetadataIntegrityIssues
)
AND @DebugMode = 0
BEGIN
SET @ErrorDetails = 'Metadata integrity checks failed. Run EXEC [procfwk].[CheckMetadataIntegrity] @DebugMode = 1; for details.'
RAISERROR(@ErrorDetails, 16, 1);
RETURN 0;
END;
--report issues when in debug mode
IF @DebugMode = 1
BEGIN
IF NOT EXISTS
(
SELECT * FROM @MetadataIntegrityIssues
)
BEGIN
PRINT 'No data integrity issues found in metadata.'
RETURN 0;
END
ELSE
BEGIN
SELECT * FROM @MetadataIntegrityIssues;
END;
END;
END;
================================================
FILE: MetadataDB/procfwk/Stored Procedures/CheckPreviousExeuction.sql
================================================
CREATE PROCEDURE [procfwk].[CheckPreviousExeuction]
(
@BatchName VARCHAR(255) = NULL
)
AS
BEGIN
SET NOCOUNT ON;
/*
Check A: - Are there any Running pipelines that need to be cleaned up?
*/
DECLARE @BatchId UNIQUEIDENTIFIER
DECLARE @LocalExecutionId UNIQUEIDENTIFIER
--Check A:
IF ([procfwk].[GetPropertyValueInternal]('UseExecutionBatches')) = '0'
BEGIN
IF EXISTS
(
SELECT
1
FROM
[procfwk].[CurrentExecution]
WHERE
[PipelineStatus] NOT IN ('Success','Failed','Blocked', 'Cancelled')
AND [PipelineRunId] IS NOT NULL
)
BEGIN
--return pipelines details that require a clean up
SELECT
[ResourceGroupName],
[OrchestratorType],
[OrchestratorName],
[PipelineName],
[PipelineRunId],
[LocalExecutionId],
[StageId],
[PipelineId]
FROM
[procfwk].[CurrentExecution]
WHERE
[PipelineStatus] NOT IN ('Success','Failed','Blocked','Cancelled')
AND [PipelineRunId] IS NOT NULL
END;
ELSE
GOTO LookUpReturnEmptyResult;
END
ELSE IF ([procfwk].[GetPropertyValueInternal]('UseExecutionBatches')) = '1'
BEGIN
IF @BatchName IS NULL
BEGIN
RAISERROR('A NULL batch name cannot be passed when the UseExecutionBatches property is set to 1 (true).',16,1);
RETURN 0;
END
IF EXISTS
(
SELECT
1
FROM
[procfwk].[CurrentExecution] ce
INNER JOIN [procfwk].[BatchExecution] be
ON ce.[LocalExecutionId] = be.[ExecutionId]
INNER JOIN [procfwk].[Batches] b
ON be.[BatchId] = b.[BatchId]
WHERE
b.[BatchName] = @BatchName
AND ce.[PipelineStatus] NOT IN ('Success','Failed','Blocked','Cancelled')
AND ce.[PipelineRunId] IS NOT NULL
)
BEGIN
--return pipelines details that require a clean up
SELECT
ce.[ResourceGroupName],
ce.[OrchestratorType],
ce.[OrchestratorName],
ce.[PipelineName],
ce.[PipelineRunId],
ce.[LocalExecutionId],
ce.[StageId],
ce.[PipelineId]
FROM
[procfwk].[CurrentExecution] ce
INNER JOIN [procfwk].[BatchExecution] be
ON ce.[LocalExecutionId] = be.[ExecutionId]
INNER JOIN [procfwk].[Batches] b
ON be.[BatchId] = b.[BatchId]
WHERE
b.[BatchName] = @BatchName
AND ce.[PipelineStatus] NOT IN ('Success','Failed','Blocked','Cancelled')
AND ce.[PipelineRunId] IS NOT NULL
END;
ELSE
GOTO LookUpReturnEmptyResult;
END
LookUpReturnEmptyResult:
--lookup activity must return something, even if just an empty dataset
SELECT
NULL AS ResourceGroupName,
NULL AS OrchestratorType,
NULL AS OrchestratorName,
NULL AS PipelineName,
NULL AS PipelineRunId,
NULL AS LocalExecutionId,
NULL AS StageId,
NULL AS PipelineId
FROM
[procfwk].[CurrentExecution]
WHERE
1 = 2; --ensure no results
END;
================================================
FILE: MetadataDB/procfwk/Stored Procedures/CreateNewExecution.sql
================================================
CREATE PROCEDURE [procfwk].[CreateNewExecution]
(
@CallingOrchestratorName NVARCHAR(200),
@LocalExecutionId UNIQUEIDENTIFIER = NULL
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @BatchId UNIQUEIDENTIFIER;
IF([procfwk].[GetPropertyValueInternal]('UseExecutionBatches')) = '0'
BEGIN
SET @LocalExecutionId = NEWID();
TRUNCATE TABLE [procfwk].[CurrentExecution];
--defensive check
IF NOT EXISTS
(
SELECT
1
FROM
[procfwk].[Pipelines] p
INNER JOIN [procfwk].[Stages] s
ON p.[StageId] = s.[StageId]
INNER JOIN [procfwk].[Orchestrators] d
ON p.[OrchestratorId] = d.[OrchestratorId]
WHERE
p.[Enabled] = 1
AND s.[Enabled] = 1
)
BEGIN
RAISERROR('Requested execution run does not contain any enabled stages/pipelines.',16,1);
RETURN 0;
END;
INSERT INTO [procfwk].[CurrentExecution]
(
[LocalExecutionId],
[StageId],
[PipelineId],
[CallingOrchestratorName],
[ResourceGroupName],
[OrchestratorType],
[OrchestratorName],
[PipelineName]
)
SELECT
@LocalExecutionId,
p.[StageId],
p.[PipelineId],
@CallingOrchestratorName,
d.[ResourceGroupName],
d.[OrchestratorType],
d.[OrchestratorName],
p.[PipelineName]
FROM
[procfwk].[Pipelines] p
INNER JOIN [procfwk].[Stages] s
ON p.[StageId] = s.[StageId]
INNER JOIN [procfwk].[Orchestrators] d
ON p.[OrchestratorId] = d.[OrchestratorId]
WHERE
p.[Enabled] = 1
AND s.[Enabled] = 1;
SELECT
@LocalExecutionId AS ExecutionId;
END
ELSE IF ([procfwk].[GetPropertyValueInternal]('UseExecutionBatches')) = '1'
BEGIN
DELETE FROM
[procfwk].[CurrentExecution]
WHERE
[LocalExecutionId] = @LocalExecutionId;
SELECT
@BatchId = [BatchId]
FROM
[procfwk].[BatchExecution]
WHERE
[ExecutionId] = @LocalExecutionId;
--defensive check
IF NOT EXISTS
(
SELECT
1
FROM
[procfwk].[Pipelines] p
INNER JOIN [procfwk].[Stages] s
ON p.[StageId] = s.[StageId]
INNER JOIN [procfwk].[Orchestrators] d
ON p.[OrchestratorId] = d.[OrchestratorId]
INNER JOIN [procfwk].[BatchStageLink] b
ON b.[StageId] = s.[StageId]
WHERE
b.[BatchId] = @BatchId
AND p.[Enabled] = 1
AND s.[Enabled] = 1
)
BEGIN
RAISERROR('Requested execution run does not contain any enabled stages/pipelines.',16,1);
RETURN 0;
END;
INSERT INTO [procfwk].[CurrentExecution]
(
[LocalExecutionId],
[StageId],
[PipelineId],
[CallingOrchestratorName],
[ResourceGroupName],
[OrchestratorType],
[OrchestratorName],
[PipelineName]
)
SELECT
@LocalExecutionId,
p.[StageId],
p.[PipelineId],
@CallingOrchestratorName,
d.[ResourceGroupName],
d.[OrchestratorType],
d.[OrchestratorName],
p.[PipelineName]
FROM
[procfwk].[Pipelines] p
INNER JOIN [procfwk].[Stages] s
ON p.[StageId] = s.[StageId]
INNER JOIN [procfwk].[Orchestrators] d
ON p.[OrchestratorId] = d.[OrchestratorId]
INNER JOIN [procfwk].[BatchStageLink] b
ON b.[StageId] = s.[StageId]
WHERE
b.[BatchId] = @BatchId
AND p.[Enabled] = 1
AND s.[Enabled] = 1;
SELECT
@LocalExecutionId AS ExecutionId;
END;
ALTER INDEX [IDX_GetPipelinesInStage] ON [procfwk].[CurrentExecution]
REBUILD;
END;
================================================
FILE: MetadataDB/procfwk/Stored Procedures/ExecutePrecursorProcedure.sql
================================================
CREATE PROCEDURE [procfwk].[ExecutePrecursorProcedure]
AS
BEGIN
DECLARE @SQL VARCHAR(MAX)
DECLARE @ErrorDetail NVARCHAR(MAX)
IF OBJECT_ID([procfwk].[GetPropertyValueInternal]('ExecutionPrecursorProc')) IS NOT NULL
BEGIN
BEGIN TRY
SET @SQL = [procfwk].[GetPropertyValueInternal]('ExecutionPrecursorProc');
EXEC(@SQL);
END TRY
BEGIN CATCH
SELECT
@ErrorDetail = 'Precursor procedure failed with error: ' + ERROR_MESSAGE();
RAISERROR(@ErrorDetail,16,1);
END CATCH
END;
ELSE
BEGIN
PRINT 'Precursor object not found in database.';
END;
END;
================================================
FILE: MetadataDB/procfwk/Stored Procedures/ExecutionWrapper.sql
================================================
CREATE PROCEDURE [procfwk].[ExecutionWrapper]
(
@CallingOrchestratorName NVARCHAR(200) = NULL,
@BatchName VARCHAR(255) = NULL
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @RestartStatus BIT
DECLARE @BatchId UNIQUEIDENTIFIER
DECLARE @BLocalExecutionId UNIQUEIDENTIFIER --declared here for batches
IF @CallingOrchestratorName IS NULL
SET @CallingOrchestratorName = 'Unknown';
--get restart overide property
SELECT @RestartStatus = [procfwk].[GetPropertyValueInternal]('OverideRestart')
IF([procfwk].[GetPropertyValueInternal]('UseExecutionBatches')) = '0'
BEGIN
SET @BatchId = NULL;
--check for running execution
IF EXISTS
(
SELECT * FROM [procfwk].[CurrentExecution] WHERE ISNULL([PipelineStatus],'') = 'Running'
)
BEGIN
RAISERROR('There is already an execution run in progress. Stop this via the Orchestrator before restarting.',16,1);
RETURN 0;
END;
--reset and restart execution
IF EXISTS
(
SELECT 1 FROM [procfwk].[CurrentExecution] WHERE ISNULL([PipelineStatus],'') <> 'Success'
)
AND @RestartStatus = 0
BEGIN
EXEC [procfwk].[ResetExecution]
END
--capture failed execution and run new anyway
ELSE IF EXISTS
(
SELECT 1 FROM [procfwk].[CurrentExecution]
)
AND @RestartStatus = 1
BEGIN
EXEC [procfwk].[UpdateExecutionLog]
@PerformErrorCheck = 0; --Special case when OverideRestart = 1;
EXEC [procfwk].[CreateNewExecution]
@CallingOrchestratorName = @CallingOrchestratorName
END
--no restart considerations, just create new execution
ELSE
BEGIN
EXEC [procfwk].[CreateNewExecution]
@CallingOrchestratorName = @CallingOrchestratorName
END
END
ELSE IF ([procfwk].[GetPropertyValueInternal]('UseExecutionBatches')) = '1'
BEGIN
IF @BatchName IS NULL
BEGIN
RAISERROR('A NULL batch name cannot be passed when the UseExecutionBatches property is set to 1 (true).',16,1);
RETURN 0;
END;
SELECT
@BatchId = [BatchId]
FROM
[procfwk].[Batches]
WHERE
[BatchName] = @BatchName;
--create local execution id now for the batch
EXEC [procfwk].[BatchWrapper]
@BatchId = @BatchId,
@LocalExecutionId = @BLocalExecutionId OUTPUT;
--reset and restart execution
IF EXISTS
(
SELECT 1
FROM
[procfwk].[CurrentExecution]
WHERE
[LocalExecutionId] = @BLocalExecutionId
AND ISNULL([PipelineStatus],'') <> 'Success'
)
AND @RestartStatus = 0
BEGIN
EXEC [procfwk].[ResetExecution]
@LocalExecutionId = @BLocalExecutionId;
END
--capture failed execution and run new anyway
ELSE IF EXISTS
(
SELECT 1
FROM
[procfwk].[CurrentExecution]
WHERE
[LocalExecutionId] = @BLocalExecutionId
)
AND @RestartStatus = 1
BEGIN
EXEC [procfwk].[UpdateExecutionLog]
@PerformErrorCheck = 0, --Special case when OverideRestart = 1;
@ExecutionId = @BLocalExecutionId;
EXEC [procfwk].[CreateNewExecution]
@CallingOrchestratorName = @CallingOrchestratorName,
@LocalExecutionId = @BLocalExecutionId;
END
--no restart considerations, just create new execution
ELSE
BEGIN
EXEC [procfwk].[CreateNewExecution]
@CallingOrchestratorName = @CallingOrchestratorName,
@LocalExecutionId = @BLocalExecutionId;
END
END
ELSE
BEGIN
--metadata integrity checks should mean this condition is never hit
RAISERROR('Unknown batch handling configuration. Update properties with UseExecutionBatches value and try again.',16,1);
RETURN 0;
END
END;
================================================
FILE: MetadataDB/procfwk/Stored Procedures/GetEmailAlertParts.sql
================================================
CREATE PROCEDURE [procfwk].[GetEmailAlertParts]
(
@PipelineId INT
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @ToRecipients NVARCHAR(MAX) = ''
DECLARE @CcRecipients NVARCHAR(MAX) = ''
DECLARE @BccRecipients NVARCHAR(MAX) = ''
DECLARE @EmailSubject NVARCHAR(500)
DECLARE @EmailBody NVARCHAR(MAX)
DECLARE @EmailImportance VARCHAR(5)
DECLARE @OutcomeBitValue INT
--map pipeline status to alert outcome bit value
SELECT
@OutcomeBitValue = ao.[BitValue]
FROM
[procfwk].[CurrentExecution] ce
INNER JOIN [procfwk].[AlertOutcomes] ao
ON ce.[PipelineStatus] = ao.[PipelineOutcomeStatus]
WHERE
ce.[PipelineId] = @PipelineId;
--get to recipients
SELECT
@ToRecipients += r.[EmailAddress] + ','
FROM
[procfwk].[PipelineAlertLink] al
INNER JOIN [procfwk].[Recipients] r
ON al.[RecipientId] = r.[RecipientId]
WHERE
al.[PipelineId] = @PipelineId
AND al.[Enabled] = 1
AND r.[Enabled] = 1
AND UPPER(r.[MessagePreference]) = 'TO'
AND (
al.[OutcomesBitValue] & @OutcomeBitValue <> 0
OR al.[OutcomesBitValue] & 1 <> 0 --all
);
IF (@ToRecipients <> '') SET @ToRecipients = LEFT(@ToRecipients,LEN(@ToRecipients)-1);
--get cc recipients
SELECT
@CcRecipients += r.[EmailAddress] + ','
FROM
[procfwk].[PipelineAlertLink] al
INNER JOIN [procfwk].[Recipients] r
ON al.[RecipientId] = r.[RecipientId]
WHERE
al.[PipelineId] = @PipelineId
AND al.[Enabled] = 1
AND r.[Enabled] = 1
AND UPPER(r.[MessagePreference]) = 'CC'
AND (
al.[OutcomesBitValue] & @OutcomeBitValue <> 0
OR al.[OutcomesBitValue] & 1 <> 0 --all
);
IF (@CcRecipients <> '') SET @CcRecipients = LEFT(@CcRecipients,LEN(@CcRecipients)-1);
--get bcc recipients
SELECT
@BccRecipients += r.[EmailAddress] + ','
FROM
[procfwk].[PipelineAlertLink] al
INNER JOIN [procfwk].[Recipients] r
ON al.[RecipientId] = r.[RecipientId]
WHERE
al.[PipelineId] = @PipelineId
AND al.[Enabled] = 1
AND r.[Enabled] = 1
AND UPPER(r.[MessagePreference]) = 'BCC'
AND (
al.[OutcomesBitValue] & @OutcomeBitValue <> 0
OR al.[OutcomesBitValue] & 1 <> 0 --all
);
IF (@BccRecipients <> '') SET @BccRecipients = LEFT(@BccRecipients,LEN(@BccRecipients)-1);
--get email template
SELECT
@EmailBody = [PropertyValue]
FROM
[procfwk].[CurrentProperties]
WHERE
[PropertyName] = 'EmailAlertBodyTemplate';
--set subject, body and importance
SELECT TOP (1)
--subject
@EmailSubject = 'ProcFwk Alert: ' + [PipelineName] + ' - ' + [PipelineStatus],
--body
@EmailBody = REPLACE(@EmailBody,'##PipelineName###',[PipelineName]),
@EmailBody = REPLACE(@EmailBody,'##Status###',[PipelineStatus]),
@EmailBody = REPLACE(@EmailBody,'##ExecId###',CAST([LocalExecutionId] AS VARCHAR(36))),
@EmailBody = REPLACE(@EmailBody,'##RunId###',CAST([PipelineRunId] AS VARCHAR(36))),
@EmailBody = REPLACE(@EmailBody,'##StartDateTime###',CONVERT(VARCHAR(30), [StartDateTime], 120)),
@EmailBody = CASE
WHEN [EndDateTime] IS NULL THEN REPLACE(@EmailBody,'##EndDateTime###','N/A')
ELSE REPLACE(@EmailBody,'##EndDateTime###',CONVERT(VARCHAR(30), [EndDateTime], 120))
END,
@EmailBody = CASE
WHEN [EndDateTime] IS NULL THEN REPLACE(@EmailBody,'##Duration###','N/A')
ELSE REPLACE(@EmailBody,'##Duration###',CAST(DATEDIFF(MINUTE, [StartDateTime], [EndDateTime]) AS VARCHAR(30)))
END,
@EmailBody = REPLACE(@EmailBody,'##CalledByOrc###',[CallingOrchestratorName]),
@EmailBody = REPLACE(@EmailBody,'##ExecutedByOrcType###',[OrchestratorType]),
@EmailBody = REPLACE(@EmailBody,'##ExecutedByOrc###',[OrchestratorName]),
--importance
@EmailImportance =
CASE [PipelineStatus]
WHEN 'Success' THEN 'Low'
WHEN 'Failed' THEN 'High'
ELSE 'Normal'
END
FROM
[procfwk].[CurrentExecution]
WHERE
[PipelineId] = @PipelineId
ORDER BY
[StartDateTime] DESC;
--precaution
IF @EmailBody IS NULL
SET @EmailBody = 'Internal error. Failed to create profwk email alert body. Execute procedure [procfwk].[GetEmailAlertParts] with pipeline Id: ' + CAST(@PipelineId AS VARCHAR(30)) + ' to debug.';
--return email parts
SELECT
@ToRecipients AS emailRecipients,
@CcRecipients AS emailCcRecipients,
@BccRecipients AS emailBccRecipients,
@EmailSubject AS emailSubject,
@EmailBody AS emailBody,
@EmailImportance AS emailImportance;
END;
================================================
FILE: MetadataDB/procfwk/Stored Procedures/GetFrameworkOrchestratorDetails.sql
================================================
CREATE PROCEDURE [procfwk].[GetFrameworkOrchestratorDetails]
(
@CallingOrchestratorName NVARCHAR(200)
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @FrameworkOrchestrator NVARCHAR(200)
--defensive check
SELECT
@FrameworkOrchestrator = UPPER([OrchestratorName]),
@CallingOrchestratorName = UPPER(@CallingOrchestratorName)
FROM
[procfwk].[Orchestrators]
WHERE
[IsFrameworkOrchestrator] = 1;
IF(@FrameworkOrchestrator <> @CallingOrchestratorName)
BEGIN
RAISERROR('Orchestrator mismatch. Calling orchestrator does not match expected IsFrameworkOrchestrator name.',16,1);
RETURN 0;
END
--orchestrator detials
SELECT
[SubscriptionId],
[ResourceGroupName],
[OrchestratorName],
[OrchestratorType]
FROM
[procfwk].[Orchestrators]
WHERE
[IsFrameworkOrchestrator] = 1;
END;
================================================
FILE: MetadataDB/procfwk/Stored Procedures/GetPipelineParameters.sql
================================================
CREATE PROCEDURE [procfwk].[GetPipelineParameters]
(
@PipelineId INT
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @Json VARCHAR(MAX) = ''
--get parameters if required for worker pipeline
IF NOT EXISTS
(
SELECT
[ParameterId]
FROM
[procfwk].[PipelineParameters]
WHERE
[PipelineId] = @PipelineId
)
BEGIN
SET @Json = '' --Can't return NULL. Would break ADF expression.
END
ELSE
BEGIN
SELECT
@Json +=
CASE
WHEN [ParameterValue] IS NULL THEN '' --don't add pair so ADF uses default
ELSE '"' + [ParameterName] + '": "' + STRING_ESCAPE([ParameterValue],'json') + '",'
END
FROM
[procfwk].[PipelineParameters]
WHERE
[PipelineId] = @PipelineId;
--handle parameter(s) with a NULL values
IF LEN(@Json) > 0
BEGIN
--JSON snippet gets injected into Azure Function body request via Orchestrator expressions.
--Comma used to support Orchestrator expression.
SET @Json = ',"pipelineParameters": {' + LEFT(@Json,LEN(@Json)-1) + '}'
--update current execution log if this is a runtime request
UPDATE
[procfwk].[CurrentExecution]
SET
--add extra braces to make JSON string valid in logs
[PipelineParamsUsed] = '{ ' + RIGHT(@Json,LEN(@Json)-1) + ' }'
WHERE
[PipelineId] = @PipelineId;
--set last values values
UPDATE
[procfwk].[PipelineParameters]
SET
[ParameterValueLastUsed] = [ParameterValue]
WHERE
[PipelineId] = @PipelineId;
END;
END;
--return JSON snippet
SELECT @Json AS Params
END;
================================================
FILE: MetadataDB/procfwk/Stored Procedures/GetPipelinesInStage.sql
================================================
CREATE PROCEDURE [procfwk].[GetPipelinesInStage]
(
@ExecutionId UNIQUEIDENTIFIER,
@StageId INT
)
AS
BEGIN
SET NOCOUNT ON;
SELECT
[PipelineId]
FROM
[procfwk].[CurrentExecution]
WHERE
[LocalExecutionId] = @ExecutionId
AND [StageId] = @StageId
AND ISNULL([PipelineStatus],'') <> 'Success'
AND [IsBlocked] <> 1
ORDER BY
[PipelineId] ASC;
END;
================================================
FILE: MetadataDB/procfwk/Stored Procedures/GetPropertyValue.sql
================================================
CREATE PROCEDURE [procfwk].[GetPropertyValue]
(
@PropertyName VARCHAR(128)
)
AS
BEGIN
DECLARE @ErrorDetail NVARCHAR(4000) = ''
--defensive checks
IF NOT EXISTS
(
SELECT * FROM [procfwk].[Properties] WHERE [PropertyName] = @PropertyName
)
BEGIN
SET @ErrorDetail = 'Invalid property name provided. Property does not exist.'
RAISERROR(@ErrorDetail, 16, 1);
RETURN 0;
END
ELSE IF NOT EXISTS
(
SELECT * FROM [procfwk].[Properties] WHERE [PropertyName] = @PropertyName AND [ValidTo] IS NULL
)
BEGIN
SET @ErrorDetail = 'Property name provided does not have a current valid version of the required value.'
RAISERROR(@ErrorDetail, 16, 1);
RETURN 0;
END
--get valid property value
ELSE
BEGIN
SELECT
[PropertyValue]
FROM
[procfwk].[CurrentProperties]
WHERE
[PropertyName] = @PropertyName
END
END;
================================================
FILE: MetadataDB/procfwk/Stored Procedures/GetStages.sql
================================================
CREATE PROCEDURE [procfwk].[GetStages]
(
@ExecutionId UNIQUEIDENTIFIER
)
AS
BEGIN
SET NOCOUNT ON;
--defensive check
IF NOT EXISTS
(
SELECT
1
FROM
[procfwk].[CurrentExecution]
WHERE
[LocalExecutionId] = @ExecutionId
AND ISNULL([PipelineStatus],'') <> 'Success'
)
BEGIN
RAISERROR('Requested execution run does not contain any enabled stages/pipelines.',16,1);
RETURN 0;
END;
SELECT DISTINCT
[StageId]
FROM
[procfwk].[CurrentExecution]
WHERE
[LocalExecutionId] = @ExecutionId
AND ISNULL([PipelineStatus],'') <> 'Success'
ORDER BY
[StageId] ASC
END;
================================================
FILE: MetadataDB/procfwk/Stored Procedures/GetWorkerAuthDetails.sql
================================================
CREATE PROCEDURE [procfwk].[GetWorkerAuthDetails]
(
@ExecutionId UNIQUEIDENTIFIER,
@StageId INT,
@PipelineId INT
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @TenId NVARCHAR(MAX)
DECLARE @SubId NVARCHAR(MAX)
DECLARE @AppId NVARCHAR(MAX)
DECLARE @AppSecret NVARCHAR(MAX)
DECLARE @OrchestratorName NVARCHAR(200)
DECLARE @OrchestratorType CHAR(3)
DECLARE @PipelineName NVARCHAR(200)
SELECT
@PipelineName = [PipelineName],
@OrchestratorName = [OrchestratorName],
@OrchestratorType = [OrchestratorType]
FROM
[procfwk].[CurrentExecution]
WHERE
[LocalExecutionId] = @ExecutionId
AND [StageId] = @StageId
AND [PipelineId] = @PipelineId;
IF ([procfwk].[GetPropertyValueInternal]('SPNHandlingMethod')) = 'StoreInDatabase'
BEGIN
--get auth details regardless of being pipeline specific and regardless of a pipeline param being passed
;WITH cte AS
(
SELECT DISTINCT
Sub.[TenantId],
Sub.[SubscriptionId],
S.[PrincipalId] AS AppId,
CAST(DECRYPTBYPASSPHRASE(CONCAT(@OrchestratorName, @OrchestratorType, @PipelineName), S.[PrincipalSecret]) AS NVARCHAR(MAX)) AS AppSecret
FROM
[dbo].[ServicePrincipals] S
INNER JOIN [procfwk].[PipelineAuthLink] L
ON S.[CredentialId] = L.[CredentialId]
INNER JOIN [procfwk].[Pipelines] P
ON L.[PipelineId] = P.[PipelineId]
INNER JOIN [procfwk].[Orchestrators] D
ON P.[OrchestratorId] = D.[OrchestratorId]
AND L.[OrchestratorId] = D.[OrchestratorId]
INNER JOIN [procfwk].[Subscriptions] Sub
ON D.[SubscriptionId] = Sub.[SubscriptionId]
WHERE
P.[PipelineName] = @PipelineName
AND D.[OrchestratorName] = @OrchestratorName
AND D.[OrchestratorType] = @OrchestratorType
UNION
SELECT DISTINCT
Sub.[TenantId],
Sub.[SubscriptionId],
S.[PrincipalId] AS AppId,
CAST(DECRYPTBYPASSPHRASE(CONCAT(@OrchestratorName, @OrchestratorType), S.[PrincipalSecret]) AS NVARCHAR(MAX)) AS AppSecret
FROM
[dbo].[ServicePrincipals] S
INNER JOIN [procfwk].[PipelineAuthLink] L
ON S.[CredentialId] = L.[CredentialId]
INNER JOIN [procfwk].[Orchestrators] D
ON L.[OrchestratorId] = D.[OrchestratorId]
INNER JOIN [procfwk].[Subscriptions] Sub
ON D.[SubscriptionId] = Sub.[SubscriptionId]
WHERE
D.[OrchestratorName] = @OrchestratorName
AND D.[OrchestratorType] = @OrchestratorType
)
SELECT TOP 1
@TenId = [TenantId],
@SubId = [SubscriptionId],
@AppId = [AppId],
@AppSecret = [AppSecret]
FROM
cte
WHERE
[AppSecret] IS NOT NULL
END
ELSE IF ([procfwk].[GetPropertyValueInternal]('SPNHandlingMethod')) = 'StoreInKeyVault'
BEGIN
--get auth details regardless of being pipeline specific and regardless of a pipeline param being passed
;WITH cte AS
(
SELECT DISTINCT
Sub.[TenantId],
Sub.[SubscriptionId],
S.[PrincipalIdUrl] AS AppId,
S.[PrincipalSecretUrl] AS AppSecret
FROM
[dbo].[ServicePrincipals] S
INNER JOIN [procfwk].[PipelineAuthLink] L
ON S.[CredentialId] = L.[CredentialId]
INNER JOIN [procfwk].[Pipelines] P
ON L.[PipelineId] = P.[PipelineId]
INNER JOIN [procfwk].[Orchestrators] D
ON P.[OrchestratorId] = D.[OrchestratorId]
AND L.[OrchestratorId] = D.[OrchestratorId]
INNER JOIN [procfwk].[Subscriptions] Sub
ON D.[SubscriptionId] = Sub.[SubscriptionId]
WHERE
P.[PipelineName] = @PipelineName
AND D.[OrchestratorName] = @OrchestratorName
AND D.[OrchestratorType] = @OrchestratorType
UNION
SELECT DISTINCT
Sub.[TenantId],
Sub.[SubscriptionId],
S.[PrincipalIdUrl] AS AppId,
S.[PrincipalSecretUrl] AS AppSecret
FROM
[dbo].[ServicePrincipals] S
INNER JOIN [procfwk].[PipelineAuthLink] L
ON S.[CredentialId] = L.[CredentialId]
INNER JOIN [procfwk].[Orchestrators] D
ON L.[OrchestratorId] = D.[OrchestratorId]
INNER JOIN [procfwk].[Subscriptions] Sub
ON D.[SubscriptionId] = Sub.[SubscriptionId]
WHERE
D.[OrchestratorName] = @OrchestratorName
AND D.[OrchestratorType] = @OrchestratorType
)
SELECT TOP 1
@TenId = [TenantId],
@SubId = [SubscriptionId],
@AppId = [AppId],
@AppSecret = [AppSecret]
FROM
cte
WHERE
[AppSecret] IS NOT NULL
END
ELSE
BEGIN
RAISERROR('Unknown SPN retrieval method.',16,1);
RETURN 0;
END
--return usable values
SELECT
@TenId AS TenantId,
@SubId AS SubscriptionId,
@AppId AS AppId,
@AppSecret AS AppSecret
END;
================================================
FILE: MetadataDB/procfwk/Stored Procedures/GetWorkerDetailsWrapper.sql
================================================
CREATE PROCEDURE [procfwk].[GetWorkerDetailsWrapper]
(
@ExecutionId UNIQUEIDENTIFIER,
@StageId INT,
@PipelineId INT
)
AS
BEGIN
/*
Created this proc just to reduce and refactor the number of pipeline activity
calls needed due to the Microsoft enforced limit of 40 activities per pipeline.
*/
SET NOCOUNT ON;
DECLARE @WorkerAuthDetails TABLE
(
[tenantId] UNIQUEIDENTIFIER NULL,
[applicationId] NVARCHAR(MAX) NULL,
[authenticationKey] NVARCHAR(MAX) NULL,
[subscriptionId] UNIQUEIDENTIFIER NULL
)
DECLARE @WorkerDetails TABLE
(
[resourceGroupName] NVARCHAR(200) NULL,
[orchestratorName] NVARCHAR(200) NULL,
[orchestratorType] CHAR(3) NULL,
[pipelineName] NVARCHAR(200) NULL
)
--get work auth details
INSERT INTO @WorkerAuthDetails
(
[tenantId],
[subscriptionId],
[applicationId],
[authenticationKey]
)
EXEC [procfwk].[GetWorkerAuthDetails]
@ExecutionId = @ExecutionId,
@StageId = @StageId,
@PipelineId = @PipelineId;
--get main worker details
INSERT INTO @WorkerDetails
(
[pipelineName],
[orchestratorName],
[orchestratorType],
[resourceGroupName]
)
EXEC [procfwk].[GetWorkerPipelineDetails]
@ExecutionId = @ExecutionId,
@StageId = @StageId,
@PipelineId = @PipelineId;
--return all details
SELECT
ad.[tenantId],
ad.[applicationId],
ad.[authenticationKey],
ad.[subscriptionId],
d.[resourceGroupName],
d.[orchestratorName],
d.[orchestratorType],
d.[pipelineName]
FROM
@WorkerDetails d
CROSS JOIN @WorkerAuthDetails ad;
END;
================================================
FILE: MetadataDB/procfwk/Stored Procedures/GetWorkerPipelineDetails.sql
================================================
CREATE PROCEDURE [procfwk].[GetWorkerPipelineDetails]
(
@ExecutionId UNIQUEIDENTIFIER,
@StageId INT,
@PipelineId INT
)
AS
BEGIN
SET NOCOUNT ON;
SELECT
[PipelineName],
[OrchestratorName],
[OrchestratorType],
[ResourceGroupName]
FROM
[procfwk].[CurrentExecution]
WHERE
[LocalExecutionId] = @ExecutionId
AND [StageId] = @StageId
AND [PipelineId] = @PipelineId;
END;
================================================
FILE: MetadataDB/procfwk/Stored Procedures/ResetExecution.sql
================================================
CREATE PROCEDURE [procfwk].[ResetExecution]
(
@LocalExecutionId UNIQUEIDENTIFIER = NULL
)
AS
BEGIN
SET NOCOUNT ON;
IF([procfwk].[GetPropertyValueInternal]('UseExecutionBatches')) = '0'
BEGIN
--capture any pipelines that might be in an unexpected state
INSERT INTO [procfwk].[ExecutionLog]
(
[LocalExecutionId],
[StageId],
[PipelineId],
[CallingOrchestratorName],
[ResourceGroupName],
[OrchestratorType],
[OrchestratorName],
[PipelineName],
[StartDateTime],
[PipelineStatus],
[EndDateTime]
)
SELECT
[LocalExecutionId],
[StageId],
[PipelineId],
[CallingOrchestratorName],
[ResourceGroupName],
[OrchestratorType],
[OrchestratorName],
[PipelineName],
[StartDateTime],
'Unknown',
[EndDateTime]
FROM
[procfwk].[CurrentExecution]
WHERE
--these are predicted states
[PipelineStatus] NOT IN
(
'Success',
'Failed',
'Blocked',
'Cancelled'
);
--reset status ready for next attempt
UPDATE
[procfwk].[CurrentExecution]
SET
[StartDateTime] = NULL,
[EndDateTime] = NULL,
[PipelineStatus] = NULL,
[LastStatusCheckDateTime] = NULL,
[PipelineRunId] = NULL,
[PipelineParamsUsed] = NULL,
[IsBlocked] = 0
WHERE
ISNULL([PipelineStatus],'') <> 'Success'
OR [IsBlocked] = 1;
--return current execution id
SELECT DISTINCT
[LocalExecutionId] AS ExecutionId
FROM
[procfwk].[CurrentExecution];
END
ELSE IF ([procfwk].[GetPropertyValueInternal]('UseExecutionBatches')) = '1'
BEGIN
--capture any pipelines that might be in an unexpected state
INSERT INTO [procfwk].[ExecutionLog]
(
[LocalExecutionId],
[StageId],
[PipelineId],
[CallingOrchestratorName],
[ResourceGroupName],
[OrchestratorType],
[OrchestratorName],
[PipelineName],
[StartDateTime],
[PipelineStatus],
[EndDateTime]
)
SELECT
[LocalExecutionId],
[StageId],
[PipelineId],
[CallingOrchestratorName],
[ResourceGroupName],
[OrchestratorType],
[OrchestratorName],
[PipelineName],
[StartDateTime],
'Unknown',
[EndDateTime]
FROM
[procfwk].[CurrentExecution]
WHERE
[LocalExecutionId] = @LocalExecutionId
--these are predicted states
AND [PipelineStatus] NOT IN
(
'Success',
'Failed',
'Blocked',
'Cancelled'
);
--reset status ready for next attempt
UPDATE
[procfwk].[CurrentExecution]
SET
[StartDateTime] = NULL,
[EndDateTime] = NULL,
[PipelineStatus] = NULL,
[LastStatusCheckDateTime] = NULL,
[PipelineRunId] = NULL,
[PipelineParamsUsed] = NULL,
[IsBlocked] = 0
WHERE
[LocalExecutionId] = @LocalExecutionId
AND ISNULL([PipelineStatus],'') <> 'Success'
OR [IsBlocked] = 1;
UPDATE
[procfwk].[BatchExecution]
SET
[EndDateTime] = NULL,
[BatchStatus] = 'Running'
WHERE
[ExecutionId] = @LocalExecutionId;
SELECT
@LocalExecutionId AS ExecutionId
END;
END;
================================================
FILE: MetadataDB/procfwk/Stored Procedures/SetErrorLogDetails.sql
================================================
CREATE PROCEDURE [procfwk].[SetErrorLogDetails]
(
@LocalExecutionId UNIQUEIDENTIFIER,
@JsonErrorDetails VARCHAR(MAX)
)
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO [procfwk].[ErrorLog]
(
[LocalExecutionId],
[PipelineRunId],
[ActivityRunId],
[ActivityName],
[ActivityType],
[ErrorCode],
[ErrorType],
[ErrorMessage]
)
SELECT
@LocalExecutionId,
Base.[RunId],
ErrorDetail.[ActivityRunId],
ErrorDetail.[ActivityName],
ErrorDetail.[ActivityType],
ErrorDetail.[ErrorCode],
ErrorDetail.[ErrorType],
ErrorDetail.[ErrorMessage]
FROM
OPENJSON(@JsonErrorDetails) WITH
(
[RunId] UNIQUEIDENTIFIER,
[Errors] NVARCHAR(MAX) AS JSON
) AS Base
CROSS APPLY OPENJSON (Base.[Errors]) WITH
(
[ActivityRunId] UNIQUEIDENTIFIER,
[ActivityName] VARCHAR(100),
[ActivityType] VARCHAR(100),
[ErrorCode] VARCHAR(100),
[ErrorType] VARCHAR(100),
[ErrorMessage] VARCHAR(MAX)
) AS ErrorDetail
END;
================================================
FILE: MetadataDB/procfwk/Stored Procedures/SetExecutionBlockDependants.sql
================================================
CREATE PROCEDURE [procfwk].[SetExecutionBlockDependants]
(
@ExecutionId UNIQUEIDENTIFIER = NULL,
@PipelineId INT
)
AS
BEGIN
--update dependents status
UPDATE
ce
SET
ce.[PipelineStatus] = 'Blocked',
ce.[IsBlocked] = 1
FROM
[procfwk].[PipelineDependencies] pe
INNER JOIN [procfwk].[CurrentExecution] ce
ON pe.[DependantPipelineId] = ce.[PipelineId]
WHERE
ce.[LocalExecutionId] = @ExecutionId
AND pe.[PipelineId] = @PipelineId
END;
================================================
FILE: MetadataDB/procfwk/Stored Procedures/SetLogActivityFailed.sql
================================================
CREATE PROCEDURE [procfwk].[SetLogActivityFailed]
(
@ExecutionId UNIQUEIDENTIFIER,
@StageId INT,
@PipelineId INT,
@CallingActivity VARCHAR(255)
)
AS
BEGIN
SET NOCOUNT ON;
--mark specific failure pipeline
UPDATE
[procfwk].[CurrentExecution]
SET
[PipelineStatus] = @CallingActivity + 'Error'
WHERE
[LocalExecutionId] = @ExecutionId
AND [StageId] = @StageId
AND [PipelineId] = @PipelineId
--persist failed pipeline records to long term log
INSERT INTO [procfwk].[ExecutionLog]
(
[LocalExecutionId],
[StageId],
[PipelineId],
[CallingOrchestratorName],
[ResourceGroupName],
[OrchestratorType],
[OrchestratorName],
[PipelineName],
[StartDateTime],
[PipelineStatus],
[EndDateTime],
[PipelineRunId],
[PipelineParamsUsed]
)
SELECT
[LocalExecutionId],
[StageId],
[PipelineId],
[CallingOrchestratorName],
[ResourceGroupName],
[OrchestratorType],
[OrchestratorName],
[PipelineName],
[StartDateTime],
[PipelineStatus],
[EndDateTime],
[PipelineRunId],
[PipelineParamsUsed]
FROM
[procfwk].[CurrentExecution]
WHERE
[LocalExecutionId] = @ExecutionId
AND [PipelineStatus] = @CallingActivity + 'Error'
AND [StageId] = @StageId
AND [PipelineId] = @PipelineId
--decide how to proceed with error/failure depending on framework property configuration
IF ([procfwk].[GetPropertyValueInternal]('FailureHandling')) = 'None'
BEGIN
--do nothing allow processing to carry on regardless
RETURN 0;
END;
ELSE IF ([procfwk].[GetPropertyValueInternal]('FailureHandling')) = 'Simple'
BEGIN
--flag all downstream stages as blocked
UPDATE
[procfwk].[CurrentExecution]
SET
[PipelineStatus] = 'Blocked',
[IsBlocked] = 1
WHERE
[LocalExecutionId] = @ExecutionId
AND [StageId] > @StageId;
--update batch if applicable
IF ([procfwk].[GetPropertyValueInternal]('UseExecutionBatches')) = '1'
BEGIN
UPDATE
[procfwk].[BatchExecution]
SET
[BatchStatus] = 'Stopping' --special case when its an activity failure to call stop ready for restart
WHERE
[ExecutionId] = @ExecutionId
AND [BatchStatus] = 'Running';
END;
END;
ELSE IF ([procfwk].[GetPropertyValueInternal]('FailureHandling')) = 'DependencyChain'
BEGIN
EXEC [procfwk].[SetExecutionBlockDependants]
@ExecutionId = @ExecutionId,
@PipelineId = @PipelineId
END;
ELSE
BEGIN
RAISERROR('Unknown failure handling state.',16,1);
RETURN 0;
END;
END;
================================================
FILE: MetadataDB/procfwk/Stored Procedures/SetLogPipelineCancelled.sql
================================================
CREATE PROCEDURE [procfwk].[SetLogPipelineCancelled]
(
@ExecutionId UNIQUEIDENTIFIER,
@StageId INT,
@PipelineId INT,
@CleanUpRun BIT = 0
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @ErrorDetail VARCHAR(500);
--mark specific failure pipeline
UPDATE
[procfwk].[CurrentExecution]
SET
[PipelineStatus] = 'Cancelled'
WHERE
[LocalExecutionId] = @ExecutionId
AND [StageId] = @StageId
AND [PipelineId] = @PipelineId
--no need to block and log if done during a clean up cycle
IF @CleanUpRun = 1 RETURN 0;
--persist cancelled pipeline records to long term log
INSERT INTO [procfwk].[ExecutionLog]
(
[LocalExecutionId],
[StageId],
[PipelineId],
[CallingOrchestratorName],
[ResourceGroupName],
[OrchestratorType],
[OrchestratorName],
[PipelineName],
[StartDateTime],
[PipelineStatus],
[EndDateTime],
[PipelineRunId],
[PipelineParamsUsed]
)
SELECT
[LocalExecutionId],
[StageId],
[PipelineId],
[CallingOrchestratorName],
[ResourceGroupName],
[OrchestratorType],
[OrchestratorName],
[PipelineName],
[StartDateTime],
[PipelineStatus],
[EndDateTime],
[PipelineRunId],
[PipelineParamsUsed]
FROM
[procfwk].[CurrentExecution]
WHERE
[LocalExecutionId] = @ExecutionId
AND [PipelineStatus] = 'Cancelled'
AND [StageId] = @StageId
AND [PipelineId] = @PipelineId;
--block down stream stages?
IF ([procfwk].[GetPropertyValueInternal]('CancelledWorkerResultBlocks')) = 1
BEGIN
--decide how to proceed with error/failure depending on framework property configuration
IF ([procfwk].[GetPropertyValueInternal]('FailureHandling')) = 'None'
BEGIN
--do nothing allow processing to carry on regardless
RETURN 0;
END;
ELSE IF ([procfwk].[GetPropertyValueInternal]('FailureHandling')) = 'Simple'
BEGIN
--flag all downstream stages as blocked
UPDATE
[procfwk].[CurrentExecution]
SET
[PipelineStatus] = 'Blocked',
[IsBlocked] = 1
WHERE
[LocalExecutionId] = @ExecutionId
AND [StageId] > @StageId
--update batch if applicable
IF ([procfwk].[GetPropertyValueInternal]('UseExecutionBatches')) = '1'
BEGIN
UPDATE
[procfwk].[BatchExecution]
SET
[BatchStatus] = 'Stopping'
WHERE
[ExecutionId] = @ExecutionId
AND [BatchStatus] = 'Running';
END;
SET @ErrorDetail = 'Pipeline execution has a cancelled status. Blocking downstream stages as a precaution.'
RAISERROR(@ErrorDetail,16,1);
RETURN 0;
END;
ELSE IF ([procfwk].[GetPropertyValueInternal]('FailureHandling')) = 'DependencyChain'
BEGIN
EXEC [procfwk].[SetExecutionBlockDependants]
@ExecutionId = @ExecutionId,
@PipelineId = @PipelineId
END;
ELSE
BEGIN
RAISERROR('Cancelled execution failure handling state.',16,1);
RETURN 0;
END;
END;
END;
================================================
FILE: MetadataDB/procfwk/Stored Procedures/SetLogPipelineChecking.sql
================================================
CREATE PROCEDURE [procfwk].[SetLogPipelineChecking]
(
@ExecutionId UNIQUEIDENTIFIER,
@StageId INT,
@PipelineId INT
)
AS
BEGIN
SET NOCOUNT ON;
UPDATE
[procfwk].[CurrentExecution]
SET
[PipelineStatus] = 'Checking'
WHERE
[LocalExecutionId] = @ExecutionId
AND [StageId] = @StageId
AND [PipelineId] = @PipelineId
END;
================================================
FILE: MetadataDB/procfwk/Stored Procedures/SetLogPipelineFailed.sql
================================================
CREATE PROCEDURE [procfwk].[SetLogPipelineFailed]
(
@ExecutionId UNIQUEIDENTIFIER,
@StageId INT,
@PipelineId INT,
@RunId UNIQUEIDENTIFIER = NULL
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @ErrorDetail VARCHAR(500)
--mark specific failure pipeline
UPDATE
[procfwk].[CurrentExecution]
SET
[PipelineStatus] = 'Failed'
WHERE
[LocalExecutionId] = @ExecutionId
AND [StageId] = @StageId
AND [PipelineId] = @PipelineId
--persist failed pipeline records to long term log
INSERT INTO [procfwk].[ExecutionLog]
(
[LocalExecutionId],
[StageId],
[PipelineId],
[CallingOrchestratorName],
[ResourceGroupName],
[OrchestratorType],
[OrchestratorName],
[PipelineName],
[StartDateTime],
[PipelineStatus],
[EndDateTime],
[PipelineRunId],
[PipelineParamsUsed]
)
SELECT
[LocalExecutionId],
[StageId],
[PipelineId],
[CallingOrchestratorName],
[ResourceGroupName],
[OrchestratorType],
[OrchestratorName],
[PipelineName],
[StartDateTime],
[PipelineStatus],
[EndDateTime],
[PipelineRunId],
[PipelineParamsUsed]
FROM
[procfwk].[CurrentExecution]
WHERE
[LocalExecutionId] = @ExecutionId
AND [PipelineStatus] = 'Failed'
AND [StageId] = @StageId
AND [PipelineId] = @PipelineId;
IF ([procfwk].[GetPropertyValueInternal]('FailureHandling')) = 'None'
BEGIN
--do nothing allow processing to carry on regardless
RETURN 0;
END;
ELSE IF ([procfwk].[GetPropertyValueInternal]('FailureHandling')) = 'Simple'
BEGIN
--flag all downstream stages as blocked
UPDATE
[procfwk].[CurrentExecution]
SET
[PipelineStatus] = 'Blocked',
[IsBlocked] = 1
WHERE
[LocalExecutionId] = @ExecutionId
AND [StageId] > @StageId
--raise error to stop processing
IF @RunId IS NOT NULL
BEGIN
SET @ErrorDetail = 'Pipeline execution failed. Check Run ID: ' + CAST(@RunId AS CHAR(36)) + ' in ADF monitoring for details.'
END;
ELSE
BEGIN
SET @ErrorDetail = 'Pipeline execution failed. See ADF monitoring for details.'
END;
--update batch if applicable
IF ([procfwk].[GetPropertyValueInternal]('UseExecutionBatches')) = '1'
BEGIN
UPDATE
[procfwk].[BatchExecution]
SET
[BatchStatus] = 'Stopping'
WHERE
[ExecutionId] = @ExecutionId
AND [BatchStatus] = 'Running';
END;
RAISERROR(@ErrorDetail,16,1);
RETURN 0;
END;
ELSE IF ([procfwk].[GetPropertyValueInternal]('FailureHandling')) = 'DependencyChain'
BEGIN
EXEC [procfwk].[SetExecutionBlockDependants]
@ExecutionId = @ExecutionId,
@PipelineId = @PipelineId
END;
ELSE
BEGIN
RAISERROR('Unknown failure handling state.',16,1);
RETURN 0;
END;
END;
================================================
FILE: MetadataDB/procfwk/Stored Procedures/SetLogPipelineLastStatusCheck.sql
================================================
CREATE PROCEDURE [procfwk].[SetLogPipelineLastStatusCheck]
(
@ExecutionId UNIQUEIDENTIFIER,
@StageId INT,
@PipelineId INT
)
AS
BEGIN
SET NOCOUNT ON;
UPDATE
[procfwk].[CurrentExecution]
SET
[LastStatusCheckDateTime] = GETUTCDATE()
WHERE
[LocalExecutionId] = @ExecutionId
AND [StageId] = @StageId
AND [PipelineId] = @PipelineId
END;
================================================
FILE: MetadataDB/procfwk/Stored Procedures/SetLogPipelineRunId.sql
================================================
CREATE PROCEDURE [procfwk].[SetLogPipelineRunId]
(
@ExecutionId UNIQUEIDENTIFIER,
@StageId INT,
@PipelineId INT,
@RunId UNIQUEIDENTIFIER = NULL
)
AS
BEGIN
SET NOCOUNT ON;
UPDATE
[procfwk].[CurrentExecution]
SET
[PipelineRunId] = LOWER(@RunId)
WHERE
[LocalExecutionId] = @ExecutionId
AND [StageId] = @StageId
AND [PipelineId] = @PipelineId
END;
================================================
FILE: MetadataDB/procfwk/Stored Procedures/SetLogPipelineRunning.sql
================================================
CREATE PROCEDURE procfwk.SetLogPipelineRunning
(
@ExecutionId UNIQUEIDENTIFIER,
@StageId INT,
@PipelineId INT
)
AS
BEGIN
SET NOCOUNT ON;
UPDATE
[procfwk].[CurrentExecution]
SET
--case for clean up runs
[StartDateTime] = CASE WHEN [StartDateTime] IS NULL THEN GETUTCDATE() ELSE [StartDateTime] END,
[PipelineStatus] = 'Running'
WHERE
[LocalExecutionId] = @ExecutionId
AND [StageId] = @StageId
AND [PipelineId] = @PipelineId
END;
================================================
FILE: MetadataDB/procfwk/Stored Procedures/SetLogPipelineSuccess.sql
================================================
CREATE PROCEDURE procfwk.SetLogPipelineSuccess
(
@ExecutionId UNIQUEIDENTIFIER,
@StageId INT,
@PipelineId INT
)
AS
BEGIN
SET NOCOUNT ON;
UPDATE
[procfwk].[CurrentExecution]
SET
--case for clean up runs
[EndDateTime] = CASE WHEN [EndDateTime] IS NULL THEN GETUTCDATE() ELSE [EndDateTime] END,
[PipelineStatus] = 'Success'
WHERE
[LocalExecutionId] = @ExecutionId
AND [StageId] = @StageId
AND [PipelineId] = @PipelineId
END;
================================================
FILE: MetadataDB/procfwk/Stored Procedures/SetLogPipelineUnknown.sql
================================================
CREATE PROCEDURE [procfwk].[SetLogPipelineUnknown]
(
@ExecutionId UNIQUEIDENTIFIER,
@StageId INT,
@PipelineId INT,
@CleanUpRun BIT = 0
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @ErrorDetail VARCHAR(500);
--mark specific failure pipeline
UPDATE
[procfwk].[CurrentExecution]
SET
[PipelineStatus] = 'Unknown'
WHERE
[LocalExecutionId] = @ExecutionId
AND [StageId] = @StageId
AND [PipelineId] = @PipelineId
--no need to block and log if done during a clean up cycle
IF @CleanUpRun = 1 RETURN 0;
--persist unknown pipeline records to long term log
INSERT INTO [procfwk].[ExecutionLog]
(
[LocalExecutionId],
[StageId],
[PipelineId],
[CallingOrchestratorName],
[ResourceGroupName],
[OrchestratorType],
[OrchestratorName],
[PipelineName],
[StartDateTime],
[PipelineStatus],
[EndDateTime],
[PipelineRunId],
[PipelineParamsUsed]
)
SELECT
[LocalExecutionId],
[StageId],
[PipelineId],
[CallingOrchestratorName],
[ResourceGroupName],
[OrchestratorType],
[OrchestratorName],
[PipelineName],
[StartDateTime],
[PipelineStatus],
[EndDateTime],
[PipelineRunId],
[PipelineParamsUsed]
FROM
[procfwk].[CurrentExecution]
WHERE
[PipelineStatus] = 'Unknown'
AND [StageId] = @StageId
AND [PipelineId] = @PipelineId;
--block down stream stages?
IF ([procfwk].[GetPropertyValueInternal]('UnknownWorkerResultBlocks')) = 1
BEGIN
--decide how to proceed with error/failure depending on framework property configuration
IF ([procfwk].[GetPropertyValueInternal]('FailureHandling')) = 'None'
BEGIN
--do nothing allow processing to carry on regardless
RETURN 0;
END;
ELSE IF ([procfwk].[GetPropertyValueInternal]('FailureHandling')) = 'Simple'
BEGIN
--flag all downstream stages as blocked
UPDATE
[procfwk].[CurrentExecution]
SET
[PipelineStatus] = 'Blocked',
[IsBlocked] = 1
WHERE
[LocalExecutionId] = @ExecutionId
AND [StageId] > @StageId
UPDATE
[procfwk].[BatchExecution]
SET
[BatchStatus] = 'Stopping'
WHERE
[ExecutionId] = @ExecutionId
AND [BatchStatus] = 'Running';
SET @ErrorDetail = 'Pipeline execution has an unknown status. Blocking downstream stages as a precaution.'
RAISERROR(@ErrorDetail,16,1);
RETURN 0;
END;
ELSE IF ([procfwk].[GetPropertyValueInternal]('FailureHandling')) = 'DependencyChain'
BEGIN
EXEC [procfwk].[SetExecutionBlockDependants]
@ExecutionId = @ExecutionId,
@PipelineId = @PipelineId
END;
ELSE
BEGIN
RAISERROR('Unknown failure handling state.',16,1);
RETURN 0;
END;
END;
END;
================================================
FILE: MetadataDB/procfwk/Stored Procedures/SetLogPipelineValidating.sql
================================================
CREATE PROCEDURE [procfwk].[SetLogPipelineValidating]
(
@ExecutionId UNIQUEIDENTIFIER,
@StageId INT,
@PipelineId INT
)
AS
BEGIN
SET NOCOUNT ON;
UPDATE
[procfwk].[CurrentExecution]
SET
[PipelineStatus] = 'Validating'
WHERE
[LocalExecutionId] = @ExecutionId
AND [StageId] = @StageId
AND [PipelineId] = @PipelineId
END;
================================================
FILE: MetadataDB/procfwk/Stored Procedures/SetLogStagePreparing.sql
================================================
CREATE PROCEDURE [procfwk].[SetLogStagePreparing]
(
@ExecutionId UNIQUEIDENTIFIER,
@StageId INT
)
AS
BEGIN
SET NOCOUNT ON;
UPDATE
[procfwk].[CurrentExecution]
SET
[PipelineStatus] = 'Preparing'
WHERE
[LocalExecutionId] = @ExecutionId
AND [StageId] = @StageId
AND [StartDateTime] IS NULL
AND [IsBlocked] <> 1;
END;
================================================
FILE: MetadataDB/procfwk/Stored Procedures/UpdateExecutionLog.sql
================================================
CREATE PROCEDURE [procfwk].[UpdateExecutionLog]
(
@PerformErrorCheck BIT = 1,
@ExecutionId UNIQUEIDENTIFIER = NULL
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @AllCount INT
DECLARE @SuccessCount INT
IF([procfwk].[GetPropertyValueInternal]('UseExecutionBatches')) = '0'
BEGIN
IF @PerformErrorCheck = 1
BEGIN
--Check current execution
SELECT @AllCount = COUNT(0) FROM [procfwk].[CurrentExecution]
SELECT @SuccessCount = COUNT(0) FROM [procfwk].[CurrentExecution] WHERE [PipelineStatus] = 'Success'
IF @AllCount <> @SuccessCount
BEGIN
RAISERROR('Framework execution complete but not all Worker pipelines succeeded. See the [procfwk].[CurrentExecution] table for details',16,1);
RETURN 0;
END;
END;
--Do this if no error raised and when called by the execution wrapper (OverideRestart = 1).
INSERT INTO [procfwk].[ExecutionLog]
(
[LocalExecutionId],
[StageId],
[PipelineId],
[CallingOrchestratorName],
[ResourceGroupName],
[OrchestratorType],
[OrchestratorName],
[PipelineName],
[StartDateTime],
[PipelineStatus],
[EndDateTime],
[PipelineRunId],
[PipelineParamsUsed]
)
SELECT
[LocalExecutionId],
[StageId],
[PipelineId],
[CallingOrchestratorName],
[ResourceGroupName],
[OrchestratorType],
[OrchestratorName],
[PipelineName],
[StartDateTime],
[PipelineStatus],
[EndDateTime],
[PipelineRunId],
[PipelineParamsUsed]
FROM
[procfwk].[CurrentExecution];
TRUNCATE TABLE [procfwk].[CurrentExecution];
END
ELSE IF ([procfwk].[GetPropertyValueInternal]('UseExecutionBatches')) = '1'
BEGIN
IF @PerformErrorCheck = 1
BEGIN
--Check current execution
SELECT
@AllCount = COUNT(0)
FROM
[procfwk].[CurrentExecution]
WHERE
[LocalExecutionId] = @ExecutionId;
SELECT
@SuccessCount = COUNT(0)
FROM
[procfwk].[CurrentExecution]
WHERE
[LocalExecutionId] = @ExecutionId
AND [PipelineStatus] = 'Success';
IF @AllCount <> @SuccessCount
BEGIN
UPDATE
[procfwk].[BatchExecution]
SET
[BatchStatus] = 'Stopped',
[EndDateTime] = GETUTCDATE()
WHERE
[ExecutionId] = @ExecutionId;
RAISERROR('Framework execution complete for batch but not all Worker pipelines succeeded. See the [procfwk].[CurrentExecution] table for details',16,1);
RETURN 0;
END;
ELSE
BEGIN
UPDATE
[procfwk].[BatchExecution]
SET
[BatchStatus] = 'Success',
[EndDateTime] = GETUTCDATE()
WHERE
[ExecutionId] = @ExecutionId;
END;
END; --end check
--Do this if no error raised and when called by the execution wrapper (OverideRestart = 1).
INSERT INTO [procfwk].[ExecutionLog]
(
[LocalExecutionId],
[StageId],
[PipelineId],
[CallingOrchestratorName],
[ResourceGroupName],
[OrchestratorType],
[OrchestratorName],
[PipelineName],
[StartDateTime],
[PipelineStatus],
[EndDateTime],
[PipelineRunId],
[PipelineParamsUsed]
)
SELECT
[LocalExecutionId],
[StageId],
[PipelineId],
[CallingOrchestratorName],
[ResourceGroupName],
[OrchestratorType],
[OrchestratorName],
[PipelineName],
[StartDateTime],
[PipelineStatus],
[EndDateTime],
[PipelineRunId],
[PipelineParamsUsed]
FROM
[procfwk].[CurrentExecution]
WHERE
[LocalExecutionId] = @ExecutionId;
DELETE FROM
[procfwk].[CurrentExecution]
WHERE
[LocalExecutionId] = @ExecutionId;
END;
END;
================================================
FILE: MetadataDB/procfwk/Synonyms/AverageStageDuration.sql
================================================
CREATE SYNONYM [procfwk].[AverageStageDuration]
FOR [procfwkReporting].[AverageStageDuration];
================================================
FILE: MetadataDB/procfwk/Synonyms/CompleteExecutionErrorLog.sql
================================================
CREATE SYNONYM [procfwk].[CompleteExecutionErrorLog]
FOR [procfwkReporting].[CompleteExecutionErrorLog];
================================================
FILE: MetadataDB/procfwk/Synonyms/CompleteExecutionLog.sql
================================================
CREATE SYNONYM [procfwk].[CompleteExecutionLog]
FOR [procfwkReporting].[CompleteExecutionLog];
================================================
FILE: MetadataDB/procfwk/Synonyms/CurrentExecutionSummary.sql
================================================
CREATE SYNONYM [procfwk].[CurrentExecutionSummary]
FOR [procfwkReporting].[CurrentExecutionSummary];
================================================
FILE: MetadataDB/procfwk/Synonyms/DataFactoryDetails.sql
================================================
CREATE SYNONYM [procfwk].[DataFactoryDetails]
FOR [procfwk].[Orchestrators];
================================================
FILE: MetadataDB/procfwk/Synonyms/LastExecution.sql
================================================
CREATE SYNONYM [procfwk].[LastExecution]
FOR [procfwkReporting].[LastExecution];
================================================
FILE: MetadataDB/procfwk/Synonyms/LastExecutionSummary.sql
================================================
CREATE SYNONYM [procfwk].[LastExecutionSummary]
FOR [procfwkReporting].[LastExecutionSummary];
================================================
FILE: MetadataDB/procfwk/Synonyms/PipelineDependencyChains.sql
================================================
CREATE SYNONYM [procfwk].[PipelineDependencyChains]
FOR [procfwkHelpers].[PipelineDependencyChains];
================================================
FILE: MetadataDB/procfwk/Synonyms/PipelineProcesses.sql
================================================
CREATE SYNONYM [procfwk].[PipelineProcesses]
FOR [procfwk].[Pipelines];
================================================
FILE: MetadataDB/procfwk/Synonyms/ProcessingStageDetails.sql
================================================
CREATE SYNONYM [procfwk].[ProcessingStageDetails]
FOR [procfwk].[Stages];
================================================
FILE: MetadataDB/procfwk/Synonyms/WorkerParallelismOverTime.sql
================================================
CREATE SYNONYM [procfwk].[WorkerParallelismOverTime]
FOR [procfwkReporting].[WorkerParallelismOverTime];
================================================
FILE: MetadataDB/procfwk/Tables/AlertOutcomes.sql
================================================
CREATE TABLE [procfwk].[AlertOutcomes]
(
[OutcomeBitPosition] INT IDENTITY(0,1) NOT NULL,
[PipelineOutcomeStatus] NVARCHAR(200) NOT NULL,
[BitValue] AS (POWER((2),[OutcomeBitPosition])),
CONSTRAINT [PK_AlertOutcomes] PRIMARY KEY CLUSTERED ([OutcomeBitPosition] ASC),
CONSTRAINT [UK_PipelineOutcomeStatus] UNIQUE ([PipelineOutcomeStatus])
)
================================================
FILE: MetadataDB/procfwk/Tables/BatchExecution.sql
================================================
CREATE TABLE [procfwk].[BatchExecution](
[BatchId] [UNIQUEIDENTIFIER] NOT NULL,
[ExecutionId] [UNIQUEIDENTIFIER] NOT NULL,
[BatchName] VARCHAR(255) NOT NULL,
[BatchStatus] [NVARCHAR](200) NOT NULL,
[StartDateTime] [DATETIME] NOT NULL,
[EndDateTime] [DATETIME] NULL,
CONSTRAINT [PK_BatchExecution] PRIMARY KEY CLUSTERED
(
[BatchId] ASC,
[ExecutionId] ASC
)
)
================================================
FILE: MetadataDB/procfwk/Tables/BatchStageLink.sql
================================================
CREATE TABLE [procfwk].[BatchStageLink]
(
[BatchId] [UNIQUEIDENTIFIER] NOT NULL,
[StageId] [INT] NOT NULL,
CONSTRAINT [PK_BatchStageLink] PRIMARY KEY CLUSTERED
(
[BatchId] ASC,
[StageId] ASC
),
CONSTRAINT [FK_BatchStageLink_Batches] FOREIGN KEY([BatchId]) REFERENCES [procfwk].[Batches] ([BatchId]),
CONSTRAINT [FK_BatchStageLink_Stages] FOREIGN KEY([StageId]) REFERENCES [procfwk].[Stages] ([StageId])
)
================================================
FILE: MetadataDB/procfwk/Tables/Batches.sql
================================================
CREATE TABLE [procfwk].[Batches](
[BatchId] UNIQUEIDENTIFIER DEFAULT(NEWID()) NOT NULL,
[BatchName] [VARCHAR](255) NOT NULL,
[BatchDescription] [VARCHAR](4000) NULL,
[Enabled] [BIT] DEFAULT(0) NOT NULL,
CONSTRAINT [PK_Batches] PRIMARY KEY CLUSTERED
(
[BatchId] ASC
)
)
================================================
FILE: MetadataDB/procfwk/Tables/CurrentExecution.sql
================================================
CREATE TABLE [procfwk].[CurrentExecution] (
[LocalExecutionId] UNIQUEIDENTIFIER NOT NULL,
[StageId] INT NOT NULL,
[PipelineId] INT NOT NULL,
[CallingOrchestratorName] NVARCHAR(200) NOT NULL,
[ResourceGroupName]NVARCHAR (200) NOT NULL,
[OrchestratorType] CHAR(3) NOT NULL,
[OrchestratorName] NVARCHAR (200) NOT NULL,
[PipelineName] NVARCHAR (200) NOT NULL,
[StartDateTime] DATETIME NULL,
[PipelineStatus] NVARCHAR (200) NULL,
[LastStatusCheckDateTime] DATETIME NULL,
[EndDateTime] DATETIME NULL,
[IsBlocked] BIT NOT NULL DEFAULT 0,
[PipelineRunId] UNIQUEIDENTIFIER NULL,
[PipelineParamsUsed] NVARCHAR(MAX) NULL,
CONSTRAINT [PK_CurrentExecution] PRIMARY KEY CLUSTERED ([LocalExecutionId] ASC, [StageId] ASC, [PipelineId] ASC)
);
GO
CREATE NONCLUSTERED INDEX [IDX_GetPipelinesInStage] ON [procfwk].[CurrentExecution]
(
[LocalExecutionId],
[StageId],
[PipelineStatus]
)
INCLUDE
(
[PipelineId],
[PipelineName],
[OrchestratorType],
[OrchestratorName],
[ResourceGroupName]
)
GO
================================================
FILE: MetadataDB/procfwk/Tables/ErrorLog.sql
================================================
CREATE TABLE [procfwk].[ErrorLog]
(
[LogId] [int] IDENTITY(1,1) NOT NULL,
[LocalExecutionId] [uniqueidentifier] NOT NULL,
[PipelineRunId] [uniqueidentifier] NOT NULL,
[ActivityRunId] [uniqueidentifier] NOT NULL,
[ActivityName] [varchar](100) NOT NULL,
[ActivityType] [varchar](100) NOT NULL,
[ErrorCode] VARCHAR(100) NOT NULL,
[ErrorType] [varchar](100) NOT NULL,
[ErrorMessage] [nvarchar](MAX) NULL,
CONSTRAINT [PK_ErrorLog] PRIMARY KEY CLUSTERED
(
[LogId] ASC
)
)
================================================
FILE: MetadataDB/procfwk/Tables/ExecutionLog.sql
================================================
CREATE TABLE [procfwk].[ExecutionLog]
(
[LogId] INT IDENTITY (1, 1) NOT NULL,
[LocalExecutionId] UNIQUEIDENTIFIER NOT NULL,
[StageId] INT NOT NULL,
[PipelineId] INT NOT NULL,
[CallingOrchestratorName] NVARCHAR(200) NOT NULL DEFAULT ('Unknown'),
[ResourceGroupName] NVARCHAR(200) NOT NULL DEFAULT ('Unknown'),
[OrchestratorType] CHAR(3) NOT NULL DEFAULT('N/A'),
[OrchestratorName] NVARCHAR(200) NOT NULL DEFAULT ('Unknown'),
[PipelineName] NVARCHAR (200) NOT NULL,
[StartDateTime] DATETIME NULL,
[PipelineStatus] NVARCHAR (200) NULL,
[EndDateTime] DATETIME NULL,
[PipelineRunId] UNIQUEIDENTIFIER NULL,
[PipelineParamsUsed] NVARCHAR(MAX) NULL DEFAULT ('None'),
CONSTRAINT [PK_ExecutionLog] PRIMARY KEY CLUSTERED ([LogId] ASC)
);
================================================
FILE: MetadataDB/procfwk/Tables/Orchestrators.sql
================================================
CREATE TABLE [procfwk].[Orchestrators]
(
[OrchestratorId] [int] IDENTITY(1,1) NOT NULL,
[OrchestratorName] NVARCHAR(200) NOT NULL,
[OrchestratorType] CHAR(3) NOT NULL,
[IsFrameworkOrchestrator] BIT NOT NULL DEFAULT(0),
[ResourceGroupName] NVARCHAR(200) NOT NULL,
[SubscriptionId] UNIQUEIDENTIFIER NOT NULL,
[Description] NVARCHAR(MAX) NULL,
CONSTRAINT [OrchestratorType] CHECK ([OrchestratorType] IN ('ADF','SYN')),
CONSTRAINT [FK_Orchestrators_Subscriptions] FOREIGN KEY([SubscriptionId]) REFERENCES [procfwk].[Subscriptions] ([SubscriptionId]),
CONSTRAINT [PK_Orchestrators] PRIMARY KEY CLUSTERED ([OrchestratorId] ASC)
)
================================================
FILE: MetadataDB/procfwk/Tables/PipelineAlertLink.sql
================================================
CREATE TABLE [procfwk].[PipelineAlertLink]
(
[AlertId] INT IDENTITY(1,1) NOT NULL,
[PipelineId] INT NOT NULL,
[RecipientId] INT NOT NULL,
[OutcomesBitValue] INT NOT NULL,
[Enabled] BIT NOT NULL DEFAULT 1,
CONSTRAINT [PK_PipelineAlertLink] PRIMARY KEY CLUSTERED ([AlertId] ASC),
CONSTRAINT [FK_PipelineAlertLink_Pipelines] FOREIGN KEY([PipelineId]) REFERENCES [procfwk].[Pipelines] ([PipelineId]),
CONSTRAINT [FK_PipelineAlertLink_Recipients] FOREIGN KEY([RecipientId]) REFERENCES [procfwk].[Recipients] ([RecipientId])
);
================================================
FILE: MetadataDB/procfwk/Tables/PipelineAuthLink.sql
================================================
CREATE TABLE [procfwk].[PipelineAuthLink]
(
[AuthId] [int] IDENTITY(1,1) NOT NULL,
[PipelineId] [int] NOT NULL,
[OrchestratorId] [int] NOT NULL,
[CredentialId] [int] NOT NULL,
CONSTRAINT [PK_PipelineAuthLink] PRIMARY KEY CLUSTERED ([AuthId] ASC),
CONSTRAINT [FK_PipelineAuthLink_Orchestrators] FOREIGN KEY([OrchestratorId]) REFERENCES [procfwk].[Orchestrators] ([OrchestratorId]),
CONSTRAINT [FK_PipelineAuthLink_Pipelines] FOREIGN KEY([PipelineId]) REFERENCES [procfwk].[Pipelines] ([PipelineId]),
CONSTRAINT [FK_PipelineAuthLink_ServicePrincipals] FOREIGN KEY([CredentialId]) REFERENCES [dbo].[ServicePrincipals] ([CredentialId])
);
================================================
FILE: MetadataDB/procfwk/Tables/PipelineDependencies.sql
================================================
CREATE TABLE [procfwk].[PipelineDependencies]
(
[DependencyId] [INT] IDENTITY(1,1) NOT NULL,
[PipelineId] [INT] NOT NULL,
[DependantPipelineId] [INT] NOT NULL,
CONSTRAINT [PK_PipelineDependencies] PRIMARY KEY CLUSTERED ([DependencyId] ASC),
CONSTRAINT [FK_PipelineDependencies_Pipelines] FOREIGN KEY([PipelineId]) REFERENCES [procfwk].[Pipelines] ([PipelineId]),
CONSTRAINT [FK_PipelineDependencies_Pipelines1] FOREIGN KEY([DependantPipelineId]) REFERENCES [procfwk].[Pipelines] ([PipelineId]),
CONSTRAINT [UK_PipelinesToDependantPipelines] UNIQUE ([PipelineId],[DependantPipelineId]),
CONSTRAINT [EQ_PipelineIdDependantPipelineId] CHECK ([PipelineId] <> [DependantPipelineId])
)
================================================
FILE: MetadataDB/procfwk/Tables/PipelineParameters.sql
================================================
CREATE TABLE [procfwk].[PipelineParameters] (
[ParameterId] INT IDENTITY (1, 1) NOT NULL,
[PipelineId] INT NOT NULL,
[ParameterName] VARCHAR (128) NOT NULL,
[ParameterValue] NVARCHAR(MAX) NULL,
[ParameterValueLastUsed] NVARCHAR(MAX) NULL,
CONSTRAINT [PK_PipelineParameters] PRIMARY KEY CLUSTERED ([ParameterId] ASC),
CONSTRAINT [FK_PipelineParameters_Pipelines] FOREIGN KEY ([PipelineId]) REFERENCES [procfwk].[Pipelines] ([PipelineId])
);
================================================
FILE: MetadataDB/procfwk/Tables/Pipelines.sql
================================================
CREATE TABLE [procfwk].[Pipelines] (
[PipelineId] INT IDENTITY (1, 1) NOT NULL,
[OrchestratorId] INT NOT NULL,
[StageId] INT NOT NULL,
[PipelineName] NVARCHAR (200) NOT NULL,
[LogicalPredecessorId] INT NULL,
[Enabled] BIT CONSTRAINT [DF_Pipelines_Enabled] DEFAULT ((1)) NOT NULL,
CONSTRAINT [PK_Pipelines] PRIMARY KEY CLUSTERED ([PipelineId] ASC),
CONSTRAINT [FK_Pipelines_Stages] FOREIGN KEY ([StageId]) REFERENCES [procfwk].[Stages] ([StageId]),
CONSTRAINT [FK_Pipelines_Orchestrators] FOREIGN KEY([OrchestratorId]) REFERENCES [procfwk].[Orchestrators] ([OrchestratorId]),
CONSTRAINT [FK_Pipelines_Pipelines] FOREIGN KEY([LogicalPredecessorId]) REFERENCES [procfwk].[Pipelines] ([PipelineId])
);
================================================
FILE: MetadataDB/procfwk/Tables/Properties.sql
================================================
CREATE TABLE [procfwk].[Properties]
(
[PropertyId] [int] IDENTITY (1, 1) NOT NULL,
[PropertyName] [varchar](128) NOT NULL,
[PropertyValue] [nvarchar](MAX) NOT NULL,
[Description] [nvarchar](MAX) NULL,
[ValidFrom] [datetime] CONSTRAINT [DF_Properties_ValidFrom] DEFAULT (GETDATE()) NOT NULL,
[ValidTo] [datetime] NULL,
CONSTRAINT [PK_Properties] PRIMARY KEY CLUSTERED ([PropertyId] ASC, [PropertyName] ASC)
)
GO
================================================
FILE: MetadataDB/procfwk/Tables/Recipients.sql
================================================
CREATE TABLE [procfwk].[Recipients]
(
[RecipientId] INT IDENTITY(1,1) NOT NULL,
[Name] VARCHAR(255) NULL,
[EmailAddress] NVARCHAR(500) NOT NULL,
[MessagePreference] CHAR(3) NOT NULL DEFAULT ('TO'),
CONSTRAINT [MessagePreferenceValue] CHECK ([MessagePreference] IN ('TO','CC','BCC')),
[Enabled] BIT NOT NULL DEFAULT 1,
CONSTRAINT [PK_Recipients] PRIMARY KEY CLUSTERED ([RecipientId] ASC),
CONSTRAINT [UK_EmailAddressMessagePreference] UNIQUE ([EmailAddress],[MessagePreference])
);
================================================
FILE: MetadataDB/procfwk/Tables/Stages.sql
================================================
CREATE TABLE [procfwk].[Stages] (
[StageId] INT IDENTITY (1, 1) NOT NULL,
[StageName] VARCHAR (225) NOT NULL,
[StageDescription] VARCHAR (4000) NULL,
[Enabled] BIT CONSTRAINT [DF_Stages_Enabled] DEFAULT ((1)) NOT NULL,
CONSTRAINT [PK_Stages] PRIMARY KEY CLUSTERED ([StageId] ASC)
);
================================================
FILE: MetadataDB/procfwk/Tables/Subscriptions.sql
================================================
CREATE TABLE [procfwk].[Subscriptions]
(
[SubscriptionId] UNIQUEIDENTIFIER NOT NULL,
[Name] NVARCHAR(200) NOT NULL,
[Description] NVARCHAR(MAX) NULL,
[TenantId] UNIQUEIDENTIFIER NOT NULL,
CONSTRAINT [PK_Subscriptions] PRIMARY KEY CLUSTERED ([SubscriptionId] ASC),
CONSTRAINT [FK_Subscriptions_Tenants] FOREIGN KEY([TenantId]) REFERENCES [procfwk].[Tenants] ([TenantId])
)
================================================
FILE: MetadataDB/procfwk/Tables/Tenants.sql
================================================
CREATE TABLE [procfwk].[Tenants]
(
[TenantId] [UNIQUEIDENTIFIER] NOT NULL,
[Name] [NVARCHAR](200) NOT NULL,
[Description] [NVARCHAR](MAX) NULL,
CONSTRAINT [PK_Tenants] PRIMARY KEY CLUSTERED ([TenantId] ASC)
)
================================================
FILE: MetadataDB/procfwk/Views/CurrentProperties.sql
================================================
CREATE VIEW [procfwk].[CurrentProperties]
AS
SELECT
[PropertyName],
[PropertyValue]
FROM
[procfwk].[Properties]
WHERE
[ValidTo] IS NULL;
================================================
FILE: MetadataDB/procfwk/Views/DataFactorys.sql
================================================
CREATE VIEW [procfwk].[DataFactorys]
AS
SELECT
[OrchestratorId] AS DataFactoryId,
[OrchestratorName] AS DataFactoryName,
[ResourceGroupName],
[SubscriptionId],
[Description]
FROM
[procfwk].[Orchestrators]
WHERE
[OrchestratorType] = 'ADF';
================================================
FILE: MetadataDB/procfwk/Views/PipelineParameterDataSizes.sql
================================================
CREATE VIEW [procfwk].[PipelineParameterDataSizes]
AS
SELECT
[PipelineId],
SUM(
(CAST(
DATALENGTH(
STRING_ESCAPE([ParameterName] + [ParameterValue],'json')) AS DECIMAL)
/1024) --KB
/1024 --MB
) AS Size
FROM
[procfwk].[PipelineParameters]
GROUP BY
[PipelineId];
================================================
FILE: MetadataDB/procfwkHelpers/Functions/CheckForValidURL.sql
================================================
CREATE FUNCTION [procfwkHelpers].[CheckForValidURL] (@Url NVARCHAR(MAX))
RETURNS INT
AS
BEGIN
DECLARE @Ending VARCHAR(50)
DECLARE @TempString VARCHAR(50)
--check URL start
IF CHARINDEX('https://', @Url) <> 1
BEGIN
RETURN 0;
END
--check for expected sub domains
IF CHARINDEX('vault.azure.net', @Url) = 0
BEGIN
RETURN 0;
END
--check for expected value type
IF CHARINDEX('secrets', @Url) = 0
BEGIN
RETURN 0;
END
--attempt to check for secret version
SELECT
@Ending =
CASE
WHEN RIGHT(@Url,1) = '/' THEN REVERSE(LEFT(@Url,LEN(@Url)-1))
ELSE REVERSE(@Url)
END,
@Ending = REVERSE(LEFT(@Ending,CHARINDEX('/',@Ending)-1))
IF LEN(@Ending) = 32
BEGIN
SET @TempString =
SUBSTRING(@Ending, 1, 8) + '-' +
SUBSTRING(@Ending, 9, 4) + '-' +
SUBSTRING(@Ending, 13, 4) + '-' +
SUBSTRING(@Ending, 13, 4) + '-' +
SUBSTRING(@Ending, 20, 12)
END
IF TRY_CAST(@TempString AS UNIQUEIDENTIFIER) IS NOT NULL
BEGIN
RETURN 0;
END;
-- It is a valid URL
RETURN 1;
END;
================================================
FILE: MetadataDB/procfwkHelpers/Stored Procedures/AddPipelineDependant.sql
================================================
CREATE PROCEDURE [procfwkHelpers].[AddPipelineDependant]
(
@PipelineName NVARCHAR(200),
@DependantPipelineName NVARCHAR(200)
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @PipelineId INT;
DECLARE @DependantPipelineId INT;
--get pipeline ids
SELECT
@PipelineId = [PipelineId]
FROM
[procfwk].[Pipelines]
WHERE
[PipelineName] = @PipelineName;
SELECT
@DependantPipelineId = [PipelineId]
FROM
[procfwk].[Pipelines]
WHERE
[PipelineName] = @DependantPipelineName;
--defensive checks
IF @PipelineId IS NULL
BEGIN
RAISERROR('Pipeline not found in pipelines table.', 16,1);
RETURN 0;
END;
IF @DependantPipelineId IS NULL
BEGIN
RAISERROR('Dependant pipeline not found in pipelines table.', 16,1);
RETURN 0;
END;
IF @PipelineId = @DependantPipelineId
BEGIN
RAISERROR('Pipeline cannot be dependant on itself.', 16,1);
RETURN 0;
END;
IF EXISTS
(
SELECT
*
FROM
[procfwk].[Pipelines] pp
INNER JOIN [procfwk].[Pipelines] dp
ON dp.[PipelineId] = @DependantPipelineId
WHERE
pp.[PipelineId] = @PipelineId
AND pp.[StageId] = dp.[StageId]
)
BEGIN
RAISERROR('Pipeline and dependent pipeline cannot be in the same execution stage.', 16,1);
RETURN 0;
END;
--final soft check and insert
IF EXISTS
(
SELECT
*
FROM
[procfwk].[PipelineDependencies]
WHERE
[PipelineId] = @PipelineId
AND [DependantPipelineId] = @DependantPipelineId
)
BEGIN
PRINT 'Dependency already exists. Nothing added.'
RETURN 0;
END
ELSE
BEGIN
INSERT INTO [procfwk].[PipelineDependencies]
(
[PipelineId],
[DependantPipelineId]
)
VALUES
(
@PipelineId,
@DependantPipelineId
)
END;
END;
================================================
FILE: MetadataDB/procfwkHelpers/Stored Procedures/AddPipelineViaPowerShell.sql
================================================
CREATE PROCEDURE [procfwkHelpers].[AddPipelineViaPowerShell]
(
@ResourceGroup NVARCHAR(200),
@OrchestratorName NVARCHAR(200),
@OrchestratorType CHAR(3) = 'ADF',
@PipelineName NVARCHAR(200)
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @OrchestratorId INT
DECLARE @StageId INT
DECLARE @StageName VARCHAR(255) = 'PoShAdded'
--get/set orchestrator
IF EXISTS
(
SELECT * FROM [procfwk].[Orchestrators] WHERE [OrchestratorName] = @OrchestratorName AND [ResourceGroupName] = @ResourceGroup AND [OrchestratorType] = @OrchestratorType
)
BEGIN
SELECT @OrchestratorId = [OrchestratorId] FROM [procfwk].[Orchestrators] WHERE [OrchestratorName] = @OrchestratorName AND [ResourceGroupName] = @ResourceGroup AND [OrchestratorType] = @OrchestratorType;
END
ELSE
BEGIN
INSERT INTO [procfwk].[Orchestrators]
(
[OrchestratorName],
[OrchestratorType],
[ResourceGroupName],
[Description],
[SubscriptionId]
)
VALUES
(
@OrchestratorName,
@OrchestratorType,
@ResourceGroup,
'Added via PowerShell.',
'12345678-1234-1234-1234-012345678910'
)
SELECT
@OrchestratorId = SCOPE_IDENTITY();
END
--get/set stage
IF EXISTS
(
SELECT * FROM [procfwk].[Stages] WHERE [StageName] = @StageName
)
BEGIN
SELECT @StageId = [StageId] FROM [procfwk].[Stages] WHERE [StageName] = @StageName;
END;
ELSE
BEGIN
INSERT INTO [procfwk].[Stages]
(
[StageName],
[StageDescription],
[Enabled]
)
VALUES
(
@StageName,
'Added via PowerShell.',
1
);
SELECT
@StageId = SCOPE_IDENTITY();
END;
--upsert pipeline
;WITH sourceData AS
(
SELECT
@OrchestratorId AS OrchestratorId,
@PipelineName AS PipelineName,
@StageId AS StageId,
NULL AS LogicalPredecessorId,
1 AS [Enabled]
)
MERGE INTO [procfwk].[Pipelines] AS tgt
USING
sourceData AS src
ON tgt.[OrchestratorId] = src.[OrchestratorId]
AND tgt.[PipelineName] = src.[PipelineName]
WHEN MATCHED THEN
UPDATE
SET
tgt.[StageId] = src.[StageId],
tgt.[LogicalPredecessorId] = src.[LogicalPredecessorId],
tgt.[Enabled] = src.[Enabled]
WHEN NOT MATCHED BY TARGET THEN
INSERT
(
[OrchestratorId],
[StageId],
[PipelineName],
[LogicalPredecessorId],
[Enabled]
)
VALUES
(
src.[OrchestratorId],
src.[StageId],
src.[PipelineName],
src.[LogicalPredecessorId],
src.[Enabled]
);
END;
================================================
FILE: MetadataDB/procfwkHelpers/Stored Procedures/AddProperty.sql
================================================
CREATE PROCEDURE [procfwkHelpers].[AddProperty]
(
@PropertyName VARCHAR(128),
@PropertyValue NVARCHAR(MAX),
@Description NVARCHAR(MAX) = NULL
)
AS
BEGIN
SET NOCOUNT ON;
--defensive check
IF EXISTS
(
SELECT * FROM [procfwk].[Properties] WHERE [PropertyName] = @PropertyName AND [ValidTo] IS NOT NULL
)
AND NOT EXISTS
(
SELECT * FROM [procfwk].[Properties] WHERE [PropertyName] = @PropertyName AND [ValidTo] IS NULL
)
BEGIN
WITH lastValue AS
(
SELECT
[PropertyId],
ROW_NUMBER() OVER (PARTITION BY [PropertyName] ORDER BY [ValidTo] ASC) AS Rn
FROM
[procfwk].[Properties]
WHERE
[PropertyName] = @PropertyName
)
--reset property if valid to date has been incorrectly set
UPDATE
prop
SET
[ValidTo] = NULL
FROM
[procfwk].[Properties] prop
INNER JOIN lastValue
ON prop.[PropertyId] = lastValue.[PropertyId]
WHERE
lastValue.[Rn] = 1
END
--upsert property
;WITH sourceTable AS
(
SELECT
@PropertyName AS PropertyName,
@PropertyValue AS PropertyValue,
@Description AS [Description],
GETUTCDATE() AS StartEndDate
)
--insert new version of existing property from MERGE OUTPUT
INSERT INTO [procfwk].[Properties]
(
[PropertyName],
[PropertyValue],
[Description],
[ValidFrom]
)
SELECT
[PropertyName],
[PropertyValue],
[Description],
GETUTCDATE()
FROM
(
MERGE INTO
[procfwk].[Properties] targetTable
USING
sourceTable
ON sourceTable.[PropertyName] = targetTable.[PropertyName]
--set valid to date on existing property
WHEN MATCHED AND [ValidTo] IS NULL THEN
UPDATE
SET
targetTable.[ValidTo] = sourceTable.[StartEndDate]
--add new property
WHEN NOT MATCHED BY TARGET THEN
INSERT
(
[PropertyName],
[PropertyValue],
[Description],
[ValidFrom]
)
VALUES
(
sourceTable.[PropertyName],
sourceTable.[PropertyValue],
sourceTable.[Description],
sourceTable.[StartEndDate]
)
--for new entry of existing record
OUTPUT
$action AS [Action],
sourceTable.*
) AS MergeOutput
WHERE
MergeOutput.[Action] = 'UPDATE';
END;
================================================
FILE: MetadataDB/procfwkHelpers/Stored Procedures/AddRecipientPipelineAlerts.sql
================================================
CREATE PROCEDURE [procfwkHelpers].[AddRecipientPipelineAlerts]
(
@RecipientName VARCHAR(255),
@PipelineName NVARCHAR(200) = NULL,
@AlertForStatus NVARCHAR(500) = 'All'
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @ActualBitValue INT
DECLARE @SQL NVARCHAR(MAX) = ''
DECLARE @BitValue TABLE ([TotalBitValue] INT NOT NULL);
--get alert status bit value
SET @AlertForStatus = LTRIM(RTRIM(@AlertForStatus))
SET @AlertForStatus = REPLACE(@AlertForStatus,' ','')
SET @AlertForStatus = '''' + REPLACE(@AlertForStatus,',',''',''') + ''''
SET @SQL =
'
SELECT
SUM([BitValue]) AS ''TotalBitValue''
FROM
[procfwk].[AlertOutcomes]
WHERE
[PipelineOutcomeStatus] IN (' + @AlertForStatus + ')
'
INSERT INTO @BitValue ([TotalBitValue]) EXECUTE(@SQL)
SELECT @ActualBitValue = [TotalBitValue] FROM @BitValue
--set link table
IF @PipelineName IS NOT NULL
BEGIN
--add alert for specific pipeline if doesn't exist
INSERT INTO [procfwk].[PipelineAlertLink]
(
[PipelineId],
[RecipientId],
[OutcomesBitValue]
)
SELECT
p.[PipelineId],
r.[RecipientId],
@ActualBitValue
FROM
[procfwk].[Pipelines] p
INNER JOIN [procfwk].[Recipients] r
ON r.[Name] = @RecipientName
LEFT OUTER JOIN [procfwk].[PipelineAlertLink] al
ON p.[PipelineId] = al.[PipelineId]
AND r.[RecipientId] = al.[RecipientId]
WHERE
p.[PipelineName] = @PipelineName
AND al.[PipelineId] IS NULL
AND al.[RecipientId] IS NULL;
END
ELSE IF @PipelineName IS NULL
BEGIN
--remove and re-add alerts for all pipelines
DELETE
al
FROM
[procfwk].[PipelineAlertLink] al
INNER JOIN [procfwk].[Recipients] r
ON al.[RecipientId] = r.[RecipientId]
WHERE
r.[Name] = @RecipientName;
INSERT INTO [procfwk].[PipelineAlertLink]
(
[PipelineId],
[RecipientId],
[OutcomesBitValue]
)
SELECT
p.[PipelineId],
r.[RecipientId],
@ActualBitValue
FROM
[procfwk].[Recipients] r
CROSS JOIN [procfwk].[Pipelines] p
WHERE
r.[Name] = @RecipientName;
END;
END
================================================
FILE: MetadataDB/procfwkHelpers/Stored Procedures/AddServicePrincipal.sql
================================================
CREATE PROCEDURE [procfwkHelpers].[AddServicePrincipal]
(
@OrchestratorName NVARCHAR(200),
@OrchestratorType CHAR(3),
@PrincipalId NVARCHAR(256),
@PrincipalSecret NVARCHAR(MAX),
@SpecificPipelineName NVARCHAR(200) = NULL,
@PrincipalName NVARCHAR(256) = NULL
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @ErrorDetails NVARCHAR(500) = ''
DECLARE @CredentialId INT
DECLARE @LocalPrincipalId UNIQUEIDENTIFIER
--defensive checks
BEGIN TRY
SELECT --assigned to variable just to supress output of SELECT
@LocalPrincipalId = CAST(@PrincipalId AS UNIQUEIDENTIFIER)
END TRY
BEGIN CATCH
SET @ErrorDetails = 'Invalid @PrincipalId provided. The format must be a UNIQUEIDENTIFIER.'
RAISERROR(@ErrorDetails, 16, 1);
RETURN 0;
END CATCH
IF NOT EXISTS
(
SELECT [OrchestratorName] FROM [procfwk].[Orchestrators] WHERE [OrchestratorName] = @OrchestratorName AND [OrchestratorType] = @OrchestratorType
)
BEGIN
SET @ErrorDetails = 'Invalid Orchestrator name. Please ensure the Orchestrator metadata exists before trying to add authentication for it.'
RAISERROR(@ErrorDetails, 16, 1);
RETURN 0;
END
IF EXISTS
(
SELECT
*
FROM
[procfwk].[PipelineAuthLink] AL
INNER JOIN [procfwk].[Orchestrators] DF
ON AL.[OrchestratorId] = DF.[OrchestratorId]
INNER JOIN [procfwk].[Pipelines] PP
ON AL.[PipelineId] = PP.[PipelineId]
WHERE
DF.[OrchestratorName] = @OrchestratorName
AND DF.[OrchestratorType] = @OrchestratorType
AND PP.[PipelineName] = @SpecificPipelineName
)
BEGIN
SET @ErrorDetails = 'The provided Pipeline or Orchestrator combination already have a Service Principal. Delete the existing record using the procedure [procfwk].[DeleteServicePrincipal].'
RAISERROR(@ErrorDetails, 16, 1);
RETURN 0;
END
--add SPN for specific pipeline
IF @SpecificPipelineName IS NOT NULL
BEGIN
--secondary defensive check for pipeline optional param
IF NOT EXISTS
(
SELECT [PipelineName] FROM [procfwk].[Pipelines] WHERE [PipelineName] = @SpecificPipelineName
)
BEGIN
SET @ErrorDetails = 'Invalid Pipeline name. Please ensure the Pipeline metadata exists before trying to add authentication for it.'
RAISERROR(@ErrorDetails, 16, 1);
RETURN 0;
END
--spn may already exist for other pipelines
IF NOT EXISTS
(
SELECT [PrincipalId] FROM [dbo].[ServicePrincipals] WHERE [PrincipalId] = @PrincipalId
)
BEGIN
--add service principal
INSERT INTO [dbo].[ServicePrincipals]
(
[PrincipalName],
[PrincipalId],
[PrincipalSecret]
)
SELECT
ISNULL(@PrincipalName, 'Unknown'),
@PrincipalId,
ENCRYPTBYPASSPHRASE(CONCAT(@OrchestratorName, @OrchestratorType, @SpecificPipelineName), @PrincipalSecret)
SET @CredentialId = SCOPE_IDENTITY()
END
ELSE
BEGIN
SELECT @CredentialId = [CredentialId] FROM [dbo].[ServicePrincipals] WHERE [PrincipalId] = @PrincipalId
END
--add single pipeline to SPN link
INSERT INTO [procfwk].[PipelineAuthLink]
(
[PipelineId],
[OrchestratorId],
[CredentialId]
)
SELECT
P.[PipelineId],
D.[OrchestratorId],
@CredentialId
FROM
[procfwk].[Pipelines] P
INNER JOIN [procfwk].[Orchestrators] D
ON P.[OrchestratorId] = D.[OrchestratorId]
WHERE
P.[PipelineName] = @SpecificPipelineName
AND D.[OrchestratorType] = @OrchestratorType
AND D.[OrchestratorName] = @OrchestratorName;
END
ELSE
--add SPN for all pipelines in Orchestrator
BEGIN
--add service principal
INSERT INTO [dbo].[ServicePrincipals]
(
[PrincipalName],
[PrincipalId],
[PrincipalSecret]
)
SELECT
ISNULL(@PrincipalName, 'Unknown'),
@PrincipalId,
ENCRYPTBYPASSPHRASE(CONCAT(@OrchestratorName, @OrchestratorType), @PrincipalSecret)
SET @CredentialId = SCOPE_IDENTITY()
--add link
INSERT INTO [procfwk].[PipelineAuthLink]
(
[PipelineId],
[OrchestratorId],
[CredentialId]
)
SELECT
P.[PipelineId],
D.[OrchestratorId],
@CredentialId
FROM
[procfwk].[Pipelines] P
INNER JOIN [procfwk].[Orchestrators] D
ON P.[OrchestratorId] = D.[OrchestratorId]
LEFT OUTER JOIN [procfwk].[PipelineAuthLink] L
ON P.[PipelineId] = L.[PipelineId]
WHERE
D.[OrchestratorName] = @OrchestratorName
AND D.[OrchestratorType] = @OrchestratorType
AND L.[PipelineId] IS NULL;
END
END;
================================================
FILE: MetadataDB/procfwkHelpers/Stored Procedures/AddServicePrincipalUrls.sql
================================================
CREATE PROCEDURE [procfwkHelpers].[AddServicePrincipalUrls]
(
@OrchestratorName NVARCHAR(200),
@OrchestratorType CHAR(3),
@PrincipalIdUrl NVARCHAR(MAX),
@PrincipalSecretUrl NVARCHAR(MAX),
@SpecificPipelineName NVARCHAR(200) = NULL,
@PrincipalName NVARCHAR(256) = NULL
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @ErrorDetails NVARCHAR(500) = ''
DECLARE @CredentialId INT
--defensive checks
IF NOT EXISTS
(
SELECT [OrchestratorName] FROM [procfwk].[Orchestrators] WHERE [OrchestratorName] = @OrchestratorName AND [OrchestratorType] = @OrchestratorType
)
BEGIN
SET @ErrorDetails = 'Invalid Orchestrator name. Please ensure the Orchestrator metadata exists before trying to add authentication for it.'
RAISERROR(@ErrorDetails, 16, 1);
RETURN 0;
END
IF EXISTS
(
SELECT
*
FROM
[procfwk].[PipelineAuthLink] AL
INNER JOIN [procfwk].[Orchestrators] DF
ON AL.[OrchestratorId] = DF.[OrchestratorId]
INNER JOIN [procfwk].[Pipelines] PP
ON AL.[PipelineId] = PP.[PipelineId]
WHERE
DF.[OrchestratorName] = @OrchestratorName
AND DF.[OrchestratorType] = @OrchestratorType
AND PP.[PipelineName] = @SpecificPipelineName
)
BEGIN
SET @ErrorDetails = 'The provided Pipeline or Orchestrator combination already have a Service Principal. Delete the existing record using the procedure [procfwk].[DeleteServicePrincipal].'
RAISERROR(@ErrorDetails, 16, 1);
RETURN 0;
END
IF ([procfwkHelpers].[CheckForValidURL](@PrincipalIdUrl)) = 0
BEGIN
SET @ErrorDetails = 'PrincipalIdUrl value is not in the expected format. . Please confirm the URL follows the structure https://{YourKeyVaultName}.vault.azure.net/secrets/{YourSecretName} and does not include the secret version guid.'
PRINT @ErrorDetails;
END
IF ([procfwkHelpers].[CheckForValidURL](@PrincipalSecretUrl)) = 0
BEGIN
SET @ErrorDetails = 'PrincipalSecretUrl value is not in the expected format. Please confirm the URL follows the structure https://{YourKeyVaultName}.vault.azure.net/secrets/{YourSecretName} and does not include the secret version guid.'
PRINT @ErrorDetails;
END
--add SPN for specific pipeline
IF @SpecificPipelineName IS NOT NULL
BEGIN
--secondary defensive check for pipeline optional param
IF NOT EXISTS
(
SELECT [PipelineName] FROM [procfwk].[Pipelines] WHERE [PipelineName] = @SpecificPipelineName
)
BEGIN
SET @ErrorDetails = 'Invalid Pipeline name. Please ensure the Pipeline metadata exists before trying to add authentication for it.'
RAISERROR(@ErrorDetails, 16, 1);
RETURN 0;
END
--spn may already exist for other pipelines
IF NOT EXISTS
(
SELECT [PrincipalIdUrl] FROM [dbo].[ServicePrincipals] WHERE [PrincipalIdUrl] = @PrincipalIdUrl
)
BEGIN
--add service principal
INSERT INTO [dbo].[ServicePrincipals]
(
[PrincipalName],
[PrincipalIdUrl],
[PrincipalSecretUrl]
)
SELECT
ISNULL(@PrincipalName, 'Unknown'),
@PrincipalIdUrl,
@PrincipalSecretUrl
SET @CredentialId = SCOPE_IDENTITY()
END
ELSE
BEGIN
SELECT @CredentialId = [CredentialId] FROM [dbo].[ServicePrincipals] WHERE [PrincipalIdUrl] = @PrincipalIdUrl
END
--add single pipeline to SPN link
INSERT INTO [procfwk].[PipelineAuthLink]
(
[PipelineId],
[OrchestratorId],
[CredentialId]
)
SELECT
P.[PipelineId],
D.[OrchestratorId],
@CredentialId
FROM
[procfwk].[Pipelines] P
INNER JOIN [procfwk].[Orchestrators] D
ON P.[OrchestratorId] = D.[OrchestratorId]
WHERE
P.[PipelineName] = @SpecificPipelineName
AND D.[OrchestratorType] = @OrchestratorType
AND D.[OrchestratorName] = @OrchestratorName;
END
ELSE
--add SPN for all pipelines in Orchestrator
BEGIN
--add service principal
INSERT INTO [dbo].[ServicePrincipals]
(
[PrincipalName],
[PrincipalIdUrl],
[PrincipalSecretUrl]
)
SELECT
ISNULL(@PrincipalName, 'Unknown'),
@PrincipalIdUrl,
@PrincipalSecretUrl
SET @CredentialId = SCOPE_IDENTITY()
--add link
INSERT INTO [procfwk].[PipelineAuthLink]
(
[PipelineId],
[OrchestratorId],
[CredentialId]
)
SELECT
P.[PipelineId],
D.[OrchestratorId],
@CredentialId
FROM
[procfwk].[Pipelines] P
INNER JOIN [procfwk].[Orchestrators] D
ON P.[OrchestratorId] = D.[OrchestratorId]
LEFT OUTER JOIN [procfwk].[PipelineAuthLink] L
ON P.[PipelineId] = L.[PipelineId]
WHERE
D.[OrchestratorName] = @OrchestratorName
AND D.[OrchestratorType] = @OrchestratorType
AND L.[PipelineId] IS NULL;
END
END;
================================================
FILE: MetadataDB/procfwkHelpers/Stored Procedures/AddServicePrincipalWrapper.sql
================================================
CREATE PROCEDURE [procfwkHelpers].[AddServicePrincipalWrapper]
(
@OrchestratorName NVARCHAR(200),
@OrchestratorType CHAR(3),
@PrincipalIdValue NVARCHAR(MAX),
@PrincipalSecretValue NVARCHAR(MAX),
@SpecificPipelineName NVARCHAR(200) = NULL,
@PrincipalName NVARCHAR(256) = NULL
)
AS
BEGIN
IF ([procfwk].[GetPropertyValueInternal]('SPNHandlingMethod')) = 'StoreInDatabase'
BEGIN
EXEC [procfwk].[AddServicePrincipal]
@OrchestratorName = @OrchestratorName,
@OrchestratorType = @OrchestratorType,
@PrincipalId = @PrincipalIdValue,
@PrincipalSecret = @PrincipalSecretValue,
@PrincipalName = @PrincipalName,
@SpecificPipelineName = @SpecificPipelineName
END
ELSE IF ([procfwk].[GetPropertyValueInternal]('SPNHandlingMethod')) = 'StoreInKeyVault'
BEGIN
EXEC [procfwk].[AddServicePrincipalUrls]
@OrchestratorName = @OrchestratorName,
@OrchestratorType = @OrchestratorType,
@PrincipalIdUrl = @PrincipalIdValue,
@PrincipalSecretUrl = @PrincipalSecretValue,
@PrincipalName = @PrincipalName,
@SpecificPipelineName = @SpecificPipelineName
END
ELSE
BEGIN
RAISERROR('Unknown SPN insert method.',16,1);
RETURN 0;
END
END;
================================================
FILE: MetadataDB/procfwkHelpers/Stored Procedures/CheckStageAndPiplineIntegrity.sql
================================================
CREATE PROCEDURE [procfwkHelpers].[CheckStageAndPiplineIntegrity]
AS
BEGIN
DECLARE @TempCheckStageAndPiplineIntegrity TABLE
(
[ResourceGroupName] NVARCHAR(200) NOT NULL,
[OrchestratorName] NVARCHAR(200) NOT NULL,
[StageId] INT NOT NULL,
[StageName] VARCHAR(225) NOT NULL,
[PipelineId] INT NOT NULL,
[PipelineName] NVARCHAR(200) NOT NULL,
[Enabled] BIT NOT NULL,
[SuccessorStageId] INT NULL,
[SuccessorStage] VARCHAR(225) NULL,
[SuccessorId] INT NULL,
[SuccessorName] NVARCHAR(200) NULL,
[Information] VARCHAR(92) NULL
)
--get min execution stage
;WITH firstStage AS
(
SELECT
MIN([StageId]) AS firstStageId
FROM
[procfwk].[Stages]
)
--query metadata
INSERT INTO @TempCheckStageAndPiplineIntegrity
SELECT
adf.[ResourceGroupName],
adf.[OrchestratorName],
base.[StageId],
baseStage.[StageName],
base.[PipelineId],
base.[PipelineName],
base.[Enabled],
preds.[StageId] AS SuccessorStageId,
predsStage.[StageName] AS SuccessorStage,
preds.[PipelineId] AS SuccessorId,
preds.[PipelineName] AS SuccessorName,
CASE
WHEN preds.[StageId] > base.[StageId] +1 THEN 'Successor pipeline could be moved to an earlier stage.'
WHEN preds.[StageId] = base.[StageId] THEN 'Dependency issue, predeccessor pipeline is currently running in the same stage as successor.'
WHEN preds.[PipelineId] IS NOT NULL AND base.[Enabled] = 0 THEN 'Disabled pipeline has downstream successors.'
WHEN preds.[PipelineId] IS NOT NULL AND baseStage.[Enabled] = 0 THEN 'Disabled stage has downstream successors.'
WHEN base.[LogicalPredecessorId] IS NULL AND base.[StageId] <> firstStage.[firstStageId] THEN 'Pipeline could be moved to an earlier stage.'
ELSE NULL
END AS Information
FROM
--get base pipeline details
[procfwk].[Pipelines] base
INNER JOIN [procfwk].[Orchestrators] adf
ON base.[OrchestratorId] = adf.[OrchestratorId]
INNER JOIN [procfwk].[Stages] baseStage
ON base.[StageId] = baseStage.[StageId]
--get successor details
LEFT OUTER JOIN [procfwk].[Pipelines] preds
ON base.[PipelineId] = preds.[LogicalPredecessorId]
LEFT OUTER JOIN [procfwk].[Stages] predsStage
ON preds.[StageId] = predsStage.[StageId]
--other details for checking
CROSS JOIN firstStage
--provide outcome
IF EXISTS
(
SELECT [Information] FROM @TempCheckStageAndPiplineIntegrity
)
BEGIN
SELECT * FROM @TempCheckStageAndPiplineIntegrity
END
ELSE
BEGIN
PRINT 'No pipeline integrity issues to report. Nice work! :-)'
END
END;
================================================
FILE: MetadataDB/procfwkHelpers/Stored Procedures/DeleteMetadataWithIntegrity.sql
================================================
CREATE PROCEDURE [procfwkHelpers].[DeleteMetadataWithIntegrity]
AS
BEGIN
/*
DELETE ORDER IMPORTANT FOR REFERENTIAL INTEGRITY
*/
--BatchExecution
IF OBJECT_ID(N'[procfwk].[BatchExecution]') IS NOT NULL
BEGIN
TRUNCATE TABLE [procfwk].[BatchExecution];
END;
--CurrentExecution
IF OBJECT_ID(N'[procfwk].[CurrentExecution]') IS NOT NULL
BEGIN
TRUNCATE TABLE [procfwk].[CurrentExecution];
END;
--ExecutionLog
IF OBJECT_ID(N'[procfwk].[ExecutionLog]') IS NOT NULL
BEGIN
TRUNCATE TABLE [procfwk].[ExecutionLog];
END
--ErrorLog
IF OBJECT_ID(N'[procfwk].[ExecutionLog]') IS NOT NULL
BEGIN
TRUNCATE TABLE [procfwk].[ErrorLog];
END
--BatchStageLink
IF OBJECT_ID(N'[procfwk].[BatchStageLink]') IS NOT NULL
BEGIN
DELETE FROM [procfwk].[BatchStageLink];
END;
--Batches
IF OBJECT_ID(N'[procfwk].[Batches]') IS NOT NULL
BEGIN
DELETE FROM [procfwk].[Batches];
END;
--PipelineDependencies
IF OBJECT_ID(N'[procfwk].[PipelineDependencies]') IS NOT NULL
BEGIN
DELETE FROM [procfwk].[PipelineDependencies];
DBCC CHECKIDENT ('[procfwk].[PipelineDependencies]', RESEED, 0);
END;
--PipelineAlertLink
IF OBJECT_ID(N'[procfwk].[PipelineAlertLink]') IS NOT NULL
BEGIN
DELETE FROM [procfwk].[PipelineAlertLink];
DBCC CHECKIDENT ('[procfwk].[PipelineAlertLink]', RESEED, 0);
END;
--Recipients
IF OBJECT_ID(N'[procfwk].[Recipients]') IS NOT NULL
BEGIN
DELETE FROM [procfwk].[Recipients];
DBCC CHECKIDENT ('[procfwk].[Recipients]', RESEED, 0);
END;
--AlertOutcomes
IF OBJECT_ID(N'[procfwk].[AlertOutcomes]') IS NOT NULL
BEGIN
TRUNCATE TABLE [procfwk].[AlertOutcomes];
END;
--PipelineAuthLink
IF OBJECT_ID(N'[procfwk].[PipelineAuthLink]') IS NOT NULL
BEGIN
DELETE FROM [procfwk].[PipelineAuthLink];
DBCC CHECKIDENT ('[procfwk].[PipelineAuthLink]', RESEED, 0);
END;
--ServicePrincipals
IF OBJECT_ID(N'[dbo].[ServicePrincipals]') IS NOT NULL
BEGIN
DELETE FROM [dbo].[ServicePrincipals];
DBCC CHECKIDENT ('[dbo].[ServicePrincipals]', RESEED, 0);
END;
--Properties
IF OBJECT_ID(N'[procfwk].[Properties]') IS NOT NULL
BEGIN
DELETE FROM [procfwk].[Properties];
DBCC CHECKIDENT ('[procfwk].[Properties]', RESEED, 0);
END;
--PipelineParameters
IF OBJECT_ID(N'[procfwk].[PipelineParameters]') IS NOT NULL
BEGIN
DELETE FROM [procfwk].[PipelineParameters];
DBCC CHECKIDENT ('[procfwk].[PipelineParameters]', RESEED, 0);
END;
--Pipelines
IF OBJECT_ID(N'[procfwk].[Pipelines]') IS NOT NULL
BEGIN
DELETE FROM [procfwk].[Pipelines];
DBCC CHECKIDENT ('[procfwk].[Pipelines]', RESEED, 0);
END;
--Orchestrators
IF OBJECT_ID(N'[procfwk].[Orchestrators]') IS NOT NULL
BEGIN
DELETE FROM [procfwk].[Orchestrators];
DBCC CHECKIDENT ('[procfwk].[Orchestrators]', RESEED, 0);
END;
--Stages
IF OBJECT_ID(N'[procfwk].[Stages]') IS NOT NULL
BEGIN
DELETE FROM [procfwk].[Stages];
DBCC CHECKIDENT ('[procfwk].[Stages]', RESEED, 0);
END;
--Subscriptions
IF OBJECT_ID(N'[procfwk].[Subscriptions]') IS NOT NULL
BEGIN
DELETE FROM [procfwk].[Subscriptions];
END;
--Tenants
IF OBJECT_ID(N'[procfwk].[Tenants]') IS NOT NULL
BEGIN
DELETE FROM [procfwk].[Tenants];
END;
END;
================================================
FILE: MetadataDB/procfwkHelpers/Stored Procedures/DeleteMetadataWithoutIntegrity.sql
================================================
CREATE PROCEDURE [procfwkHelpers].[DeleteMetadataWithoutIntegrity]
AS
BEGIN
DECLARE @SQL NVARCHAR(MAX) = ''
;WITH procfwkTables AS
(
SELECT
QUOTENAME(s.[name]) + '.' + QUOTENAME(o.[name]) AS FullName
FROM
sys.objects o
INNER JOIN sys.schemas s
ON o.[schema_id] = s.[schema_id]
WHERE
s.[name] LIKE 'procfwk%'
AND o.[type] = 'U'
UNION
SELECT
QUOTENAME(s.[name]) + '.' + QUOTENAME(o.[name]) AS FullName
FROM
sys.objects o
INNER JOIN sys.schemas s
ON o.[schema_id] = s.[schema_id]
WHERE
o.[name] = 'ServicePrincipals'
AND o.[type] = 'U'
)
SELECT --tables must exist or wouldnt appear in sys.objects query
@SQL += 'DELETE FROM ' + [FullName] + ';' + CHAR(13)
FROM
procfwkTables
EXEC(@SQL);
END;
================================================
FILE: MetadataDB/procfwkHelpers/Stored Procedures/DeleteRecipientAlerts.sql
================================================
CREATE PROCEDURE [procfwkHelpers].[DeleteRecipientAlerts]
(
@EmailAddress NVARCHAR(500),
@SoftDeleteOnly BIT = 1
)
AS
BEGIN
SET NOCOUNT ON;
--defensive check
IF NOT EXISTS
(
SELECT [RecipientId] FROM [procfwk].[Recipients] WHERE [EmailAddress] = @EmailAddress
)
BEGIN
RAISERROR('Recipient email address does not exists in [procfwk].[Recipients] table.',16,1);
RETURN 0;
END;
--update/delete
IF @SoftDeleteOnly = 1
BEGIN
--disable links
UPDATE
al
SET
al.[Enabled] = 0
FROM
[procfwk].[PipelineAlertLink] al
INNER JOIN [procfwk].[Recipients] r
ON al.[RecipientId] = r.[RecipientId]
WHERE
r.[EmailAddress] = @EmailAddress;
--disable recipient(s)
UPDATE
[procfwk].[Recipients]
SET
[Enabled] = 0
WHERE
[EmailAddress] = @EmailAddress;
END
ELSE
BEGIN
--delete links
DELETE
al
FROM
[procfwk].[PipelineAlertLink] al
INNER JOIN [procfwk].[Recipients] r
ON al.[RecipientId] = r.[RecipientId]
WHERE
r.[EmailAddress] = @EmailAddress;
--delete recipient(s)
DELETE FROM
[procfwk].[Recipients]
WHERE
[EmailAddress] = @EmailAddress;
END;
END;
================================================
FILE: MetadataDB/procfwkHelpers/Stored Procedures/DeleteServicePrincipal.sql
================================================
CREATE PROCEDURE [procfwkHelpers].[DeleteServicePrincipal]
(
@OrchestratorName NVARCHAR(200),
@OrchestratorType CHAR(3),
@PrincipalIdValue NVARCHAR(256),
@SpecificPipelineName NVARCHAR(200) = NULL
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @ErrorDetails NVARCHAR(500) = ''
DECLARE @CredentialId INT
--resolve principal Id or Url to credential Id
IF ([procfwk].[GetPropertyValueInternal]('SPNHandlingMethod')) = 'StoreInDatabase'
BEGIN
--defensive checks
BEGIN TRY
DECLARE @LocalPrincipalId UNIQUEIDENTIFIER
SELECT --assigned to variable just to supress output of SELECT
@LocalPrincipalId = CAST(@PrincipalIdValue AS UNIQUEIDENTIFIER)
END TRY
BEGIN CATCH
SET @ErrorDetails = 'Invalid @PrincipalId provided. The format must be a UNIQUEIDENTIFIER.'
RAISERROR(@ErrorDetails, 16, 1);
RETURN 0;
END CATCH
--get cred id using principal id
SELECT
@CredentialId = [CredentialId]
FROM
[dbo].[ServicePrincipals]
WHERE
[PrincipalId] = @PrincipalIdValue
END
ELSE IF ([procfwk].[GetPropertyValueInternal]('SPNHandlingMethod')) = 'StoreInKeyVault'
BEGIN
--get cred id using principal id url
SELECT
@CredentialId = [CredentialId]
FROM
[dbo].[ServicePrincipals]
WHERE
[PrincipalIdUrl] = @PrincipalIdValue
END;
ELSE
BEGIN
RAISERROR('Unknown SPN deletion method.',16,1);
RETURN 0;
END;
--secondary defensive checks
IF NOT EXISTS
(
SELECT [OrchestratorName] FROM [procfwk].[Orchestrators] WHERE [OrchestratorName] = @OrchestratorName AND [OrchestratorType] = @OrchestratorType
)
BEGIN
SET @ErrorDetails = 'Invalid Orchestrator name. Please ensure the Orchestrator metadata exists.'
RAISERROR(@ErrorDetails, 16, 1);
RETURN 0;
END
IF @CredentialId IS NULL
BEGIN
SET @ErrorDetails = 'Invalid Service Principal Id Value provided. Please ensure the Service Principal exists.'
RAISERROR(@ErrorDetails, 16, 1);
RETURN 0;
END
--delete SPN for specific pipeline
IF @SpecificPipelineName IS NOT NULL
BEGIN
IF NOT EXISTS
(
SELECT [PipelineName] FROM [procfwk].[Pipelines] WHERE [PipelineName] = @SpecificPipelineName
)
BEGIN
SET @ErrorDetails = 'Invalid Pipeline name. Please ensure the Pipeline metadata exists.'
RAISERROR(@ErrorDetails, 16, 1);
RETURN 0;
END
--delete links
DELETE
L
FROM
[procfwk].[PipelineAuthLink] L
INNER JOIN [procfwk].[Pipelines] P
ON L.[PipelineId] = P.[PipelineId]
INNER JOIN [procfwk].[Orchestrators] D
ON P.[OrchestratorId] = D.[OrchestratorId]
AND L.[OrchestratorId] = D.[OrchestratorId]
INNER JOIN [dbo].[ServicePrincipals] S
ON L.[CredentialId] = S.[CredentialId]
WHERE
P.[PipelineName] = @SpecificPipelineName
AND D.[OrchestratorName] = @OrchestratorName
AND D.[OrchestratorType] = @OrchestratorType
AND S.[CredentialId] = @CredentialId;
END
ELSE
BEGIN
--delete links
DELETE
L
FROM
[procfwk].[PipelineAuthLink] L
INNER JOIN [procfwk].[Orchestrators] D
ON L.[OrchestratorId] = D.[OrchestratorId]
INNER JOIN [dbo].[ServicePrincipals] S
ON L.[CredentialId] = S.[CredentialId]
WHERE
D.[OrchestratorName] = @OrchestratorName
AND D.[OrchestratorType] = @OrchestratorType
AND S.[CredentialId] = @CredentialId;
END
--finall, delete principal only if not still used by other pipelines
DELETE
SP
FROM
[dbo].[ServicePrincipals] SP
LEFT OUTER JOIN [procfwk].[PipelineAuthLink] AL
ON SP.[CredentialId] = AL.[CredentialId]
WHERE
SP.[CredentialId] = @CredentialId
AND AL.[CredentialId] IS NULL;
END;
================================================
FILE: MetadataDB/procfwkHelpers/Stored Procedures/GetExecutionDetails.sql
================================================
CREATE PROCEDURE [procfwkHelpers].[GetExecutionDetails]
(
@LocalExecutionId UNIQUEIDENTIFIER = NULL
)
AS
BEGIN
--Get last execution ID
IF @LocalExecutionId IS NULL
BEGIN
WITH maxLog AS
(
SELECT
MAX([LogId]) AS MaxLogId
FROM
[procfwk].[ExecutionLog]
)
SELECT
@LocalExecutionId = el1.[LocalExecutionId]
FROM
[procfwk].[ExecutionLog] el1
INNER JOIN maxLog
ON maxLog.[MaxLogId] = el1.[LogId];
END;
--Execution Summary
SELECT
CAST(el2.[StageId] AS VARCHAR(5)) + ' - ' + stgs.[StageName] AS Stage,
COUNT(0) AS RecordCount,
DATEDIFF(MINUTE, MIN(el2.[StartDateTime]), MAX(el2.[EndDateTime])) DurationMinutes
FROM
[procfwk].[ExecutionLog] el2
INNER JOIN [procfwk].[Stages] stgs
ON el2.[StageId] = stgs.[StageId]
WHERE
el2.[LocalExecutionId] = @LocalExecutionId
GROUP BY
CAST(el2.[StageId] AS VARCHAR(5)) + ' - ' + stgs.[StageName]
ORDER BY
CAST(el2.[StageId] AS VARCHAR(5)) + ' - ' + stgs.[StageName];
--Full execution details
SELECT
el3.[LogId],
el3.[LocalExecutionId],
el3.[OrchestratorType],
el3.[OrchestratorName],
el3.[StageId],
stgs.[StageName],
el3.[PipelineId],
el3.[PipelineName],
el3.[StartDateTime],
el3.[EndDateTime],
ISNULL(DATEDIFF(MINUTE, el3.[StartDateTime], el3.[EndDateTime]),0) AS DurationMinutes,
el3.[PipelineStatus],
el3.[PipelineRunId],
el3.[PipelineParamsUsed],
errLog.[ActivityRunId],
errLog.[ActivityName],
errLog.[ActivityType],
errLog.[ErrorCode],
errLog.[ErrorType],
errLog.[ErrorMessage]
FROM
[procfwk].[ExecutionLog] el3
LEFT OUTER JOIN [procfwk].[ErrorLog] errLog
ON el3.[LocalExecutionId] = errLog.[LocalExecutionId]
AND el3.[PipelineRunId] = errLog.[PipelineRunId]
INNER JOIN [procfwk].[Stages] stgs
ON el3.[StageId] = stgs.[StageId]
WHERE
el3.[LocalExecutionId] = @LocalExecutionId
ORDER BY
el3.[PipelineId],
el3.[StartDateTime];
END;
================================================
FILE: MetadataDB/procfwkHelpers/Stored Procedures/GetServicePrincipal.sql
================================================
CREATE PROCEDURE [procfwkHelpers].[GetServicePrincipal]
(
@OrchestratorName NVARCHAR(200),
@OrchestratorType CHAR(3),
@PipelineName NVARCHAR(200) = NULL
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @Id NVARCHAR(MAX)
DECLARE @Secret NVARCHAR(MAX)
IF ([procfwk].[GetPropertyValueInternal]('SPNHandlingMethod')) = 'StoreInDatabase'
BEGIN
--get auth details regardless of being pipeline specific and regardless of a pipeline param being passed
;WITH cte AS
(
SELECT DISTINCT
S.[PrincipalId] AS Id,
CAST(DECRYPTBYPASSPHRASE(CONCAT(@OrchestratorName, @PipelineName), S.[PrincipalSecret]) AS NVARCHAR(MAX)) AS [Secret]
FROM
[dbo].[ServicePrincipals] S
INNER JOIN [procfwk].[PipelineAuthLink] L
ON S.[CredentialId] = L.[CredentialId]
INNER JOIN [procfwk].[Pipelines] P
ON L.[PipelineId] = P.[PipelineId]
INNER JOIN [procfwk].[Orchestrators] D
ON P.[OrchestratorId] = D.[OrchestratorId]
AND L.[OrchestratorId] = D.[OrchestratorId]
WHERE
P.[PipelineName] = @PipelineName
AND D.[OrchestratorName] = @OrchestratorName
AND D.[OrchestratorType] = @OrchestratorType
UNION
SELECT DISTINCT
S.[PrincipalId] AS Id,
CAST(DECRYPTBYPASSPHRASE(@OrchestratorName, S.[PrincipalSecret]) AS NVARCHAR(MAX)) AS [Secret]
FROM
[dbo].[ServicePrincipals] S
INNER JOIN [procfwk].[PipelineAuthLink] L
ON S.[CredentialId] = L.[CredentialId]
INNER JOIN [procfwk].[Orchestrators] D
ON L.[OrchestratorId] = D.[OrchestratorId]
WHERE
D.[OrchestratorName] = @OrchestratorName
AND D.[OrchestratorType] = @OrchestratorType
)
SELECT TOP 1
@Id = [Id],
@Secret = [Secret]
FROM
cte
WHERE
[Secret] IS NOT NULL
END
ELSE IF ([procfwk].[GetPropertyValueInternal]('SPNHandlingMethod')) = 'StoreInKeyVault'
BEGIN
--get auth details regardless of being pipeline specific and regardless of a pipeline param being passed
;WITH cte AS
(
SELECT DISTINCT
S.[PrincipalIdUrl] AS Id,
S.[PrincipalSecretUrl] AS [Secret]
FROM
[dbo].[ServicePrincipals] S
INNER JOIN [procfwk].[PipelineAuthLink] L
ON S.[CredentialId] = L.[CredentialId]
INNER JOIN [procfwk].[Pipelines] P
ON L.[PipelineId] = P.[PipelineId]
INNER JOIN [procfwk].[Orchestrators] D
ON P.[OrchestratorId] = D.[OrchestratorId]
AND L.[OrchestratorId] = D.[OrchestratorId]
WHERE
P.[PipelineName] = @PipelineName
AND D.[OrchestratorName] = @OrchestratorName
AND D.[OrchestratorType] = @OrchestratorType
UNION
SELECT DISTINCT
S.[PrincipalIdUrl] AS Id,
S.[PrincipalSecretUrl] AS [Secret]
FROM
[dbo].[ServicePrincipals] S
INNER JOIN [procfwk].[PipelineAuthLink] L
ON S.[CredentialId] = L.[CredentialId]
INNER JOIN [procfwk].[Orchestrators] D
ON L.[OrchestratorId] = D.[OrchestratorId]
WHERE
D.[OrchestratorName] = @OrchestratorName
AND D.[OrchestratorType] = @OrchestratorType
)
SELECT TOP 1
@Id = [Id],
@Secret = [Secret]
FROM
cte
WHERE
[Secret] IS NOT NULL
END
ELSE
BEGIN
RAISERROR('Unknown SPN retrieval method.',16,1);
RETURN 0;
END
--return usable values
SELECT
@Id AS Id,
@Secret AS [Secret]
END;
================================================
FILE: MetadataDB/procfwkHelpers/Stored Procedures/SetDefaultAlertOutcomes.sql
================================================
CREATE PROCEDURE [procfwkHelpers].[SetDefaultAlertOutcomes]
AS
BEGIN
TRUNCATE TABLE [procfwk].[AlertOutcomes];
INSERT INTO [procfwk].[AlertOutcomes]
(
[PipelineOutcomeStatus]
)
VALUES
('All'),
('Success'),
('Failed'),
('Unknown'),
('Cancelled');
END;
================================================
FILE: MetadataDB/procfwkHelpers/Stored Procedures/SetDefaultBatchStageLink.sql
================================================
CREATE PROCEDURE [procfwkHelpers].[SetDefaultBatchStageLink]
AS
BEGIN
TRUNCATE TABLE [procfwk].[BatchStageLink]
INSERT INTO [procfwk].[BatchStageLink]
(
[BatchId],
[StageId]
)
SELECT
b.[BatchId],
s.[StageId]
FROM
[procfwk].[Batches] b
INNER JOIN [procfwk].[Stages] s
ON s.[StageName] <> 'Speed'
WHERE
b.[BatchName] = 'Daily'
UNION ALL
SELECT
b.[BatchId],
s.[StageId]
FROM
[procfwk].[Batches] b
INNER JOIN [procfwk].[Stages] s
ON s.[StageName] = 'Speed'
WHERE
b.[BatchName] = 'Hourly'
END;
================================================
FILE: MetadataDB/procfwkHelpers/Stored Procedures/SetDefaultBatches.sql
================================================
CREATE PROCEDURE [procfwkHelpers].[SetDefaultBatches]
AS
BEGIN
DECLARE @Batches TABLE
(
[BatchName] [VARCHAR](225) NOT NULL,
[BatchDescription] [VARCHAR](4000) NULL,
[Enabled] [BIT] NOT NULL
)
INSERT @Batches
(
[BatchName],
[BatchDescription],
[Enabled]
)
VALUES
('Daily', N'Daily Worker Pipelines.', 1),
('Hourly', N'Hourly Worker Pipelines.', 1);
MERGE INTO [procfwk].[Batches] AS tgt
USING
@Batches AS src
ON tgt.[BatchName] = src.[BatchName]
WHEN MATCHED THEN
UPDATE
SET
tgt.[BatchDescription] = src.[BatchDescription],
tgt.[Enabled] = src.[Enabled]
WHEN NOT MATCHED BY TARGET THEN
INSERT
(
[BatchName],
[BatchDescription],
[Enabled]
)
VALUES
(
src.[BatchName],
src.[BatchDescription],
src.[Enabled]
)
WHEN NOT MATCHED BY SOURCE THEN
DELETE;
END;
================================================
FILE: MetadataDB/procfwkHelpers/Stored Procedures/SetDefaultOrchestrators.sql
================================================
CREATE PROCEDURE [procfwkHelpers].[SetDefaultOrchestrators]
AS
BEGIN
DECLARE @Orchestrators TABLE
(
[OrchestratorName] NVARCHAR(200) NOT NULL,
[OrchestratorType] CHAR(3) NOT NULL,
[IsFrameworkOrchestrator] BIT NOT NULL,
[ResourceGroupName] NVARCHAR(200) NOT NULL,
[SubscriptionId] UNIQUEIDENTIFIER NOT NULL,
[Description] NVARCHAR(MAX) NULL
)
INSERT INTO @Orchestrators
(
[OrchestratorName],
[OrchestratorType],
[IsFrameworkOrchestrator],
[Description],
[ResourceGroupName],
[SubscriptionId]
)
VALUES
('FrameworkFactory','ADF',1,'Example Data Factory used for development.','ADF.procfwk','12345678-1234-1234-1234-012345678910'),
('FrameworkFactoryDev','ADF',0,'Example Data Factory used for development deployments.','ADF.procfwk','12345678-1234-1234-1234-012345678910'),
('FrameworkFactoryTest','ADF',0,'Example Data Factory used for testing.','ADF.procfwk','12345678-1234-1234-1234-012345678910'),
('WorkersFactory','ADF',0,'Example Data Factory used to house worker pipelines.','ADF.procfwk','12345678-1234-1234-1234-012345678910'),
('procfwkforsynapse','SYN',0,'Example Synapse instance used to house all pipelines.','ADF.procfwk','12345678-1234-1234-1234-012345678910');
MERGE INTO [procfwk].[Orchestrators] AS tgt
USING
@Orchestrators AS src
ON tgt.[OrchestratorName] = src.[OrchestratorName]
AND tgt.[OrchestratorType] = src.[OrchestratorType]
WHEN MATCHED THEN
UPDATE
SET
tgt.[IsFrameworkOrchestrator] = src.[IsFrameworkOrchestrator],
tgt.[Description] = src.[Description],
tgt.[ResourceGroupName] = src.[ResourceGroupName],
tgt.[SubscriptionId] = src.[SubscriptionId]
WHEN NOT MATCHED BY TARGET THEN
INSERT
(
[OrchestratorName],
[OrchestratorType],
[IsFrameworkOrchestrator],
[Description],
[ResourceGroupName],
[SubscriptionId]
)
VALUES
(
src.[OrchestratorName],
src.[OrchestratorType],
src.[IsFrameworkOrchestrator],
src.[Description],
src.[ResourceGroupName],
src.[SubscriptionId]
)
WHEN NOT MATCHED BY SOURCE THEN
DELETE;
END;
================================================
FILE: MetadataDB/procfwkHelpers/Stored Procedures/SetDefaultPipelineDependants.sql
================================================
CREATE PROCEDURE [procfwkHelpers].[SetDefaultPipelineDependants]
AS
BEGIN
EXEC [procfwkHelpers].[AddPipelineDependant]
@PipelineName = 'Intentional Error',
@DependantPipelineName = 'Wait 5';
EXEC [procfwkHelpers].[AddPipelineDependant]
@PipelineName = 'Intentional Error',
@DependantPipelineName = 'Wait 6';
EXEC [procfwkHelpers].[AddPipelineDependant]
@PipelineName = 'Wait 6',
@DependantPipelineName = 'Wait 9';
EXEC [procfwkHelpers].[AddPipelineDependant]
@PipelineName = 'Wait 9',
@DependantPipelineName = 'Wait 10';
END;
================================================
FILE: MetadataDB/procfwkHelpers/Stored Procedures/SetDefaultPipelineParameters.sql
================================================
CREATE PROCEDURE [procfwkHelpers].[SetDefaultPipelineParameters]
AS
BEGIN
DECLARE @PipelineParameters TABLE
(
[PipelineId] [INT] NOT NULL,
[ParameterName] [VARCHAR](128) NOT NULL,
[ParameterValue] [NVARCHAR](MAX) NULL
)
INSERT @PipelineParameters
(
[PipelineId],
[ParameterName],
[ParameterValue]
)
VALUES
(1, 'WaitTime', '3'),
(2, 'WaitTime', '6'),
(6, 'WaitTime', '9'),
(4, 'WaitTime', '5'),
(5, 'WaitTime', '2'),
(3, 'RaiseErrors', 'false'),
(3, 'WaitTime', '10'),
(7, 'WaitTime', '3'),
(8, 'WaitTime', '5'),
(9, 'WaitTime', '7'),
(11, 'WaitTime', '10');
MERGE INTO [procfwk].[PipelineParameters] AS tgt
USING
@PipelineParameters AS src
ON tgt.[PipelineId] = src.[PipelineId]
AND tgt.[ParameterName] = src.[ParameterName]
WHEN MATCHED THEN
UPDATE
SET
tgt.[ParameterValue] = src.[ParameterValue]
WHEN NOT MATCHED BY TARGET THEN
INSERT
(
[PipelineId],
[ParameterName],
[ParameterValue]
)
VALUES
(
src.[PipelineId],
src.[ParameterName],
src.[ParameterValue]
)
WHEN NOT MATCHED BY SOURCE THEN
DELETE;
END;
================================================
FILE: MetadataDB/procfwkHelpers/Stored Procedures/SetDefaultPipelines.sql
================================================
CREATE PROCEDURE [procfwkHelpers].[SetDefaultPipelines]
AS
BEGIN
DECLARE @Pipelines TABLE
(
[OrchestratorId] [INT] NOT NULL,
[StageId] [INT] NOT NULL,
[PipelineName] [NVARCHAR](200) NOT NULL,
[LogicalPredecessorId] [INT] NULL,
[Enabled] [BIT] NOT NULL
)
INSERT @Pipelines
(
[OrchestratorId],
[StageId],
[PipelineName],
[LogicalPredecessorId],
[Enabled]
)
VALUES
(1,1 ,'Wait 1' ,NULL ,1),
(1,1 ,'Wait 2' ,NULL ,1),
(1,1 ,'Intentional Error' ,NULL ,1),
(1,1 ,'Wait 3' ,NULL ,1),
(1,2 ,'Wait 4' ,NULL ,1),
(1,2 ,'Wait 5' ,1 ,1),
(1,2 ,'Wait 6' ,1 ,1),
(1,2 ,'Wait 7' ,NULL ,1),
(1,3 ,'Wait 8' ,1 ,1),
(1,3 ,'Wait 9' ,6 ,1),
(1,4 ,'Wait 10' ,9 ,1),
--speed
(1,5 ,'Wait 1' ,NULL ,0),
(1,5 ,'Wait 2' ,NULL ,0),
(1,5 ,'Wait 3' ,NULL ,0),
(1,5 ,'Wait 4' ,NULL ,0),
--synapse
(5,1 ,'Wait 1' ,NULL ,1),
(5,1 ,'Wait 2' ,NULL ,1),
(5,1 ,'Wait 3' ,NULL ,1),
(5,1 ,'Wait 4' ,NULL ,1);
MERGE INTO [procfwk].[Pipelines] AS tgt
USING
@Pipelines AS src
ON tgt.[OrchestratorId] = src.[OrchestratorId]
AND tgt.[PipelineName] = src.[PipelineName]
AND tgt.[StageId] = src.[StageId]
WHEN MATCHED THEN
UPDATE
SET
tgt.[LogicalPredecessorId] = src.[LogicalPredecessorId],
tgt.[Enabled] = src.[Enabled]
WHEN NOT MATCHED BY TARGET THEN
INSERT
(
[OrchestratorId],
[StageId],
[PipelineName],
[LogicalPredecessorId],
[Enabled]
)
VALUES
(
src.[OrchestratorId],
src.[StageId],
src.[PipelineName],
src.[LogicalPredecessorId],
src.[Enabled]
)
WHEN NOT MATCHED BY SOURCE THEN
DELETE;
END;
================================================
FILE: MetadataDB/procfwkHelpers/Stored Procedures/SetDefaultProperties.sql
================================================
CREATE PROCEDURE [procfwkHelpers].[SetDefaultProperties]
AS
BEGIN
EXEC [procfwkHelpers].[AddProperty]
@PropertyName = N'OverideRestart',
@PropertyValue = N'0',
@Description = N'Should processing not be restarted from the point of failure or should a new execution will be created regardless. 1 = Start New, 0 = Restart. ';
EXEC [procfwkHelpers].[AddProperty]
@PropertyName = N'PipelineStatusCheckDuration',
@PropertyValue = N'30',
@Description = N'Duration applied to the Wait activity within the Infant pipeline Until iterations.';
EXEC [procfwkHelpers].[AddProperty]
@PropertyName = N'UnknownWorkerResultBlocks',
@PropertyValue = N'1',
@Description = N'If a worker pipeline returns an unknown status. Should this block and fail downstream pipeline? 1 = Yes, 0 = No.';
EXEC [procfwkHelpers].[AddProperty]
@PropertyName = N'CancelledWorkerResultBlocks',
@PropertyValue = N'1',
@Description = N'If a worker pipeline returns an cancelled status. Should this block and fail downstream pipeline? 1 = Yes, 0 = No.';
EXEC [procfwkHelpers].[AddProperty]
@PropertyName = N'UseFrameworkEmailAlerting',
@PropertyValue = N'0',
@Description = N'Do you want the framework to handle pipeline email alerts via the database metadata? 1 = Yes, 0 = No.';
EXEC [procfwkHelpers].[AddProperty]
@PropertyName = N'EmailAlertBodyTemplate',
@PropertyValue =
N'
Pipeline Name: ##PipelineName###
Status: ##Status###
Execution ID: ##ExecId###
Run ID: ##RunId###
Start Date Time: ##StartDateTime###
End Date Time: ##EndDateTime###
Duration (Minutes): ##Duration###
Called by Orchestrator: ##CalledByOrc###
Executed by Orchestrator Type: ##ExecutedByOrcType###
Executed by Orchestrator: ##ExecutedByOrc###
',
@Description = N'Basic HTML template of execution information used as the eventual body in email alerts sent.';
EXEC [procfwkHelpers].[AddProperty]
@PropertyName = N'FailureHandling',
@PropertyValue = N'Simple',
@Description = N'Accepted values: None, Simple, DependencyChain. Controls processing bahaviour in the event of Worker failures. See v1.8 release notes for full details.';
EXEC [procfwkHelpers].[AddProperty]
@PropertyName = N'SPNHandlingMethod',
@PropertyValue = N'StoreInDatabase',
@Description = N'Accepted values: StoreInDatabase, StoreInKeyVault. See v1.8.2 release notes for full details.';
EXEC [procfwkHelpers].[AddProperty]
@PropertyName = N'ExecutionPrecursorProc',
@PropertyValue = N'[dbo].[ExampleCustomExecutionPrecursor]',
@Description = N'This procedure will be called first in the parent pipeline and can be used to perform/update any required custom behaviour in the framework execution. For example, enable/disable Worker pipelines given a certain run time/day. Invalid proc name values will be ignored.'
EXEC [procfwkHelpers].[AddProperty]
@PropertyName = N'UseExecutionBatches',
@PropertyValue = N'0',
@Description = N'Establishes if execution batches are used as a level above execution stages within the framework. 1 = True, 0 = False.';
EXEC [procfwkHelpers].[AddProperty]
@PropertyName = N'FrameworkFactoryResourceGroup',
@PropertyValue = N'ADF.procfwk',
@Description = N'Supports various queries where the framework factory is inspecting itself and the resource group cant be inferred.';
EXEC [procfwkHelpers].[AddProperty]
@PropertyName = N'PreviousPipelineRunsQueryRange',
@PropertyValue = N'-1',
@Description = N'Used as a date range, today +- this value, when checking for if an execution for a given pipeline is already running. Must include +- symbol in value.';
END;
================================================
FILE: MetadataDB/procfwkHelpers/Stored Procedures/SetDefaultRecipientPipelineAlerts.sql
================================================
CREATE PROCEDURE [procfwkHelpers].[SetDefaultRecipientPipelineAlerts]
AS
BEGIN
EXEC [procfwkHelpers].[AddRecipientPipelineAlerts]
@RecipientName = N'Test User 1',
@AlertForStatus = 'All';
EXEC [procfwkHelpers].[AddRecipientPipelineAlerts]
@RecipientName = N'Test User 2',
@PipelineName = 'Intentional Error',
@AlertForStatus = 'Failed';
EXEC [procfwkHelpers].[AddRecipientPipelineAlerts]
@RecipientName = N'Test User 3',
@PipelineName = 'Wait 1',
@AlertForStatus = 'Success, Failed, Cancelled';
END;
================================================
FILE: MetadataDB/procfwkHelpers/Stored Procedures/SetDefaultRecipients.sql
================================================
CREATE PROCEDURE [procfwkHelpers].[SetDefaultRecipients]
AS
BEGIN
DECLARE @Recipients TABLE
(
[Name] [VARCHAR](255) NULL,
[EmailAddress] [NVARCHAR](500) NOT NULL,
[MessagePreference] [CHAR](3) NOT NULL,
[Enabled] [BIT] NOT NULL
)
INSERT INTO @Recipients
(
[Name],
[EmailAddress],
[MessagePreference],
[Enabled]
)
VALUES
('Test User 1','test.user1@adfprocfwk.com', 'TO', 1),
('Test User 2','test.user2@adfprocfwk.com', 'CC', 1),
('Test User 3','test.user3@adfprocfwk.com', 'BCC', 1);
MERGE INTO [procfwk].[Recipients] AS tgt
USING
@Recipients AS src
ON tgt.[Name] = src.[Name]
WHEN MATCHED THEN
UPDATE
SET
tgt.[EmailAddress] = src.[EmailAddress],
tgt.[MessagePreference] = src.[MessagePreference],
tgt.[Enabled] = src.[Enabled]
WHEN NOT MATCHED BY TARGET THEN
INSERT
(
[Name],
[EmailAddress],
[MessagePreference],
[Enabled]
)
VALUES
(
src.[Name],
src.[EmailAddress],
src.[MessagePreference],
src.[Enabled]
)
WHEN NOT MATCHED BY SOURCE THEN
DELETE;
END;
================================================
FILE: MetadataDB/procfwkHelpers/Stored Procedures/SetDefaultStages.sql
================================================
CREATE PROCEDURE [procfwkHelpers].[SetDefaultStages]
AS
BEGIN
DECLARE @Stages TABLE
(
[StageName] [VARCHAR](225) NOT NULL,
[StageDescription] [VARCHAR](4000) NULL,
[Enabled] [BIT] NOT NULL
)
INSERT @Stages
(
[StageName],
[StageDescription],
[Enabled]
)
VALUES
('Extract', N'Ingest all data from source systems.', 1),
('Transform', N'Transform ingested data and apply business logic.', 1),
('Load', N'Load transformed data into data warehouse layer.', 1),
('Serve', N'Load transformed data into semantic layer.', 1),
('Speed', N'Regular loading of frequently used data.', 0);
MERGE INTO [procfwk].[Stages] AS tgt
USING
@Stages AS src
ON tgt.[StageName] = src.[StageName]
WHEN MATCHED THEN
UPDATE
SET
tgt.[StageDescription] = src.[StageDescription],
tgt.[Enabled] = src.[Enabled]
WHEN NOT MATCHED BY TARGET THEN
INSERT
(
[StageName],
[StageDescription],
[Enabled]
)
VALUES
(
src.[StageName],
src.[StageDescription],
src.[Enabled]
)
WHEN NOT MATCHED BY SOURCE THEN
DELETE;
END;
================================================
FILE: MetadataDB/procfwkHelpers/Stored Procedures/SetDefaultSubscription.sql
================================================
CREATE PROCEDURE [procfwkHelpers].[SetDefaultSubscription]
AS
BEGIN
DECLARE @Subscriptions TABLE
(
[SubscriptionId] UNIQUEIDENTIFIER NOT NULL,
[Name] NVARCHAR(200) NOT NULL,
[Description] NVARCHAR(MAX) NULL,
[TenantId] UNIQUEIDENTIFIER NOT NULL
)
INSERT INTO @Subscriptions
(
[SubscriptionId],
[Name],
[Description],
[TenantId]
)
VALUES
('12345678-1234-1234-1234-012345678910', 'Default', 'Example value for development environment.', '12345678-1234-1234-1234-012345678910');
MERGE INTO [procfwk].[Subscriptions] AS tgt
USING
@Subscriptions AS src
ON tgt.[SubscriptionId] = src.[SubscriptionId]
WHEN MATCHED THEN
UPDATE
SET
tgt.[Name] = src.[Name],
tgt.[Description] = src.[Description],
tgt.[TenantId] = src.[TenantId]
WHEN NOT MATCHED BY TARGET THEN
INSERT
(
[SubscriptionId],
[Name],
[Description],
[TenantId]
)
VALUES
(
src.[SubscriptionId],
src.[Name],
src.[Description],
src.[TenantId]
)
WHEN NOT MATCHED BY SOURCE THEN
DELETE;
END;
================================================
FILE: MetadataDB/procfwkHelpers/Stored Procedures/SetDefaultTenant.sql
================================================
CREATE PROCEDURE [procfwkHelpers].[SetDefaultTenant]
AS
BEGIN
DECLARE @Tenants TABLE
(
[TenantId] UNIQUEIDENTIFIER NOT NULL,
[Name] NVARCHAR(200) NOT NULL,
[Description] NVARCHAR(MAX) NULL
)
INSERT INTO @Tenants
(
[TenantId],
[Name],
[Description]
)
VALUES
('12345678-1234-1234-1234-012345678910', 'Default', 'Example value for development environment.');
MERGE INTO [procfwk].[Tenants] AS tgt
USING
@Tenants AS src
ON tgt.[TenantId] = src.[TenantId]
WHEN MATCHED THEN
UPDATE
SET
tgt.[Name] = src.[Name],
tgt.[Description] = src.[Description]
WHEN NOT MATCHED BY TARGET THEN
INSERT
(
[TenantId],
[Name],
[Description]
)
VALUES
(
src.[TenantId],
src.[Name],
src.[Description]
)
WHEN NOT MATCHED BY SOURCE THEN
DELETE;
END;
================================================
FILE: MetadataDB/procfwkHelpers/Views/PipelineDependencyChains.sql
================================================
CREATE VIEW [procfwkHelpers].[PipelineDependencyChains]
AS
SELECT
ps.[StageName] AS PredecessorStage,
pp.[PipelineName] AS PredecessorPipeline,
ds.[StageName] AS DependantStage,
dp.[PipelineName] AS DependantPipeline
FROM
[procfwk].[PipelineDependencies] pd --pipeline dependencies
INNER JOIN [procfwk].[Pipelines] pp --predecessor pipelines
ON pd.[PipelineId] = pp.[PipelineId]
INNER JOIN [procfwk].[Pipelines] dp --dependant pipelines
ON pd.[DependantPipelineId] = dp.[PipelineId]
INNER JOIN [procfwk].[Stages] ps --predecessor stage
ON pp.[StageId] = ps.[StageId]
INNER JOIN [procfwk].[Stages] ds --dependant stage
ON dp.[StageId] = ds.[StageId];
================================================
FILE: MetadataDB/procfwkReporting/Views/AverageStageDuration.sql
================================================
CREATE VIEW [procfwkReporting].[AverageStageDuration]
AS
WITH stageStartEnd AS
(
SELECT
[LocalExecutionId],
[StageId],
MIN([StartDateTime]) AS 'StageStart',
MAX([EndDateTime]) AS 'StageEnd'
FROM
[procfwk].[ExecutionLog]
GROUP BY
[LocalExecutionId],
[StageId]
)
SELECT
s.[StageId],
s.[StageName],
s.[StageDescription],
AVG(DATEDIFF(MINUTE, stageStartEnd.[StageStart], stageStartEnd.[StageEnd])) 'AvgStageRunDurationMinutes'
FROM
stageStartEnd
INNER JOIN [procfwk].[Stages] s
ON stageStartEnd.[StageId] = s.[StageId]
GROUP BY
s.[StageId],
s.[StageName],
s.[StageDescription]
================================================
FILE: MetadataDB/procfwkReporting/Views/CompleteExecutionErrorLog.sql
================================================
CREATE VIEW [procfwkReporting].[CompleteExecutionErrorLog]
AS
SELECT
exeLog.[LogId] AS ExecutionLogId,
errLog.[LogId] AS ErrorLogId,
exeLog.[LocalExecutionId],
exeLog.[StartDateTime] AS ProcessingDateTime,
exeLog.[CallingOrchestratorName],
exeLog.[OrchestratorType] AS WorkerOrchestartorType,
exeLog.[OrchestratorName] AS WorkerOrchestrator,
exeLog.[PipelineName] AS WorkerPipelineName,
exeLog.[PipelineStatus],
errLog.[ActivityRunId],
errLog.[ActivityName],
errLog.[ActivityType],
errLog.[ErrorCode],
errLog.[ErrorType],
errLog.[ErrorMessage]
FROM
[procfwk].[ExecutionLog] exeLog
INNER JOIN [procfwk].[ErrorLog] errLog
ON exeLog.[LocalExecutionId] = errLog.[LocalExecutionId]
AND exeLog.[PipelineRunId] = errLog.[PipelineRunId]
INNER JOIN [procfwk].[Stages] stgs
ON exeLog.[StageId] = stgs.[StageId]
;
================================================
FILE: MetadataDB/procfwkReporting/Views/CompleteExecutionLog.sql
================================================
CREATE VIEW [procfwkReporting].[CompleteExecutionLog]
AS
SELECT
[LogId],
[LocalExecutionId],
[StageId],
[PipelineId],
[CallingOrchestratorName],
[ResourceGroupName],
[OrchestratorType],
[OrchestratorName],
[PipelineName],
[StartDateTime],
[PipelineStatus],
[EndDateTime],
DATEDIFF(MINUTE, [StartDateTime], [EndDateTime]) 'RunDurationMinutes'
FROM
[procfwk].[ExecutionLog]
================================================
FILE: MetadataDB/procfwkReporting/Views/CurrentExecutionSummary.sql
================================================
CREATE VIEW [procfwkReporting].[CurrentExecutionSummary]
AS
SELECT
ISNULL([PipelineStatus], 'Not Started') AS 'PipelineStatus',
COUNT(0) AS 'RecordCount'
FROM
[procfwk].[CurrentExecution]
GROUP BY
[PipelineStatus]
================================================
FILE: MetadataDB/procfwkReporting/Views/LastExecution.sql
================================================
CREATE VIEW [procfwkReporting].[LastExecution]
AS
WITH maxLog AS
(
SELECT
MAX([LogId]) AS 'MaxLogId'
FROM
[procfwk].[ExecutionLog]
),
lastExecutionId AS
(
SELECT
[LocalExecutionId]
FROM
[procfwk].[ExecutionLog] el1
INNER JOIN maxLog
ON maxLog.[MaxLogId] = el1.[LogId]
)
SELECT
el2.[LogId],
el2.[StageId],
el2.[PipelineId],
el2.[PipelineName],
el2.[StartDateTime],
el2.[PipelineStatus],
el2.[EndDateTime],
DATEDIFF(MINUTE, el2.[StartDateTime], el2.[EndDateTime]) AS RunDurationMinutes
FROM
[procfwk].[ExecutionLog] el2
INNER JOIN lastExecutionId
ON el2.[LocalExecutionId] = lastExecutionId.[LocalExecutionId]
WHERE
el2.[EndDateTime] IS NOT NULL;
================================================
FILE: MetadataDB/procfwkReporting/Views/LastExecutionSummary.sql
================================================
CREATE VIEW [procfwkReporting].[LastExecutionSummary]
AS
WITH maxLog AS
(
SELECT
MAX([LogId]) AS 'MaxLogId'
FROM
[procfwk].[ExecutionLog]
),
lastExecutionId AS
(
SELECT
[LocalExecutionId]
FROM
[procfwk].[ExecutionLog] el1
INNER JOIN maxLog
ON maxLog.[MaxLogId] = el1.[LogId]
)
SELECT
el2.[LocalExecutionId],
DATEDIFF(MINUTE, MIN(el2.[StartDateTime]), MAX(el2.[EndDateTime])) 'RunDurationMinutes'
FROM
[procfwk].[ExecutionLog] el2
INNER JOIN lastExecutionId
ON el2.[LocalExecutionId] = lastExecutionId.[LocalExecutionId]
GROUP BY
el2.[LocalExecutionId]
================================================
FILE: MetadataDB/procfwkReporting/Views/WorkerParallelismOverTime.sql
================================================
CREATE VIEW [procfwkReporting].[WorkerParallelismOverTime]
AS
WITH numbers AS
(
SELECT TOP 500
ROW_NUMBER() OVER (ORDER BY s1.[object_id]) - 1 AS 'Number'
FROM
sys.all_columns AS s1
CROSS JOIN sys.all_columns AS s2
),
executionBoundaries AS
(
SELECT
[LocalExecutionId],
CAST(CONVERT(VARCHAR(16), MIN([StartDateTime]), 120) AS DATETIME) AS 'ExecutionStart',
CAST(CONVERT(VARCHAR(16), MAX([EndDateTime]), 120) AS DATETIME) AS 'ExecutionEnd'
FROM
[procfwk].[ExecutionLog]
--WHERE
-- [LocalExecutionId] = '2BB02783-2A2C-4970-9BEA-0543013BFD5E'
GROUP BY
[LocalExecutionId]
),
wallclockRunning AS
(
SELECT
CAST(DATEADD(MINUTE, n.[Number], eB.[ExecutionStart]) AS DATE) AS 'WallclockDate',
CAST(DATEADD(MINUTE, n.[Number], eB.[ExecutionStart]) AS TIME) AS 'WallclockTime',
el.[LocalExecutionId],
el.[PipelineId],
el.[PipelineName],
s.[StageName]
FROM
executionBoundaries eB
CROSS JOIN numbers n
INNER JOIN [procfwk].[ExecutionLog] eL
ON eB.[LocalExecutionId] = eL.[LocalExecutionId]
AND DATEADD(MINUTE, n.[Number], eB.[ExecutionStart])
BETWEEN eL.[StartDateTime] AND eL.[EndDateTime]
INNER JOIN [procfwk].[Stages] s
ON eL.[StageId] = s.[StageId]
)
SELECT
[WallclockDate],
[WallclockTime],
[LocalExecutionId],
[StageName],
STRING_AGG(ISNULL([PipelineName],' '),', ') As 'PipelineName',
COUNT([PipelineId]) AS 'WorkerCount'
FROM
wallclockRunning
GROUP BY
[WallclockDate],
[WallclockTime],
[LocalExecutionId],
[StageName]
GO
================================================
FILE: MetadataDB/procfwkTesting/Stored Procedures/Add20BatchesFor1000Workers.sql
================================================
CREATE PROCEDURE [procfwkTesting].[Add20BatchesFor1000Workers]
AS
BEGIN
SET NOCOUNT ON;
--clear default metadata
DELETE FROM [procfwk].[BatchStageLink];
DELETE FROM [procfwk].[Batches];
DELETE FROM [procfwk].[PipelineDependencies];
DBCC CHECKIDENT ('[procfwk].[PipelineDependencies]', RESEED, 0);
DELETE FROM [procfwk].[PipelineAlertLink];
DBCC CHECKIDENT ('[procfwk].[PipelineAlertLink]', RESEED, 0);
DELETE FROM [procfwk].[Recipients];
DBCC CHECKIDENT ('[procfwk].[Recipients]', RESEED, 0);
DELETE FROM [procfwk].[PipelineAuthLink];
DBCC CHECKIDENT ('[procfwk].[PipelineAuthLink]', RESEED, 0);
DELETE FROM [dbo].[ServicePrincipals];
DBCC CHECKIDENT ('[dbo].[ServicePrincipals]', RESEED, 0);
DELETE FROM [procfwk].[PipelineParameters];
DBCC CHECKIDENT ('[procfwk].[PipelineParameters]', RESEED, 0);
DELETE FROM [procfwk].[Pipelines];
DBCC CHECKIDENT ('[procfwk].[Pipelines]', RESEED, 0);
--get Orchestrator id
DECLARE @OrcId INT
SELECT
@OrcId = [OrchestratorId]
FROM
[procfwk].[Orchestrators]
WHERE
[OrchestratorName] = 'WorkersFactory'
AND [OrchestratorType] = 'ADF';
--tweak properties
UPDATE
[procfwk].[Properties]
SET
[PropertyValue] = '[dbo].[None]'
WHERE
[PropertyName] = 'ExecutionPrecursorProc';
UPDATE
[procfwk].[Properties]
SET
[PropertyValue] = '30'
WHERE
[PropertyName] = 'PipelineStatusCheckDuration';
UPDATE
[procfwk].[Properties]
SET
[PropertyValue] = '0'
WHERE
[PropertyName] = 'UseFrameworkEmailAlerting';
UPDATE
[procfwk].[Properties]
SET
[PropertyValue] = '1'
WHERE
[PropertyName] = 'UseExecutionBatches';
--insert 200 pipelines
;WITH cte AS
(
SELECT TOP 200
ROW_NUMBER() OVER (ORDER BY s1.[object_id]) AS Number
FROM
sys.all_columns AS s1
CROSS JOIN sys.all_columns AS s2
)
INSERT INTO [procfwk].[Pipelines]
(
[OrchestratorId],
[StageId],
[PipelineName],
[LogicalPredecessorId],
[Enabled]
)
SELECT
@OrcId,
CASE
WHEN [Number] <= 50 THEN 1
WHEN [Number] > 50 AND [Number] <= 100 THEN 2
WHEN [Number] > 100 AND [Number] <= 150 THEN 3
WHEN [Number] > 150 AND [Number] <= 200 THEN 4
END,
'Wait ' + CAST([Number] AS VARCHAR),
NULL,
1
FROM
cte;
--disable other execution stages if exist
UPDATE [procfwk].[Stages] SET [Enabled] = 1;
UPDATE [procfwk].[Stages] SET [Enabled] = 0 WHERE [StageId] > 4;
--insert 200 pipeline parameters
INSERT INTO [procfwk].[PipelineParameters]
(
[PipelineId],
[ParameterName],
[ParameterValue]
)
SELECT
[PipelineId],
'WaitTime',
LEFT(ABS(CAST(CAST(NEWID() AS VARBINARY) AS INT)),1)
FROM
[procfwk].[Pipelines];
--insert batches
;WITH batchNames AS
(
SELECT 'One' AS [Name]
UNION SELECT 'Two'
UNION SELECT 'Three'
UNION SELECT 'Four'
UNION SELECT 'Five'
UNION SELECT 'Six'
UNION SELECT 'Seven'
UNION SELECT 'Eight'
UNION SELECT 'Nine'
UNION SELECT 'Ten'
UNION SELECT 'Eleven'
UNION SELECT 'Twelve'
UNION SELECT 'Thirteen'
UNION SELECT 'Fourteen'
UNION SELECT 'Fifteen'
UNION SELECT 'Sixteen'
UNION SELECT 'Seventeen'
UNION SELECT 'Eighteen'
UNION SELECT 'Nineteen'
UNION SELECT 'Twenty'
)
INSERT INTO [procfwk].[Batches]
(
[BatchName],
[BatchDescription],
[Enabled]
)
SELECT
[Name],
'1000 Workers Test',
1
FROM
batchNames
--allocation batches to stages evenly
;WITH maxStages AS
(
SELECT
MAX([StageId]) AS Id
FROM
[procfwk].[Stages]
WHERE
[Enabled] = 1
)
INSERT INTO [procfwk].[BatchStageLink]
SELECT
b.[BatchId],
CASE
WHEN (ROW_NUMBER() OVER (ORDER BY b.[BatchName] DESC) * 1) % maxStages.[Id] = 0 THEN maxStages.[Id]
ELSE (ROW_NUMBER() OVER (ORDER BY b.[BatchName] DESC) * 1) % maxStages.[Id]
END AS Stage
FROM
[procfwk].[Batches] b
CROSS JOIN maxStages;
/*
--generate the c# for the NUnit test:
SELECT
[BatchName],
'private GrandparentHelper _helperBatch' + [BatchName] + ';',
'_helperBatch' + [BatchName] + ' = new GrandparentHelper().WithParameter("BatchName", "' + [BatchName] + '");',
'var batch' + [BatchName] + ' = _helperBatch' + [BatchName] + '.RunPipeline();',
'batch' + [BatchName] + ',',
'[Test]' + CHAR(13) +
'public void Then' + [BatchName] + 'BatchPipelineOutcomeIsSucceeded()' + CHAR(13) +
'{' + CHAR(13) +
' _helperBatch' + [BatchName] + '.RunOutcome.Should().Be("Succeeded");' + CHAR(13) +
'}'
FROM
[procfwk].[Batches]
*/
END;
================================================
FILE: MetadataDB/procfwkTesting/Stored Procedures/Add300WorkerPipelineBatches.sql
================================================
CREATE PROCEDURE [procfwkTesting].[Add300WorkerPipelineBatches]
AS
BEGIN
SET NOCOUNT ON;
--clear default metadata
DELETE FROM [procfwk].[BatchStageLink];
DELETE FROM [procfwk].[Batches];
--add batch details
;WITH sourceData AS
(
SELECT
'0to300' AS BatchName,
'The first 300.' AS BatchDescription,
1 AS [Enabled]
UNION SELECT
'301to600',
'The second 300.',
1
)
MERGE INTO [procfwk].[Batches] AS tgt
USING
sourceData AS src
ON tgt.[BatchName] = src.[BatchName]
WHEN MATCHED THEN
UPDATE
SET
tgt.[BatchDescription] = src.[BatchDescription],
tgt.[Enabled] = src.[Enabled]
WHEN NOT MATCHED BY TARGET THEN
INSERT
(
[BatchName],
[BatchDescription],
[Enabled]
)
VALUES
(
src.[BatchName],
src.[BatchDescription],
src.[Enabled]
)
WHEN NOT MATCHED BY SOURCE THEN
DELETE;
--link batches to stages
INSERT INTO [procfwk].[BatchStageLink]
(
[BatchId],
[StageId]
)
SELECT
b.[BatchId],
s.[StageId]
FROM
[procfwk].[Batches] b
INNER JOIN [procfwk].[Stages] s
ON s.[Enabled] = 1;
END;
================================================
FILE: MetadataDB/procfwkTesting/Stored Procedures/Add300WorkerPipelines.sql
================================================
CREATE PROCEDURE [procfwkTesting].[Add300WorkerPipelines]
AS
BEGIN
SET NOCOUNT ON;
--clear default metadata
DELETE FROM [procfwk].[PipelineDependencies];
DBCC CHECKIDENT ('[procfwk].[PipelineDependencies]', RESEED, 0);
DELETE FROM [procfwk].[PipelineAlertLink];
DBCC CHECKIDENT ('[procfwk].[PipelineAlertLink]', RESEED, 0);
DELETE FROM [procfwk].[Recipients];
DBCC CHECKIDENT ('[procfwk].[Recipients]', RESEED, 0);
DELETE FROM [procfwk].[PipelineAuthLink];
DBCC CHECKIDENT ('[procfwk].[PipelineAuthLink]', RESEED, 0);
DELETE FROM [dbo].[ServicePrincipals];
DBCC CHECKIDENT ('[dbo].[ServicePrincipals]', RESEED, 0);
DELETE FROM [procfwk].[PipelineParameters];
DBCC CHECKIDENT ('[procfwk].[PipelineParameters]', RESEED, 0);
DELETE FROM [procfwk].[Pipelines];
DBCC CHECKIDENT ('[procfwk].[Pipelines]', RESEED, 0);
--get Orchestrator id
DECLARE @OrcId INT
SELECT
@OrcId = [OrchestratorId]
FROM
[procfwk].[Orchestrators]
WHERE
[OrchestratorName] = 'WorkersFactory'
AND [OrchestratorType] = 'ADF';
--insert 300 pipelines
;WITH cte AS
(
SELECT TOP 300
ROW_NUMBER() OVER (ORDER BY s1.[object_id]) AS Number
FROM
sys.all_columns AS s1
CROSS JOIN sys.all_columns AS s2
)
INSERT INTO [procfwk].[Pipelines]
(
[OrchestratorId],
[StageId],
[PipelineName],
[LogicalPredecessorId],
[Enabled]
)
SELECT
@OrcId,
CASE
WHEN [Number] <= 100 THEN 1
WHEN [Number] > 100 AND [Number] <= 200 THEN 2
WHEN [Number] > 200 AND [Number] <= 300 THEN 3
END,
'Wait ' + CAST([Number] AS VARCHAR),
NULL,
1
FROM
cte;
--disable other execution stages if exist
UPDATE [procfwk].[Stages] SET [Enabled] = 0 WHERE [StageId] > 3;
--insert 300 pipeline parameters
INSERT INTO [procfwk].[PipelineParameters]
(
[PipelineId],
[ParameterName],
[ParameterValue]
)
SELECT
[PipelineId],
'WaitTime',
LEFT(ABS(CAST(CAST(NEWID() AS VARBINARY) AS INT)),2)
FROM
[procfwk].[Pipelines];
END;
================================================
FILE: MetadataDB/procfwkTesting/Stored Procedures/CleanUpMetadata.sql
================================================
CREATE PROCEDURE [procfwkTesting].[CleanUpMetadata]
AS
BEGIN
EXEC [procfwkHelpers].[DeleteMetadataWithIntegrity];
EXEC [procfwkHelpers].[DeleteMetadataWithoutIntegrity];
END;
================================================
FILE: MetadataDB/procfwkTesting/Stored Procedures/GetRunIdWhenAvailable.sql
================================================
CREATE PROCEDURE [procfwkTesting].[GetRunIdWhenAvailable]
(
@PipelineName NVARCHAR(200) = NULL
)
AS
BEGIN
IF @PipelineName IS NULL
BEGIN
WHILE 1=1
BEGIN
IF EXISTS
(
SELECT TOP 1
[PipelineRunId]
FROM
[procfwk].[CurrentExecution]
WHERE
[PipelineRunId] IS NOT NULL
)
BEGIN
BREAK;
END
WAITFOR DELAY '00:00:10';
END;
SELECT TOP 1
CAST([PipelineRunId] AS VARCHAR(36)) AS RunId
FROM
[procfwk].[CurrentExecution]
WHERE
[PipelineRunId] IS NOT NULL
END
ELSE IF @PipelineName IS NOT NULL
BEGIN
WHILE 1=1
BEGIN
IF EXISTS
(
SELECT TOP 1
[PipelineRunId]
FROM
[procfwk].[CurrentExecution]
WHERE
[PipelineRunId] IS NOT NULL
AND [PipelineName] = @PipelineName
)
BEGIN
BREAK;
END
WAITFOR DELAY '00:00:10';
END;
SELECT TOP 1
CAST([PipelineRunId] AS VARCHAR(36)) AS RunId
FROM
[procfwk].[CurrentExecution]
WHERE
[PipelineRunId] IS NOT NULL
AND [PipelineName] = @PipelineName
END
ELSE
BEGIN
RAISERROR('Unknown use of testing procedure.',16,1);
END
END;
================================================
FILE: MetadataDB/procfwkTesting/Stored Procedures/ResetMetadata.sql
================================================
CREATE PROCEDURE [procfwkTesting].[ResetMetadata]
AS
BEGIN
EXEC [procfwkHelpers].[SetDefaultProperties];
EXEC [procfwkHelpers].[SetDefaultTenant];
EXEC [procfwkHelpers].[SetDefaultSubscription];
EXEC [procfwkHelpers].[SetDefaultOrchestrators];
EXEC [procfwkHelpers].[SetDefaultBatches];
EXEC [procfwkHelpers].[SetDefaultStages];
EXEC [procfwkHelpers].[SetDefaultBatchStageLink];
EXEC [procfwkHelpers].[SetDefaultPipelines];
EXEC [procfwkHelpers].[SetDefaultPipelineParameters];
EXEC [procfwkHelpers].[SetDefaultPipelineDependants];
EXEC [procfwkHelpers].[SetDefaultRecipients];
EXEC [procfwkHelpers].[SetDefaultAlertOutcomes];
EXEC [procfwkHelpers].[SetDefaultRecipientPipelineAlerts];
END;
================================================
FILE: MetadataDBTests/MetadataDBTests.sqlproj
================================================
Debug
AnyCPU
MetadataDBTests
2.0
4.1
{32d54b90-932d-44a3-911d-007c4b90bc55}
Microsoft.Data.Tools.Schema.Sql.SqlAzureV12DatabaseSchemaProvider
Database
MetadataDBTests
MetadataDBTests
1033, CI
BySchemaAndSchemaType
True
v4.7.2
CS
Properties
False
True
True
bin\Release\
$(MSBuildProjectName).sql
False
pdbonly
true
false
true
prompt
4
bin\Debug\
$(MSBuildProjectName).sql
false
true
full
false
true
true
prompt
4
11.0
True
11.0
MetadataDB
{202ebf84-a56b-4999-92a3-10f7ffe4ef25}
True
False
$(DacPacRootPath)\Extensions\Microsoft\SQLDB\Extensions\SqlServer\AzureV12\SqlSchemas\master.dacpac
False
master
tSQLt.dacpac
False
================================================
FILE: MetadataDBTests/Scripts/Script.PostDeployment.sql
================================================
/*
Post-Deployment Script Template
--------------------------------------------------------------------------------------
This file contains SQL statements that will be appended to the build script.
Use SQLCMD syntax to include a file in the post-deployment script.
Example: :r .\myfile.sql
Use SQLCMD syntax to reference a variable in the post-deployment script.
Example: :setvar TableName MyTable
SELECT * FROM [$(TableName)]
--------------------------------------------------------------------------------------
*/
:r ..\..\MetadataDB\Scripts\Script.PostDeployment.sql
================================================
FILE: MetadataDBTests/Scripts/Script.PreDeployment.sql
================================================
/*
Pre-Deployment Script Template
--------------------------------------------------------------------------------------
This file contains SQL statements that will be executed before the build script.
Use SQLCMD syntax to include a file in the pre-deployment script.
Example: :r .\myfile.sql
Use SQLCMD syntax to reference a variable in the pre-deployment script.
Example: :setvar TableName MyTable
SELECT * FROM [$(TableName)]
--------------------------------------------------------------------------------------
*/
:r ..\..\MetadataDB\Scripts\Script.PreDeployment.sql
================================================
FILE: MetadataDBTests/_TestClasses/procfwk_GetPropertyValue.sql
================================================
CREATE SCHEMA procfwk_GetPropertyValue
AUTHORIZATION [dbo];
GO
EXEC sp_addextendedproperty @name = N'tSQLt.TestClass', @value = 1, @level0type = N'SCHEMA', @level0name = N'procfwk_GetPropertyValue'
================================================
FILE: MetadataDBTests/_TestClasses/procfwk_GetPropertyValueInternal.sql
================================================
CREATE SCHEMA procfwk_GetPropertyValueInternal
AUTHORIZATION [dbo];
GO
EXEC sp_addextendedproperty @name = N'tSQLt.TestClass', @value = 1, @level0type = N'SCHEMA', @level0name = N'procfwk_GetPropertyValueInternal'
================================================
FILE: MetadataDBTests/procfwk_GetPropertyValue/setup.sql
================================================
CREATE PROCEDURE procfwk_GetPropertyValue.[setup]
AS
DECLARE @propertyName NVARCHAR(128) = 'TestProperty'
EXEC tSQLt.FakeTable 'procfwk.CurrentProperties'
INSERT INTO procfwk.CurrentProperties (
[PropertyName]
, [PropertyValue]
) VALUES (
@propertyName
, 'TestPropertyValue'
)
================================================
FILE: MetadataDBTests/procfwk_GetPropertyValue/test WHEN property does not exist THEN error raised.sql
================================================
CREATE PROCEDURE procfwk_GetPropertyValue.[test WHEN property does not exist THEN error raised]
AS
-- ARRANGE
DECLARE @propertyName NVARCHAR(128) = 'OtherProperty'
EXEC tSQLt.FakeTable 'procfwk.Properties'
INSERT INTO procfwk.Properties (
[PropertyName]
, [PropertyValue]
) VALUES (
'TestProperty'
, 'TestPropertyValue'
)
-- EXPECT
EXEC tSQLt.ExpectException @ExpectedMessagePattern = '%Invalid property name %'
-- ACT
CREATE TABLE #actual (
PropertyValue NVARCHAR(4000)
)
INSERT INTO #actual (
PropertyValue
)
EXEC procfwk.GetPropertyValue @propertyName
================================================
FILE: MetadataDBTests/procfwk_GetPropertyValue/test WHEN property exists THEN property value returned.sql
================================================
CREATE PROCEDURE procfwk_GetPropertyValue.[test WHEN property exists THEN property value returned]
AS
-- ARRANGE
DECLARE @propertyName NVARCHAR(128) = 'TestProperty'
EXEC tSQLt.FakeTable 'procfwk.Properties'
INSERT INTO procfwk.Properties (
[PropertyName]
, [PropertyValue]
) VALUES (
'TestProperty'
, 'TestPropertyValue'
)
SELECT N'TestPropertyValue' AS PropertyValue
INTO #expected
-- ACT
CREATE TABLE #actual (
PropertyValue NVARCHAR(4000)
)
INSERT INTO #actual (
PropertyValue
)
EXEC procfwk.GetPropertyValue @propertyName
-- ASSERT
EXEC tSQLt.AssertEqualsTable
@Expected = '#expected'
, @Actual = '#actual'
================================================
FILE: MetadataDBTests/procfwk_GetPropertyValue/test WHEN property invalidated THEN error raised.sql
================================================
CREATE PROCEDURE procfwk_GetPropertyValue.[test WHEN property invalidated THEN error raised]
AS
-- ARRANGE
DECLARE @propertyName NVARCHAR(128) = 'TestProperty'
EXEC tSQLt.FakeTable 'procfwk.Properties'
INSERT INTO procfwk.Properties (
[PropertyName]
, [PropertyValue]
, ValidTo
) VALUES (
'TestProperty'
, 'TestPropertyValue'
, GETDATE()
)
-- EXPECT
EXEC tSQLt.ExpectException @ExpectedMessagePattern = '% does not have a current valid version %'
-- ACT
CREATE TABLE #actual (
PropertyValue NVARCHAR(4000)
)
INSERT INTO #actual (
PropertyValue
)
EXEC procfwk.GetPropertyValue @propertyName
================================================
FILE: MetadataDBTests/procfwk_GetPropertyValue/test WHEN property name is null THEN error raised.sql
================================================
CREATE PROCEDURE procfwk_GetPropertyValue.[test WHEN property name is null THEN error raised]
AS
-- ARRANGE
DECLARE @propertyName NVARCHAR(128) = NULL
EXEC tSQLt.FakeTable 'procfwk.Properties'
INSERT INTO procfwk.Properties (
[PropertyName]
, [PropertyValue]
) VALUES (
'TestProperty'
, 'TestPropertyValue'
)
-- EXPECT
EXEC tSQLt.ExpectException @ExpectedMessagePattern = '%Invalid property name %'
-- ACT
CREATE TABLE #actual (
PropertyValue NVARCHAR(4000)
)
INSERT INTO #actual (
PropertyValue
)
EXEC procfwk.GetPropertyValue @propertyName
================================================
FILE: MetadataDBTests/procfwk_GetPropertyValueInternal/test WHEN property does not exist THEN empty string returned.sql
================================================
CREATE PROCEDURE procfwk_GetPropertyValueInternal.[test WHEN property name does not exist THEN empty string returned]
AS
-- ARRANGE
DECLARE @propertyName NVARCHAR(128) = 'TestProperty'
EXEC tSQLt.FakeTable 'procfwk.CurrentProperties'
DECLARE @expected NVARCHAR(4000) = ''
-- ACT
DECLARE @actual NVARCHAR(4000) = procfwk.GetPropertyValueInternal(@propertyName)
-- ASSERT
EXEC tSQLt.AssertEquals
@Expected = @expected
, @Actual = @actual
================================================
FILE: MetadataDBTests/procfwk_GetPropertyValueInternal/test WHEN property exists THEN property value returned.sql
================================================
CREATE PROCEDURE procfwk_GetPropertyValueInternal.[test WHEN property exists THEN property value returned]
AS
-- ARRANGE
DECLARE @propertyName NVARCHAR(128) = 'TestProperty'
EXEC tSQLt.FakeTable 'procfwk.CurrentProperties'
INSERT INTO procfwk.CurrentProperties (
[PropertyName]
, [PropertyValue]
) VALUES (
'TestProperty'
, 'TestPropertyValue'
)
DECLARE @expected NVARCHAR(4000) = 'TestPropertyValue'
-- ACT
DECLARE @actual NVARCHAR(4000) = procfwk.GetPropertyValueInternal(@propertyName)
-- ASSERT
EXEC tSQLt.AssertEquals
@Expected = @expected
, @Actual = @actual
================================================
FILE: MetadataDBTests/procfwk_GetPropertyValueInternal/test WHEN property name is null THEN empty string returned.sql
================================================
CREATE PROCEDURE procfwk_GetPropertyValueInternal.[test WHEN property name is null THEN empty string returned]
AS
-- ARRANGE
DECLARE @propertyName NVARCHAR(128) = NULL
EXEC tSQLt.FakeTable 'procfwk.CurrentProperties'
INSERT INTO procfwk.CurrentProperties (
[PropertyName]
, [PropertyValue]
) VALUES (
'TestProperty'
, 'TestPropertyValue'
)
DECLARE @expected NVARCHAR(4000) = ''
-- ACT
DECLARE @actual NVARCHAR(4000) = procfwk.GetPropertyValueInternal(@propertyName)
-- ASSERT
EXEC tSQLt.AssertEquals
@Expected = @expected
, @Actual = @actual
================================================
FILE: Notebooks/Databricks - Throw Exception.scala
================================================
// Databricks notebook source
import scala.util.Try
dbutils.widgets.text("RaiseError", "","")
// COMMAND ----------
val raiseError = Try(dbutils.widgets.get("RaiseError").toBoolean).getOrElse(false)
if(raiseError)
{
throw new Exception("The Notebook intentionally failed.")
}
================================================
FILE: Notebooks/Metadata Guide and Handy Code Snippets.ipynb
================================================
{
"metadata": {
"kernelspec": {
"name": "SQL",
"display_name": "SQL",
"language": "sql"
},
"language_info": {
"name": "sql",
"version": ""
}
},
"nbformat_minor": 2,
"nbformat": 4,
"cells": [
{
"cell_type": "markdown",
"source": [
"# Welcome to the ADF.procfwk Handy User Guide Notebook\r\n",
"\r\n",
"This Notebook provides a series of short code snippets and narrative to help developers work with processing framework metadata.\r\n",
"\r\n",
"\r\n",
"\r\n",
"Note: do not just run all cells in this Notebook. This may make unwanted changes to your deployed solution. The EXEC code is written with example values for you to update."
],
"metadata": {
"azdata_cell_guid": "be267c69-3b61-4daf-980e-0adf85f85108"
}
},
{
"cell_type": "code",
"source": [
"SET NOCOUNT ON;"
],
"metadata": {
"azdata_cell_guid": "4b561a97-5508-4001-9bb3-4d2ed7fe3a2f"
},
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"source": [
"***\r\n",
"# Getting Current & Previous Execution Details\r\n",
"\r\n",
"* The [CurrentExecution] table only contains data for processing runs that our in progress or in an incomplete state.\r\n",
"\r\n",
"* The [ExecutionLog] table and [CompleteExecutionLog] views contains all other log details for execution runs."
],
"metadata": {
"azdata_cell_guid": "1f574591-3c81-4fa4-ad6a-54a06aa75e2b"
}
},
{
"cell_type": "code",
"source": [
"SELECT * FROM [procfwk].[CurrentExecution];\r\n",
"\r\n",
"SELECT * FROM [procfwk].[CompleteExecutionLog];\r\n",
"\r\n",
"SELECT * FROM [procfwk].[LastExecution];\r\n",
"\r\n",
"SELECT TOP 100 * FROM [procfwk].[ExecutionLog] ORDER BY [LocalExecutionId], [StageId], [PipelineId], [StartDateTime];\r\n",
"\r\n",
"EXEC [procfwk].[GetExecutionDetails];"
],
"metadata": {
"azdata_cell_guid": "ad517e7c-9517-404b-9e4d-c58e4b7dbd0f"
},
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"source": [
"***\r\n",
"# Getting Error Details\r\n",
"\r\n",
"* The [CurrentExecution] table and the [CompleteExecutionErrorLog] view contain details of error logged for failed pipeline activities. A single pipeline can contain multiple activities that if executed in parallel may generate multiple errrors for a single pipeline Run ID."
],
"metadata": {
"azdata_cell_guid": "f6362034-9ff7-4a6d-a39f-789787d445df"
}
},
{
"cell_type": "code",
"source": [
"SELECT * FROM [procfwk].[ErrorLog];\r\n",
"\r\n",
"SELECT * FROM [procfwk].[CompleteExecutionErrorLog];\r\n",
"\r\n",
"EXEC [procfwk].[GetExecutionDetails];"
],
"metadata": {
"azdata_cell_guid": "5a3106a2-c3c8-4985-923e-79410022ff90"
},
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"source": [
"***\r\n",
"# Reviewing Basic Processing Metadata\r\n",
"The following tables have been ordered as per there level within the processing framework. A logical hierarchy exists between these tables and is enforced via database constraints connecting primary and foreign keys.\r\n",
"* Data Factory's\r\n",
"* Stages\r\n",
"* Pipelines\r\n",
"* Pipeline Parameters"
],
"metadata": {
"azdata_cell_guid": "88506809-f0a5-422d-bf7f-6e6e5082a8d0"
}
},
{
"cell_type": "code",
"source": [
"SELECT * FROM [procfwk].[DataFactorys];\r\n",
"\r\n",
"SELECT * FROM [procfwk].[Stages];\r\n",
"\r\n",
"SELECT * FROM [procfwk].[Pipelines];\r\n",
"\r\n",
"SELECT * FROM [procfwk].[PipelineParameters];"
],
"metadata": {
"azdata_cell_guid": "1a77b2ec-ffa9-4d67-91db-a1fb3acb1693"
},
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"source": [
"***\r\n",
"# Review and Check Logical Pipeline Metadata Integrity\r\n",
"\r\n",
"The following procedure uses the optional attribute [LogicalPredecessorId] within the table [procfwk].[Pipelines] to create a chain of dependencies between processes. This chain has zero affect of the execution of the framework, but does allow data lineage chains to be reviewed and created without impacting processing.\r\n",
"\r\n",
"The procedure also implements a series of case statement checks against pipeline chains to advise where metadata issues may exist. For example:\r\n",
"\r\n",
"* Pipeline could be moved to an earlier stage if it has no predecessors and/or isn't in an earlier stage.\r\n",
"* Dependency issue, predeccessor pipeline is currently running in the same stage as successor.\r\n",
"* Disabled pipeline has downstream successors.\r\n",
"* Disabled stage has downstream successors.\r\n",
"\r\n",
"It is recommended that these advisory points are reviewed and the logical chain of pipelines updated to inform better framework execution.\r\n",
"\r\n",
""
],
"metadata": {
"azdata_cell_guid": "8fae870b-a02f-4b4b-8122-bd94e2fbd39b"
}
},
{
"cell_type": "code",
"source": [
"EXEC [procfwk].[CheckStageAndPiplineIntegrity];"
],
"metadata": {
"azdata_cell_guid": "eeded0ba-002d-4c6f-b4ff-1047aa38ee62"
},
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"source": [
"***\r\n",
"# Checking and Adding Framework Properties\r\n",
"* Use the [CurrentProperties] view to check only the latest version of property values.\r\n",
"* Use the complete [Properties] table to see all versions of framework properties with valid from and to dates.\r\n",
"* Use the stored procedure [AddProperty] to add a new property/value or update an existing property/value.\r\n",
"* Use the stored procedure [GetPropertyValue] to get the latest version of a single property value."
],
"metadata": {
"azdata_cell_guid": "ae575f21-e47d-4544-96c5-44e1af85c9d9"
}
},
{
"cell_type": "code",
"source": [
"SELECT * FROM [procfwk].[CurrentProperties];\r\n",
"\r\n",
"SELECT * FROM [procfwk].[Properties];\r\n",
"\r\n",
"EXEC [procfwk].[AddProperty] \r\n",
"\t@PropertyName = 'TenantId',\r\n",
"\t@PropertyValue = '1234-1234-1234-1234-1234',\r\n",
"\t@Description = 'Used to provide authentication throughout the framework execution.';\r\n",
"\r\n",
"EXEC [procfwk].[GetPropertyValue]\r\n",
"\t@PropertyName = N'TenantId';"
],
"metadata": {
"azdata_cell_guid": "e0e57080-aa45-49d6-a994-7fb83dfe4a08"
},
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"source": [
"***\r\n",
"# Checking, Getting, Adding and Deleting Service Principals\r\n",
"\r\n",
"To **check** which SPN details are being used follow the guidance in the framework for pipeline authentication:\r\n",
"\r\n",
"* The [ServicePrincipals] table in the [dbo] schema details which credentials are being used by the framework. These details are specific to an Azure Tenant. However, this table also needs to be joined with table [procfwk].[PipelineAuthLink] to better understand which credentials are being used by which Data Factory/Pipeline.\r\n",
"\r\n",
"To **get** actual unencrypted SPN details the stored procedure [procfwk].[GetServicePrincipal].\r\n",
"\r\n",
"Be careful not to change the Tenant ID property after Service Principals have been added.\r\n",
"\r\n",
"To **add** Service Principals use the stored procedure [procfwk].[AddServicePrincipal]. This will handle the creation of the links between Data Factory's and Pipelines.\r\n",
"\r\n",
"To **delete** Service Principals use the stored procedure [procfwk].[DeleteServicePrincipal]. This will also handle the removal of the links between Data Factory's and Pipelines.\r\n",
"\r\n",
"Also, be aware that as part of the new metadata integrity checks introduced in v1.3 of the framework. This will ensure all enabled pipelines have a valid SPN before the execution run starts."
],
"metadata": {
"azdata_cell_guid": "86d98611-0f43-4c65-bf91-ea8d3542e705"
}
},
{
"cell_type": "code",
"source": [
"--Checking:\r\n",
"SELECT * FROM [dbo].[ServicePrincipals];\r\n",
"\r\n",
"SELECT\r\n",
"\tSP.[PrincipalName],\r\n",
"\tDF.[ResourceGroupName],\r\n",
"\tDF.[DataFactoryName],\r\n",
"\tPP.[PipelineName]\r\n",
"FROM\r\n",
"\t[procfwk].[PipelineAuthLink] AL\r\n",
"\tINNER JOIN [procfwk].[DataFactorys] DF\r\n",
"\t\tON AL.[DataFactoryId] = DF.[DataFactoryId]\r\n",
"\tINNER JOIN [procfwk].[Pipelines] PP\r\n",
"\t\tON AL.[PipelineId] = PP.[PipelineId]\r\n",
"\tINNER JOIN [dbo].[ServicePrincipals] SP\r\n",
"\t\tON AL.[CredentialId] = SP.[CredentialId];\r\n",
"\r\n",
"--Getting:\r\n",
"EXEC [procfwk].[GetServicePrincipal]\r\n",
"\t@DataFactory = 'FrameworkFactory',\r\n",
"\t@PipelineName = 'Wait 1';\r\n",
"\r\n",
"--Adding:\r\n",
"EXEC [procfwk].[AddServicePrincipal]\r\n",
"\t@DataFactory = N'FrameworkFactory',\r\n",
"\t@PrincipalId = N'1234-1234-1234-1234-1234',\r\n",
"\t@PrincipalSecret = N'Passw0rd123!',\r\n",
"\t@PrincipalName = N'ADFFrameworkExecutor',\r\n",
"\t@SpecificPipelineName = N'Wait 1' --Optional parameter\r\n",
"\r\n",
"--Deleteing:\r\n",
"EXEC [procfwk].[DeleteServicePrincipal]\r\n",
"\t@DataFactory = N'FrameworkFactory',\r\n",
"\t@PrincipalId = N'1234-1234-1234-1234-1234',\r\n",
"\t@SpecificPipelineName = N'Wait 1' --Optional parameter"
],
"metadata": {
"azdata_cell_guid": "ac0c404d-5a8a-4c39-96ff-66e198fffd9f"
},
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"source": [
"***\r\n",
"# Pre Execution Metadata Integrity Checks\r\n",
"\r\n",
"This procedure now acts as a pass/fail check before a given framework exeuction runs starts. If any of the checks fail the Data Factory pipelines will not start and the execution run will be stalled.\r\n",
"\r\n",
"In debug mode details of the checks that failed can be reviewed and fixed.\r\n",
""
],
"metadata": {
"azdata_cell_guid": "6698a16a-026d-4ab0-bae0-5a3b0a672649"
}
},
{
"cell_type": "code",
"source": [
"EXEC [procfwk].[CheckMetadataIntegrity]\r\n",
"\t@DebugMode = 1"
],
"metadata": {
"azdata_cell_guid": "f4247341-87a7-46d3-b55e-1371a48f6d81"
},
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"source": [
"***\r\n",
"# Email Alerting\r\n",
"\r\n",
"The following snippets provide examples on setting up alerting and adding users to the metadata.\r\n",
"\r\n",
"Note: SMTP details need to be provided in the Application Settings of the Azure Function App for email to be sent.\r\n",
""
],
"metadata": {
"azdata_cell_guid": "f0e2fc3b-b6d9-49be-874f-d8fd59d8c7bc"
}
},
{
"cell_type": "code",
"source": [
"--Is framework email alerting enabled?\r\n",
"SELECT CASE [PropertyValue] WHEN 1 THEN 'Yes' WHEN 0 THEN 'No' ELSE 'Unknown' END AS AlertingStatus FROM [procfwk].[CurrentProperties] WHERE [PropertyName] = 'UseFrameworkEmailAlerting';\r\n",
"\r\n",
"--Enable framework alerting:\r\n",
"EXEC [procfwk].[AddProperty]\r\n",
"\t@PropertyName = N'UseFrameworkEmailAlerting',\r\n",
"\t@PropertyValue = N'1',\r\n",
"\t@Description = N'Do you want the framework to handle pipeline email alerts via the database metadata? 1 = Yes, 0 = No.';\r\n",
"\r\n",
"--List current recipients:\r\n",
"SELECT [RecipientId], [Name], [EmailAddress], [MessagePreference], [Enabled] FROM [procfwk].[Recipients];\r\n",
"\r\n",
"--Add a new recipient:\r\n",
"INSERT INTO [procfwk].[Recipients] VALUES ('Test User 3','test.user3@adfprocfwk.com', 'BCC', 1);\r\n",
"\r\n",
"--Add an alert link for a recipient and pipeline:\r\n",
"EXEC [procfwk].[AddRecipientPipelineAlerts]\r\n",
"\t@RecipientName = N'Test User 3',\r\n",
" @PipelineName = 'Wait 1', --optional, default = all\r\n",
"\t@AlertForStatus = 'Success, Failed, Cancelled'; --optional, default = all\r\n",
"\r\n",
"--Remove recipient alerts:\r\n",
"EXEC [procfwk].[DeleteRecipientAlerts]\r\n",
"\t@EmailAddress = N'test.user1@adfprocfwk.com',\r\n",
"\t@SoftDeleteOnly = 1; --soft delete sets Enabled = 0\r\n",
"\r\n",
"--Check a recipients alert subscriptions and preferences for all pipelines:\r\n",
"SELECT\r\n",
"\tr.[Name] AS RecipientName,\r\n",
"\tp.[PipelineName],\r\n",
"\tr.[MessagePreference],\r\n",
"\tao.[PipelineOutcomeStatus],\r\n",
"\tp.[Enabled] AS PipelineEnabled,\r\n",
"\tr.[Enabled] AS RecipientEnabled,\r\n",
"\tal.[Enabled] AS AlertLinkEnabled\r\n",
"FROM\r\n",
"\t[procfwk].[PipelineAlertLink] al\r\n",
"\tINNER JOIN [procfwk].[Recipients] r\r\n",
"\t\tON al.[RecipientId] = r.[RecipientId]\r\n",
"\tINNER JOIN [procfwk].[Pipelines] p\r\n",
"\t\tON al.[PipelineId] = p.[PipelineId]\r\n",
"\tINNER JOIN [procfwk].[AlertOutcomes] ao\r\n",
"\t\tON al.[OutcomesBitValue] & ao.[BitValue] <> 0\r\n",
"WHERE\r\n",
"\tr.[EmailAddress] = 'test.user3@adfprocfwk.com';\r\n",
"\r\n",
"--Customise the email body HTML template:\r\n",
"DECLARE @BodyTemplate NVARCHAR(MAX) =\r\n",
"N'
Pipeline Name: ##PipelineName###
\r\n",
"Status: ##Status###
\r\n",
"Execution ID: ##ExecId###
\r\n",
"Run ID: ##RunId###
\r\n",
"Start Date Time: ##StartDateTime###
\r\n",
"End Date Time: ##EndDateTime###
\r\n",
"Duration (Minutes): ##Duration###
\r\n",
"Called by Data Factory: ##CalledByADF###
\r\n",
"Executed by Data Factory: ##ExecutedByADF###
'\r\n",
"\r\n",
"EXEC [procfwk].[AddProperty]\r\n",
"\t@PropertyName = N'EmailAlertBodyTemplate',\r\n",
"\t@PropertyValue = @BodyTemplate,\r\n",
"\t@Description = N'Custom HTML template of execution information used as the eventual body in email alerts sent.';"
],
"metadata": {
"azdata_cell_guid": "63ffc489-41e7-4ff7-8fd8-4accc2429cf2"
},
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"source": [
"***\r\n",
"# Resources and Content\r\n",
"\r\n",
"|  | Blogs |[mrpaulandrew.com/ADF.procfwk](https://mrpaulandrew.com/category/azure/data-factory/adf-procfwk/)|\r\n",
"|:----:|:----:|:----:|\r\n",
"|  | **GitHub** |**[github.com/mrpaulandrew/ADF.procfwk](https://github.com/mrpaulandrew/ADF.procfwk)** |\r\n",
"|  | **Twitter** |**[#ADFprocfwk](https://twitter.com/search?q=%23ADFprocfwk&src=hashtag_click)** |"
],
"metadata": {
"azdata_cell_guid": "0ffd1628-cef6-41a4-b37c-133d37a01bcf"
}
}
]
}
================================================
FILE: ProcessingFramework.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29728.190
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Functions", "Functions\Functions.csproj", "{491422B7-393B-4421-BE9E-5B70E7746CC1}"
EndProject
Project("{00D1A9C2-B5F0-4AF3-8072-F6C62B433612}") = "MetadataDB", "MetadataDB\MetadataDB.sqlproj", "{202EBF84-A56B-4999-92A3-10F7FFE4EF25}"
EndProject
Project("{151D2E53-A2C4-4D7D-83FE-D05416EBD58E}") = "DeploymentTools", "DeploymentTools\DeploymentTools.deployproj", "{3AEAD846-DBE4-45AD-97DD-37E94BE009FD}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Markdown", "Markdown", "{C7297C57-3403-473B-AA2A-31012A4A9ADF}"
ProjectSection(SolutionItems) = preProject
.github\ISSUE_TEMPLATE\bug-found.md = .github\ISSUE_TEMPLATE\bug-found.md
CODE_OF_CONDUCT.md = CODE_OF_CONDUCT.md
CONTRIBUTING.md = CONTRIBUTING.md
.github\ISSUE_TEMPLATE\feature-request.md = .github\ISSUE_TEMPLATE\feature-request.md
LICENSE = LICENSE
README.md = README.md
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DataFactory", "DataFactory", "{E081CE7B-3DE2-4AB7-8C3A-E58A075BD6F5}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dataset", "dataset", "{997E1D61-E47F-48B0-8F67-09ED4AE92E0E}"
ProjectSection(SolutionItems) = preProject
DataFactory\dataset\GetSetMetadata.json = DataFactory\dataset\GetSetMetadata.json
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "linkedService", "linkedService", "{6B27406C-2C36-4BA1-AFC8-CEFC960D8EE6}"
ProjectSection(SolutionItems) = preProject
DataFactory\linkedService\FrameworkFunctions.json = DataFactory\linkedService\FrameworkFunctions.json
DataFactory\linkedService\Keys.json = DataFactory\linkedService\Keys.json
DataFactory\linkedService\SupportDatabase.json = DataFactory\linkedService\SupportDatabase.json
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "pipeline", "pipeline", "{9CEBE9B6-F1E4-43A8-B84D-FF7D43D5CB20}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_ProcFwk", "_ProcFwk", "{17586826-8BE9-4622-B12E-1683F2A20352}"
ProjectSection(SolutionItems) = preProject
DataFactory\pipeline\01-Grandparent.json = DataFactory\pipeline\01-Grandparent.json
DataFactory\pipeline\02-Parent.json = DataFactory\pipeline\02-Parent.json
DataFactory\pipeline\03-Child.json = DataFactory\pipeline\03-Child.json
DataFactory\pipeline\04-Infant.json = DataFactory\pipeline\04-Infant.json
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Workers", "Workers", "{04142829-7936-4C27-9891-FB086BEAE1AD}"
ProjectSection(SolutionItems) = preProject
DataFactory\pipeline\Intentional Error.json = DataFactory\pipeline\Intentional Error.json
DataFactory\pipeline\Wait 1.json = DataFactory\pipeline\Wait 1.json
DataFactory\pipeline\Wait 10.json = DataFactory\pipeline\Wait 10.json
DataFactory\pipeline\Wait 2.json = DataFactory\pipeline\Wait 2.json
DataFactory\pipeline\Wait 3.json = DataFactory\pipeline\Wait 3.json
DataFactory\pipeline\Wait 4.json = DataFactory\pipeline\Wait 4.json
DataFactory\pipeline\Wait 5.json = DataFactory\pipeline\Wait 5.json
DataFactory\pipeline\Wait 6.json = DataFactory\pipeline\Wait 6.json
DataFactory\pipeline\Wait 7.json = DataFactory\pipeline\Wait 7.json
DataFactory\pipeline\Wait 8.json = DataFactory\pipeline\Wait 8.json
DataFactory\pipeline\Wait 9.json = DataFactory\pipeline\Wait 9.json
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Images", "Images", "{16E32CF7-361C-4A58-B0E1-5C8C46181ADE}"
ProjectSection(SolutionItems) = preProject
Images\Activity Chain.png = Images\Activity Chain.png
Images\Database Diagram.png = Images\Database Diagram.png
Images\procfwk Designs.vsdx = Images\procfwk Designs.vsdx
Images\Repo Social Media Image.png = Images\Repo Social Media Image.png
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Notebooks", "Notebooks", "{19F99FD2-9170-42DA-B4FE-A52A358B5473}"
ProjectSection(SolutionItems) = preProject
Notebooks\Databricks - Throw Exception.scala = Notebooks\Databricks - Throw Exception.scala
Notebooks\Metadata Guide and Handy Code Snippets.ipynb = Notebooks\Metadata Guide and Handy Code Snippets.ipynb
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ARM Templates", "ARM Templates", "{CC7B607B-8C84-4E07-A6C8-326923752F92}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DataFactory", "DataFactory", "{C8F387D0-13CC-4AA5-892C-91D2F3403B55}"
ProjectSection(SolutionItems) = preProject
ARM Templates\Data Factory\v1.0 Export.json = ARM Templates\Data Factory\v1.0 Export.json
ARM Templates\Data Factory\v1.1 Export.json = ARM Templates\Data Factory\v1.1 Export.json
ARM Templates\Data Factory\v1.2 Export.json = ARM Templates\Data Factory\v1.2 Export.json
ARM Templates\Data Factory\v1.3 Export.json = ARM Templates\Data Factory\v1.3 Export.json
ARM Templates\Data Factory\v1.4 Export.json = ARM Templates\Data Factory\v1.4 Export.json
ARM Templates\Data Factory\v1.5 Export.json = ARM Templates\Data Factory\v1.5 Export.json
ARM Templates\Data Factory\v1.6 Export.json = ARM Templates\Data Factory\v1.6 Export.json
ARM Templates\Data Factory\v1.7 Export.json = ARM Templates\Data Factory\v1.7 Export.json
ARM Templates\Data Factory\v1.8 Export.json = ARM Templates\Data Factory\v1.8 Export.json
ARM Templates\Data Factory\v1.8.3 Export.json = ARM Templates\Data Factory\v1.8.3 Export.json
ARM Templates\Data Factory\v1.8.5 Export.json = ARM Templates\Data Factory\v1.8.5 Export.json
ARM Templates\Data Factory\v1.8.6 Export.json = ARM Templates\Data Factory\v1.8.6 Export.json
ARM Templates\Data Factory\v1.9 Export.json = ARM Templates\Data Factory\v1.9 Export.json
ARM Templates\Data Factory\v1.9.1 Export.json = ARM Templates\Data Factory\v1.9.1 Export.json
ARM Templates\Data Factory\v1.9.2 Export.json = ARM Templates\Data Factory\v1.9.2 Export.json
ARM Templates\Data Factory\v2.0 Export.json = ARM Templates\Data Factory\v2.0 Export.json
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "trigger", "trigger", "{FC7877EF-110F-4AD7-B203-EEECE6F08A86}"
ProjectSection(SolutionItems) = preProject
DataFactory\trigger\FunctionalTestingTrigger.json = DataFactory\trigger\FunctionalTestingTrigger.json
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Reporting", "Reporting", "{5A56A63A-351D-467D-A2DA-FDB3C9CBD252}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "PowerBI", "PowerBI", "{EBC230DF-D45D-43E4-A74E-32ADA3DDAE7A}"
ProjectSection(SolutionItems) = preProject
Reporting\PowerBI\Executions Overview.pbit = Reporting\PowerBI\Executions Overview.pbit
Reporting\PowerBI\Executions Overview.pbix = Reporting\PowerBI\Executions Overview.pbix
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SQL Database", "SQL Database", "{20313ECA-118E-408D-BB42-8094A7A9CD20}"
ProjectSection(SolutionItems) = preProject
ARM Templates\SQL Database\v1.6 Export.json = ARM Templates\SQL Database\v1.6 Export.json
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Functions App", "Functions App", "{463330CD-189F-42B4-984A-8D3C1385645B}"
ProjectSection(SolutionItems) = preProject
ARM Templates\Functions App\v1.6 Export.json = ARM Templates\Functions App\v1.6 Export.json
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FactoryTesting", "FactoryTesting\FactoryTesting.csproj", "{777BB424-9D89-49E5-BE29-E73E0A0E159A}"
EndProject
Project("{00D1A9C2-B5F0-4AF3-8072-F6C62B433612}") = "MetadataDBTests", "MetadataDBTests\MetadataDBTests.sqlproj", "{32D54B90-932D-44A3-911D-007C4B90BC55}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_ProcFwkUtils", "_ProcFwkUtils", "{6809EDBD-125D-440E-8486-9CFAB9BB5B7D}"
ProjectSection(SolutionItems) = preProject
DataFactory\pipeline\Check For Running Pipeline.json = DataFactory\pipeline\Check For Running Pipeline.json
DataFactory\pipeline\Email Sender.json = DataFactory\pipeline\Email Sender.json
DataFactory\pipeline\Intentional Error.json = DataFactory\pipeline\Intentional Error.json
DataFactory\pipeline\Throw Exception.json = DataFactory\pipeline\Throw Exception.json
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Synapse", "Synapse", "{6B8CC8C2-C4AA-4BC4-85EC-719348FC3B07}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "pipeline", "pipeline", "{398CB5BE-3687-4F95-8EAA-54EE0DAC4E6C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_ProcFwk", "_ProcFwk", "{2181D7DA-8237-418F-8CD9-CD1BF9843524}"
ProjectSection(SolutionItems) = preProject
Synapse\pipeline\01-Grandparent.json = Synapse\pipeline\01-Grandparent.json
Synapse\pipeline\02-Parent.json = Synapse\pipeline\02-Parent.json
Synapse\pipeline\03-Child.json = Synapse\pipeline\03-Child.json
Synapse\pipeline\04-Infant.json = Synapse\pipeline\04-Infant.json
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_ProcFwkUtils", "_ProcFwkUtils", "{6E660431-66E0-4B1A-BCFC-8FCBF1C646F2}"
ProjectSection(SolutionItems) = preProject
Synapse\pipeline\Check For Running Pipeline.json = Synapse\pipeline\Check For Running Pipeline.json
Synapse\pipeline\Email Sender.json = Synapse\pipeline\Email Sender.json
Synapse\pipeline\Throw Exception.json = Synapse\pipeline\Throw Exception.json
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Workers", "Workers", "{21058901-FBEE-4D40-83E0-21B05636417B}"
ProjectSection(SolutionItems) = preProject
Synapse\pipeline\Intentional Error.json = Synapse\pipeline\Intentional Error.json
Synapse\pipeline\Wait 1.json = Synapse\pipeline\Wait 1.json
Synapse\pipeline\Wait 10.json = Synapse\pipeline\Wait 10.json
Synapse\pipeline\Wait 2.json = Synapse\pipeline\Wait 2.json
Synapse\pipeline\Wait 3.json = Synapse\pipeline\Wait 3.json
Synapse\pipeline\Wait 4.json = Synapse\pipeline\Wait 4.json
Synapse\pipeline\Wait 5.json = Synapse\pipeline\Wait 5.json
Synapse\pipeline\Wait 6.json = Synapse\pipeline\Wait 6.json
Synapse\pipeline\Wait 7.json = Synapse\pipeline\Wait 7.json
Synapse\pipeline\Wait 8.json = Synapse\pipeline\Wait 8.json
Synapse\pipeline\Wait 9.json = Synapse\pipeline\Wait 9.json
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dataset", "dataset", "{7F17593A-2CEF-4741-A4B7-C1CC79F12EB7}"
ProjectSection(SolutionItems) = preProject
Synapse\dataset\GetSetMetadata.json = Synapse\dataset\GetSetMetadata.json
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "linkedservice", "linkedservice", "{F495E5FB-B908-4F76-B8BB-6C83CC5D2337}"
ProjectSection(SolutionItems) = preProject
Synapse\linkedService\FrameworkFunctions.json = Synapse\linkedService\FrameworkFunctions.json
Synapse\linkedService\Keys.json = Synapse\linkedService\Keys.json
Synapse\linkedService\SupportDatabase.json = Synapse\linkedService\SupportDatabase.json
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "trigger", "trigger", "{29DBE5FC-D1FE-4C49-9DA2-4115C7F830B4}"
ProjectSection(SolutionItems) = preProject
Synapse\trigger\FunctionalTestingTrigger.json = Synapse\trigger\FunctionalTestingTrigger.json
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Synapse", "Synapse", "{4A3176F1-B8E0-4D2B-861B-9A1655EB322E}"
ProjectSection(SolutionItems) = preProject
ARM Templates\Synapse\v2.0 Export.json = ARM Templates\Synapse\v2.0 Export.json
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{491422B7-393B-4421-BE9E-5B70E7746CC1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{491422B7-393B-4421-BE9E-5B70E7746CC1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{491422B7-393B-4421-BE9E-5B70E7746CC1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{491422B7-393B-4421-BE9E-5B70E7746CC1}.Release|Any CPU.Build.0 = Release|Any CPU
{202EBF84-A56B-4999-92A3-10F7FFE4EF25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{202EBF84-A56B-4999-92A3-10F7FFE4EF25}.Debug|Any CPU.Build.0 = Debug|Any CPU
{202EBF84-A56B-4999-92A3-10F7FFE4EF25}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{202EBF84-A56B-4999-92A3-10F7FFE4EF25}.Release|Any CPU.ActiveCfg = Release|Any CPU
{202EBF84-A56B-4999-92A3-10F7FFE4EF25}.Release|Any CPU.Build.0 = Release|Any CPU
{202EBF84-A56B-4999-92A3-10F7FFE4EF25}.Release|Any CPU.Deploy.0 = Release|Any CPU
{3AEAD846-DBE4-45AD-97DD-37E94BE009FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3AEAD846-DBE4-45AD-97DD-37E94BE009FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3AEAD846-DBE4-45AD-97DD-37E94BE009FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3AEAD846-DBE4-45AD-97DD-37E94BE009FD}.Release|Any CPU.Build.0 = Release|Any CPU
{777BB424-9D89-49E5-BE29-E73E0A0E159A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{777BB424-9D89-49E5-BE29-E73E0A0E159A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{777BB424-9D89-49E5-BE29-E73E0A0E159A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{777BB424-9D89-49E5-BE29-E73E0A0E159A}.Release|Any CPU.Build.0 = Release|Any CPU
{32D54B90-932D-44A3-911D-007C4B90BC55}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{32D54B90-932D-44A3-911D-007C4B90BC55}.Debug|Any CPU.Build.0 = Debug|Any CPU
{32D54B90-932D-44A3-911D-007C4B90BC55}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{32D54B90-932D-44A3-911D-007C4B90BC55}.Release|Any CPU.ActiveCfg = Release|Any CPU
{32D54B90-932D-44A3-911D-007C4B90BC55}.Release|Any CPU.Build.0 = Release|Any CPU
{32D54B90-932D-44A3-911D-007C4B90BC55}.Release|Any CPU.Deploy.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{997E1D61-E47F-48B0-8F67-09ED4AE92E0E} = {E081CE7B-3DE2-4AB7-8C3A-E58A075BD6F5}
{6B27406C-2C36-4BA1-AFC8-CEFC960D8EE6} = {E081CE7B-3DE2-4AB7-8C3A-E58A075BD6F5}
{9CEBE9B6-F1E4-43A8-B84D-FF7D43D5CB20} = {E081CE7B-3DE2-4AB7-8C3A-E58A075BD6F5}
{17586826-8BE9-4622-B12E-1683F2A20352} = {9CEBE9B6-F1E4-43A8-B84D-FF7D43D5CB20}
{04142829-7936-4C27-9891-FB086BEAE1AD} = {9CEBE9B6-F1E4-43A8-B84D-FF7D43D5CB20}
{C8F387D0-13CC-4AA5-892C-91D2F3403B55} = {CC7B607B-8C84-4E07-A6C8-326923752F92}
{FC7877EF-110F-4AD7-B203-EEECE6F08A86} = {E081CE7B-3DE2-4AB7-8C3A-E58A075BD6F5}
{EBC230DF-D45D-43E4-A74E-32ADA3DDAE7A} = {5A56A63A-351D-467D-A2DA-FDB3C9CBD252}
{20313ECA-118E-408D-BB42-8094A7A9CD20} = {CC7B607B-8C84-4E07-A6C8-326923752F92}
{463330CD-189F-42B4-984A-8D3C1385645B} = {CC7B607B-8C84-4E07-A6C8-326923752F92}
{6809EDBD-125D-440E-8486-9CFAB9BB5B7D} = {17586826-8BE9-4622-B12E-1683F2A20352}
{398CB5BE-3687-4F95-8EAA-54EE0DAC4E6C} = {6B8CC8C2-C4AA-4BC4-85EC-719348FC3B07}
{2181D7DA-8237-418F-8CD9-CD1BF9843524} = {398CB5BE-3687-4F95-8EAA-54EE0DAC4E6C}
{6E660431-66E0-4B1A-BCFC-8FCBF1C646F2} = {2181D7DA-8237-418F-8CD9-CD1BF9843524}
{21058901-FBEE-4D40-83E0-21B05636417B} = {398CB5BE-3687-4F95-8EAA-54EE0DAC4E6C}
{7F17593A-2CEF-4741-A4B7-C1CC79F12EB7} = {6B8CC8C2-C4AA-4BC4-85EC-719348FC3B07}
{F495E5FB-B908-4F76-B8BB-6C83CC5D2337} = {6B8CC8C2-C4AA-4BC4-85EC-719348FC3B07}
{29DBE5FC-D1FE-4C49-9DA2-4115C7F830B4} = {6B8CC8C2-C4AA-4BC4-85EC-719348FC3B07}
{4A3176F1-B8E0-4D2B-861B-9A1655EB322E} = {CC7B607B-8C84-4E07-A6C8-326923752F92}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {170F5302-BB9C-4569-8F43-D859C7678EF0}
EndGlobalSection
EndGlobal
================================================
FILE: README.md
================================================
# Read Me - Orchestrate.[procfwk](http://procfwk.com/)
For complete documentation on this solution see [procfwk.com](http://procfwk.com/).
## ProcFwk Has Become CF.Cumulus.Control
See blog: [mrpaulandrew.com](https://mrpaulandrew.com/2024/01/07/procfwk-is-getting-an-upgrade-to-cf-cumulus/)
See new product page: [cloudformations.org/cumulus](https://www.cloudformations.org/cumulus?utm_source=pa&utm_medium=github&utm_campaign=cumulus&utm_content=l2)
[  ](https://mrpaulandrew.github.io/procfwk/procfwk-to-cumulus.png)
ProcFwk will receive no further development beyond December 2023.
## Framework Capabilities
* Granular metadata control.
* Metadata integrity checking.
* Global properties.
* Complete pipeline dependency chains.
* Concurrent batch executions (hourly/daily/monthly).
* Execution restart-ability.
* Parallel pipeline execution.
* Full execution and error logs.
* Operational dashboards.
* Low cost orchestration.
* Disconnection between framework and Worker pipelines.
* Cross Tenant/Subscription/Data Factory control flows.
* Pipeline parameter support.
* Simple troubleshooting.
* Easy deployment.
* Email alerting.
* Automated testing.
* Azure Key Vault integration.
* Is pipeline already running checks.
## Complete Data Factory Activity Chain
[  ](https://mrpaulandrew.github.io/procfwk/activitychain-full.png)
## Issues
If you've found a bug or have a new feature request please log the details using the repository issues.
Go to... [Issues](https://github.com/mrpaulandrew/procfwk/issues)
## Projects
Go to... [External Requests](https://github.com/mrpaulandrew/procfwk/projects/2)
Go to... [Internal Backlog](https://github.com/mrpaulandrew/procfwk/projects/1)
## Release Details
| Version | Overview | Version Details & Release Notes |
|:----:|--------------|--------|
| 2.0 |Azure Synapse Analytics fully supported as an interchangeable orchestrator of pipelines within the procfwk.|GitHub Pages: [Orchestrators](https://mrpaulandrew.github.io/procfwk/orchestrators)[Orchestrator Types](https://mrpaulandrew.github.io/procfwk/orchestratortypes) Release Summary Video: [YouTube - procfwk Playlist](https://www.youtube.com/c/mrpaulandrew)
GitHub Issues:[procfwk #95](https://github.com/mrpaulandrew/procfwk/issues/95) |
| 2.0-beta |Azure Synapse Analytics **Beta** support added.
Development of Azure Functions App completed using the Synapse namespace: _Azure.Analytics.Synapse.Artifacts_ with version **1.0.0-beta.1** of the NuGet package.|GitHub Issues:[procfwk #21](https://github.com/mrpaulandrew/procfwk/issues/21) |
| 1.9.2 |Batch Executions added, plus:- Exception Pipeline
- Running Pipeline Check
- Pipeline Parameter Last Values
- Worker Pipeline Validation
|GitHub Pages: [Batch Executions](https://mrpaulandrew.github.io/procfwk/executionbatches) Release Demo Summary Video: [YouTube - procfwk Playlist](https://www.youtube.com/c/mrpaulandrew)
GitHub Issues:[procfwk #78](https://github.com/mrpaulandrew/procfwk/issues/78)
[procfwk #77](https://github.com/mrpaulandrew/procfwk/issues/77)
[procfwk #71](https://github.com/mrpaulandrew/procfwk/issues/71)
[procfwk #73](https://github.com/mrpaulandrew/procfwk/issues/73)
[procfwk #80](https://github.com/mrpaulandrew/procfwk/issues/80)
[procfwk #72](https://github.com/mrpaulandrew/procfwk/issues/72) |
| 1.9.1 |Activity Policy Update, plus:- Secure Activity Inputs/Outputs.
- Execution Wrapper Hardening.
- New Activity Icons and Framework Factory Cosmetics.
|GitHub Issues:[procfwk #65](https://github.com/mrpaulandrew/procfwk/issues/65)
[procfwk #66](https://github.com/mrpaulandrew/procfwk/issues/66)
[procfwk #67](https://github.com/mrpaulandrew/procfwk/issues/67)
[procfwk #69](https://github.com/mrpaulandrew/procfwk/issues/69) |
| 1.9.0 |Cross Tenant & Subscription Support added, plus:- New integration tests created.
- Infant pipeline refactoring.
- tSQLt project added.
|GitHub Issues:[procfwk #34](https://github.com/mrpaulandrew/procfwk/issues/34)
[procfwk #35](https://github.com/mrpaulandrew/procfwk/issues/35)
[procfwk #46](https://github.com/mrpaulandrew/procfwk/issues/46)
[procfwk #55](https://github.com/mrpaulandrew/procfwk/issues/55)
[procfwk #56](https://github.com/mrpaulandrew/procfwk/issues/56)
[procfwk #59](https://github.com/mrpaulandrew/procfwk/issues/59) |
| 1.8.6 |Pipeline Expressions Refactored to Use Variables added, plus:- New integration tests created.
- Complete activity chain redrawn in Visio.
|GitHub Issues:[procfwk #51](https://github.com/mrpaulandrew/procfwk/issues/51)
[procfwk #52](https://github.com/mrpaulandrew/procfwk/issues/52) |
| 1.8.5 |Execution Precursor added, plus:- PowerShell helper to add initial Worker metadata.
|[procfwk v1.8.5 - Execution Precursor](https://mrpaulandrew.com/2020/08/17/adf-procfwk-v1-8-5-execution-precursor/) |
| 1.8.4 |Database Schema Reorganise and Restructuring |[procfwk v1.8.4 - Database Schema Reorganise and Restructuring](https://mrpaulandrew.com/2020/07/23/adf-procfwk-v1-8-4-database-schema-reorganise-and-restructuring/) |
| 1.8.3 |Bug Fixes from the Community, including:- Email alerts sent to blank email addresses due to wrong flow in Child pipeline.
- Worker pipelines cancelled during an execution fail when the framework is restarted due to missing Parent pipeline clean up condition.
|GitHub Issues:[procfwk #38](https://github.com/mrpaulandrew/procfwk/issues/38)
[procfwk #37](https://github.com/mrpaulandrew/procfwk/issues/37) |
| 1.8.2 |Optionally Store SPN Details in Azure Key Vault |[procfwk v1.8.2 - Optionally Store SPN Details in Azure Key Vault](https://mrpaulandrew.com/2020/07/22/adf-procfwk-v1-8-2-optionally-store-spn-details-in-azure-key-vault/) |
| 1.8.1 |Automated Framework Pipeline Testing added, including tests for:- A simple grandparent run.
- All types of failure dependency handling.
- Metadata checks when pipelines and staged are disabled.
- No pipeline parameters provided.
|Blog Series:
- [Set up automated testing for Azure Data Factory](https://richardswinbank.net/adf/set_up_automated_testing_for_azure_data_factory)
- [Automate integration tests in Azure Data Factory](https://richardswinbank.net/adf/automate_integration_tests_in_azure_data_factory)
- [Isolated functional tests for Azure Data Factory](https://richardswinbank.net/adf/isolated_functional_tests_for_azure_data_factory)
- [Testing Azure Data Factory in your CI/CD pipeline](https://richardswinbank.net/adf/testing_azure_data_factory_in_your_cicd_pipeline)
- [Unit testing Azure Data Factory pipelines](https://richardswinbank.net/adf/unit_testing_azure_data_factory_pipelines)
- [Calculating Azure Data Factory test coverage](https://richardswinbank.net/adf/calculating_azure_data_factory_test_coverage)
|
| 1.8.0 |Complete Pipeline Dependency Chains For Failure Handling added, plus:- Clean up of a previous execution run if Workers appear as running.
- New metadata integrity checks.
- Internal get property value function added.
|[procfwk v1.8 - Complete Pipeline Dependency Chains For Failure Handling](https://mrpaulandrew.com/2020/07/01/adf-procfwk-v1-8-complete-pipeline-dependency-chains-for-failure-handling/) |
| 1.7.3 |Data Factory Deployment Updated To Use azure.datafactory.tools PowerShell Module |[SQLPlayer/azure.datafactory.tools](https://github.com/SQLPlayer/azure.datafactory.tools) |
| 1.7.2 |Pipeline Parameter NULL Handling added, plus:- Worker pipelines with a status of 'Running' protected from a new execution start/restart.
|[procfwk v1.7.2 - NULL Pipeline Parameters Handled](https://mrpaulandrew.com/2020/06/22/adf-procfwk-v1-7-2-null-pipeline-parameters-handled/) |
| 1.7.1 |Alerting Check Bug Fix added, plus:- Pipeline parameter value size limit removed.
|[procfwk v1.7.1 - Alerting Bug Fix And Pipeline Parameter Size Limit Removed](https://mrpaulandrew.com/2020/06/12/adf-procfwk-v1-7-1-alerting-bug-fix-and-pipeline-parameter-size-limit-removed/) |
| 1.7.0 |Pipleline EMail Alerting added, plus:- Send email Function implemented and hardened.
- Handy Notebook updates.
- Activity failure paths improved.
- MIT license and code of conduct added.
- Error table bug fix. Error code attribute; INT to VARCHAR
|[procfwk v1.7 - Pipeline Email Alerting](https://mrpaulandrew.com/2020/06/08/adf-procfwk-v1-7-pipeline-email-alerting/) |
| 1.6.0 |Error Details for Failed Activities Captured, plus:- Pipeline parameters used at runtime captured in execution logs.
- Emailing Function added, not yet implemented.
- Unknown Worker outcomes optionally blocks downstream stages.
- Solution housekeeping.
|[procfwk v1.6 - Error Details for Failed Activities Captured](https://mrpaulandrew.com/2020/05/19/adf-procfwk-v1-6-error-details-for-failed-activities-captured/) |
| 1.5.0 |Power BI Dashboard for Framework Executions, plus:- Worker Parallelism View.
- Pipeline Run ID now logged.
- Logging Attributes Bug Fix.
|[procfwk v1.5 - Power BI Dashboard for Framework Executions](https://mrpaulandrew.com/2020/05/01/adf-procfwk-v1-5-power-bi-dashboard-for-framework-executions/) |
| 1.4.0 |Enhancements for Long Running Pipelines, plus:- Pipeline check status function added.
- Function Data Factory client moved to internal class.
- SQL GETDATE() changed to GETUTCDATE().
- Glossary created, [here](https://github.com/mrpaulandrew/procfwk/blob/master/Glossary.md).
- Updated database views.
|[procfwk v1.4 - Enhancements for Long Running Pipelines](https://mrpaulandrew.com/2020/04/20/adf-procfwk-v1-4-enhancements-for-long-running-pipelines/) |
| 1.3.0 |Metadata Integrity Checks, plus: - Logical pipeline predecessors.
- Data Factory Powershell deployment script.
- Helper Notebook.
- Database objects renames and solution tidy up.
|[procfwk v1.3 - Metadata Integrity Checks](https://mrpaulandrew.com/2020/04/07/adf-procfwk-v1-3-metadata-integrity-checks/) |
| 1.2.0 |Execution Restartability, plus: - Data Factory annotations and descriptions.
- Database covering indexes.
- Pipeline log status changed from 'Started' to 'Preparing'.
- Pipeline log start date/time now set in child pipeline.
|[procfwk v1.2 - Execution Restartability](https://mrpaulandrew.com/2020/03/24/adf-procfwk-v1-2-execution-restartability/) |
| 1.1.0 |Service Principal Handling via Metadata, plus: - Data Factory table.
- Properties table and view.
- Function body bug fix.
- New sample data.
|[procfwk v1.1 - Service Principal Handling via Metadata](https://mrpaulandrew.com/2020/03/17/adf-procfwk-v1-1-service-principal-handling-via-metadata/) |
| 1.0.0 |Simple framework designed and base compontents built.
- Part 1 - Design, concepts, service coupling, caveats, problems.
- Part 2 - Database build and metadata.
- Part 3 - Data Factory build.
- Part 4 - Execution, conclusions, enhancements.
|Blog Series:
[Creating a Simple Staged Metadata Driven Processing Framework for Azure Data Factory Pipelines](https://mrpaulandrew.com/2020/02/25/creating-a-simple-staged-metadata-driven-processing-framework-for-azure-data-factory-pipelines-part-1-of-4/) |
================================================
FILE: Synapse/dataflow/MDF _Order_Count.json
================================================
{
"name": "MDF _Order_Count",
"properties": {
"type": "MappingDataFlow",
"typeProperties": {
"sources": [],
"sinks": [],
"transformations": [],
"script": ""
}
}
}
================================================
FILE: Synapse/dataset/GetSetMetadata.json
================================================
{
"name": "GetSetMetadata",
"properties": {
"description": "Single generic dataset used to get and set all database metadata.",
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"procfwk"
],
"type": "AzureSqlTable",
"schema": []
}
}
================================================
FILE: Synapse/factory/FrameworkFactory.json
================================================
{
"name": "FrameworkFactory"
}
================================================
FILE: Synapse/integrationRuntime/AutoResolveIntegrationRuntime.json
================================================
{
"name": "AutoResolveIntegrationRuntime",
"properties": {
"type": "Managed",
"typeProperties": {
"computeProperties": {
"location": "AutoResolve",
"dataFlowProperties": {
"computeType": "General",
"coreCount": 8,
"timeToLive": 0
}
}
}
}
}
================================================
FILE: Synapse/linkedService/FrameworkFunctions.json
================================================
{
"name": "FrameworkFunctions",
"properties": {
"annotations": [
"procfwk"
],
"type": "AzureFunction",
"typeProperties": {
"functionAppUrl": "https://frameworksupportfunctions.azurewebsites.net",
"functionKey": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "FrameworkFunctionsKey"
}
},
"description": "Interact with the Azure Functions App used as middle ware when making requests to Worker pipelines. Authentication done at the Function App level."
}
}
================================================
FILE: Synapse/linkedService/Keys.json
================================================
{
"name": "Keys",
"properties": {
"annotations": [
"procfwk"
],
"type": "AzureKeyVault",
"typeProperties": {
"baseUrl": "https://FrameworkKeys.vault.azure.net/"
},
"description": "Connection to Key Vault for all other ADF linked service credentials required to run the processing framework."
}
}
================================================
FILE: Synapse/linkedService/SupportDatabase.json
================================================
{
"name": "SupportDatabase",
"properties": {
"description": "Connection between ADF and processing framework metadata SQLDB.",
"annotations": [
"procfwk"
],
"type": "AzureSqlDatabase",
"typeProperties": {
"connectionString": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "Keys",
"type": "LinkedServiceReference"
},
"secretName": "FrameworkMetadataDev"
}
}
}
}
================================================
FILE: Synapse/linkedService/covid-tracking.json
================================================
{
"name": "covid-tracking",
"properties": {
"annotations": [],
"type": "AzureBlobStorage",
"typeProperties": {
"sasUri": "https://pandemicdatalake.blob.core.windows.net/public/curated/covid-19/covid_tracking/latest/covid_tracking.parquet?\"\""
}
}
}
================================================
FILE: Synapse/linkedService/procfwkforsynapse-WorkspaceDefaultSqlServer.json
================================================
{
"name": "procfwkforsynapse-WorkspaceDefaultSqlServer",
"type": "Microsoft.Synapse/workspaces/linkedservices",
"properties": {
"typeProperties": {
"connectionString": "Data Source=tcp:procfwkforsynapse.sql.azuresynapse.net,1433;Initial Catalog=@{linkedService().DBName}"
},
"parameters": {
"DBName": {
"type": "String"
}
},
"type": "AzureSqlDW",
"connectVia": {
"referenceName": "AutoResolveIntegrationRuntime",
"type": "IntegrationRuntimeReference"
},
"annotations": []
}
}
================================================
FILE: Synapse/linkedService/procfwkforsynapse-WorkspaceDefaultStorage.json
================================================
{
"name": "procfwkforsynapse-WorkspaceDefaultStorage",
"type": "Microsoft.Synapse/workspaces/linkedservices",
"properties": {
"typeProperties": {
"url": "https://frameworkdatalake01.dfs.core.windows.net"
},
"type": "AzureBlobFS",
"connectVia": {
"referenceName": "AutoResolveIntegrationRuntime",
"type": "IntegrationRuntimeReference"
},
"annotations": []
}
}
================================================
FILE: Synapse/notebook/Getting Started with Delta Lake.json
================================================
{
"name": "Getting Started with Delta Lake",
"properties": {
"nbformat": 4,
"nbformat_minor": 2,
"bigDataPool": {
"referenceName": "SampleSpark",
"type": "BigDataPoolReference"
},
"sessionProperties": {
"driverMemory": "28g",
"driverCores": 4,
"executorMemory": "28g",
"executorCores": 4,
"numExecutors": 2,
"conf": {
"spark.dynamicAllocation.enabled": "false",
"spark.dynamicAllocation.minExecutors": "2",
"spark.dynamicAllocation.maxExecutors": "2"
}
},
"metadata": {
"saveOutput": true,
"kernelspec": {
"name": "synapse_sparkdotnet",
"display_name": "Synapse SparkDotNet"
},
"language_info": {
"name": "csharp"
},
"a365ComputeOptions": {
"id": "/subscriptions/450eaf4d-1124-4b6d-b490-95dedc991c1e/resourceGroups/ADF.procfwk/providers/Microsoft.Synapse/workspaces/procfwkforsynapse/bigDataPools/SampleSpark",
"name": "SampleSpark",
"type": "Spark",
"endpoint": "https://procfwkforsynapse.dev.azuresynapse.net/livyApi/versions/2019-11-01-preview/sparkPools/SampleSpark",
"auth": {
"type": "AAD",
"authResource": "https://dev.azuresynapse.net"
},
"sparkVersion": "2.4",
"nodeCount": 3,
"cores": 8,
"memory": 56,
"automaticScaleJobs": false
},
"sessionKeepAliveTimeout": 30
},
"cells": [
{
"cell_type": "markdown",
"source": [
"# Hitchhiker's Guide to Delta Lake (.NET for Spark C#)\n",
"\n",
"This tutorial has been adapted for more clarity from its original counterpart [here](https://docs.delta.io/latest/quick-start.html). This notebook helps you quickly explore the main features of [Delta Lake](https://github.com/delta-io/delta). It provides code snippets that show how to read from and write to Delta Lake tables from interactive, batch, and streaming queries.\n",
"\n",
"Here's what we will cover:\n",
"* Create a table\n",
"* Understanding meta-data\n",
"* Read data\n",
"* Update table data\n",
"* Overwrite table data\n",
"* Conditional update without overwrite\n",
"* Read older versions of data using Time Travel\n",
"* Write a stream of data to a table\n",
"* Read a stream of changes from a table"
]
},
{
"cell_type": "markdown",
"source": [
"## Configuration\n",
"Make sure you modify this as appropriate."
]
},
{
"cell_type": "code",
"source": [
"var sessionId = (new Random()).Next(10000000);\n",
"var deltaTablePath = $\"/delta/delta-table-{sessionId}\";\n",
"\n",
"deltaTablePath"
],
"execution_count": 1
},
{
"cell_type": "markdown",
"source": [
"## Create a table\n",
"To create a Delta Lake table, write a DataFrame out in the **delta** format. You can use existing Spark SQL code and change the format from parquet, csv, json, and so on, to delta.\n",
"\n",
"These operations create a new Delta Lake table using the schema that was inferred from your DataFrame. For the full set of options available when you create a new Delta Lake table, see Create a table and Write to a table (subsequent cells in this notebook)."
]
},
{
"cell_type": "code",
"source": [
"var data = spark.Range(0,5);\n",
"data.Show();\n",
"data.Write().Format(\"delta\").Save(deltaTablePath);"
],
"execution_count": 2
},
{
"cell_type": "markdown",
"source": [
"## Understanding Meta-data\n",
"\n",
"In Delta Lake, meta-data is no different from data i.e., it is stored next to the data. Therefore, an interesting side-effect here is that you can peek into meta-data using regular Spark APIs. "
]
},
{
"cell_type": "code",
"source": [
"using System.Linq;\n",
"spark.Read().Text($\"{deltaTablePath}/_delta_log/\").Collect().ToList().ForEach(x => Console.WriteLine(x.GetAs(\"value\")));"
],
"execution_count": 3
},
{
"cell_type": "markdown",
"source": [
"## Read data\n",
"\n",
"You read data in your Delta Lake table by specifying the path to the files."
]
},
{
"cell_type": "code",
"source": [
"var df = spark.Read().Format(\"delta\").Load(deltaTablePath);\n",
"df.Show()"
],
"execution_count": 4
},
{
"cell_type": "markdown",
"source": [
"## Update table data\n",
"\n",
"Delta Lake supports several operations to modify tables using standard DataFrame APIs. This example runs a batch job to overwrite the data in the table.\n",
""
]
},
{
"cell_type": "code",
"source": [
"var data = spark.Range(5,10);\n",
"data.Write().Format(\"delta\").Mode(\"overwrite\").Save(deltaTablePath);\n",
"df.Show();"
],
"execution_count": 5
},
{
"cell_type": "markdown",
"source": [
"When you now inspect the meta-data, what you will notice is that the original data is over-written. Well, not in a true sense but appropriate entries are added to Delta's transaction log so it can provide an \"illusion\" that the original data was deleted. We can verify this by re-inspecting the meta-data. You will see several entries indicating reference removal to the original data."
]
},
{
"cell_type": "code",
"source": [
"spark.Read().Text($\"{deltaTablePath}/_delta_log/\").Collect().ToList().ForEach(x => Console.WriteLine(x.GetAs(\"value\")));"
],
"execution_count": 6
},
{
"cell_type": "markdown",
"source": [
"## Save as catalog tables\n",
"\n",
"Delta Lake can write to managed or external catalog tables.\n",
""
]
},
{
"cell_type": "code",
"source": [
"// Write data to a new managed catalog table.\n",
"data.Write().Format(\"delta\").SaveAsTable(\"ManagedDeltaTable\");"
],
"execution_count": 7
},
{
"cell_type": "code",
"source": [
"// Define an external catalog table that points to the existing Delta Lake data in storage.\n",
"spark.Sql($\"CREATE TABLE ExternalDeltaTable USING DELTA LOCATION '{deltaTablePath}'\");"
],
"execution_count": 8
},
{
"cell_type": "code",
"source": [
"// List the 2 new tables.\n",
"spark.Sql(\"SHOW TABLES\").Show();\n",
"\n",
"// Explore their properties.\n",
"spark.Sql(\"DESCRIBE EXTENDED ManagedDeltaTable\").Show(truncate: 0);\n",
"spark.Sql(\"DESCRIBE EXTENDED ExternalDeltaTable\").Show(truncate: 0);"
],
"execution_count": 9
},
{
"cell_type": "markdown",
"source": [
"## Conditional update without overwrite\n",
"\n",
"Delta Lake provides programmatic APIs to conditional update, delete, and merge (upsert) data into tables. For more information on these operations, see [Table Deletes, Updates, and Merges](https://docs.delta.io/latest/delta-update.html)."
]
},
{
"cell_type": "code",
"source": [
"using Microsoft.Spark.Extensions.Delta;\n",
"using Microsoft.Spark.Extensions.Delta.Tables;\n",
"using Microsoft.Spark.Sql;\n",
"using static Microsoft.Spark.Sql.Functions;\n",
"\n",
"var deltaTable = DeltaTable.ForPath(deltaTablePath);"
],
"execution_count": 10
},
{
"cell_type": "code",
"source": [
"// Update every even value by adding 100 to it\n",
"deltaTable.Update(\n",
" condition: Expr(\"id % 2 == 0\"),\n",
" set: new Dictionary(){{ \"id\", Expr(\"id + 100\") }});\n",
"deltaTable.ToDF().Show();"
],
"execution_count": 11
},
{
"cell_type": "code",
"source": [
"// Delete every even value\n",
"deltaTable.Delete(condition: Expr(\"id % 2 == 0\"));\n",
"deltaTable.ToDF().Show();"
],
"execution_count": 12
},
{
"cell_type": "code",
"source": [
"// Upsert (merge) new data\n",
"var newData = spark.Range(20).As(\"newData\");\n",
"\n",
"deltaTable\n",
" .As(\"oldData\")\n",
" .Merge(newData, \"oldData.id = newData.id\")\n",
" .WhenMatched()\n",
" .Update(new Dictionary() {{\"id\", Lit(\"-1\")}})\n",
" .WhenNotMatched()\n",
" .Insert(new Dictionary() {{\"id\", Col(\"newData.id\")}})\n",
" .Execute();\n",
"\n",
"deltaTable.ToDF().Show(100);"
],
"execution_count": 13
},
{
"cell_type": "markdown",
"source": [
"## History\n",
"Delta's most powerful feature is the ability to allow looking into history i.e., the changes that were made to the underlying Delta Table. The cell below shows how simple it is to inspect the history."
]
},
{
"cell_type": "code",
"source": [
"deltaTable.History().Show(20, 1000, false);"
],
"execution_count": 14
},
{
"cell_type": "markdown",
"source": [
"## Read older versions of data using Time Travel\n",
"\n",
"You can query previous snapshots of your Delta Lake table by using a feature called Time Travel. If you want to access the data that you overwrote, you can query a snapshot of the table before you overwrote the first set of data using the versionAsOf option.\n",
"\n",
"Once you run the cell below, you should see the first set of data, from before you overwrote it. Time Travel is an extremely powerful feature that takes advantage of the power of the Delta Lake transaction log to access data that is no longer in the table. Removing the version 0 option (or specifying version 1) would let you see the newer data again. For more information, see [Query an older snapshot of a table (time travel)](https://docs.delta.io/latest/delta-batch.html#deltatimetravel)."
]
},
{
"cell_type": "code",
"source": [
"var df = spark.Read().Format(\"delta\").Option(\"versionAsOf\", 0).Load(deltaTablePath);\n",
"df.Show();"
],
"execution_count": 15
},
{
"cell_type": "markdown",
"source": [
"## Write a stream of data to a table\n",
"\n",
"You can also write to a Delta Lake table using Spark's Structured Streaming. The Delta Lake transaction log guarantees exactly-once processing, even when there are other streams or batch queries running concurrently against the table. By default, streams run in append mode, which adds new records to the table.\n",
"\n",
"For more information about Delta Lake integration with Structured Streaming, see [Table Streaming Reads and Writes](https://docs.delta.io/latest/delta-streaming.html).\n",
"\n",
"In the cells below, here's what we are doing:\n",
"\n",
"1. *Cell 28* Setup a simple Spark Structured Streaming job to generate a sequence and make the job write into our Delta Table\n",
"2. *Cell 30* Show the newly appended data\n",
"3. *Cell 31* Inspect history\n",
"4. *Cell 32* Stop the structured streaming job\n",
"5. *Cell 33* Inspect history <-- You'll notice appends have stopped"
]
},
{
"cell_type": "code",
"source": [
"var streamingDf = spark.ReadStream().Format(\"rate\").Load();\n",
"var stream = streamingDf.SelectExpr(\"value as id\").WriteStream().Format(\"delta\").Option(\"checkpointLocation\", $\"/tmp/checkpoint-{sessionId}\").Start(deltaTablePath);"
],
"execution_count": 16
},
{
"cell_type": "markdown",
"source": [
"## Read a stream of changes from a table\n",
"\n",
"While the stream is writing to the Delta Lake table, you can also read from that table as streaming source. For example, you can start another streaming query that prints all the changes made to the Delta Lake table."
]
},
{
"cell_type": "code",
"source": [
"deltaTable.ToDF().Sort(Col(\"id\").Desc()).Show(100);"
],
"execution_count": 17
},
{
"cell_type": "code",
"source": [
"deltaTable.History().Drop(\"userId\", \"userName\", \"job\", \"notebook\", \"clusterId\", \"isolationLevel\", \"isBlindAppend\").Show(20, 1000, false);"
],
"execution_count": 18
},
{
"cell_type": "code",
"source": [
"stream.Stop();"
],
"execution_count": 19
},
{
"cell_type": "code",
"source": [
"deltaTable.History().Drop(\"userId\", \"userName\", \"job\", \"notebook\", \"clusterId\", \"isolationLevel\", \"isBlindAppend\").Show(100, 1000, false);"
],
"execution_count": 20
},
{
"cell_type": "markdown",
"source": [
"## Compaction\n",
"\n",
"If a Delta Table is growing too large, you can compact it by repartitioning into a smaller number of files.\n",
"\n",
"The option `dataChange = false` is an optimization that tells Delta Lake to do the repartition without marking the underlying data as \"modified\". This ensures that any other concurrent operations (such as streaming reads/writes) aren't negatively impacted.\n",
""
]
},
{
"cell_type": "code",
"source": [
"int partitionCount = 2;\n",
"\n",
"spark.Read()\n",
" .Format(\"delta\")\n",
" .Load(deltaTablePath)\n",
" .Repartition(partitionCount)\n",
" .Write()\n",
" .Option(\"dataChange\", \"false\")\n",
" .Format(\"delta\")\n",
" .Mode(\"overwrite\")\n",
" .Save(deltaTablePath);"
],
"execution_count": 21
},
{
"cell_type": "markdown",
"source": [
"## Convert Parquet to Delta\n",
"You can do an in-place conversion from the Parquet format to Delta."
]
},
{
"cell_type": "code",
"source": [
"var parquetPath = $\"/parquet/parquet-table-{sessionId}\";\n",
"\n",
"var data = spark.Range(0,5);\n",
"data.Write().Parquet(parquetPath);\n",
"\n",
"// Confirm that the data isn't in the Delta format\n",
"DeltaTable.IsDeltaTable(parquetPath)"
],
"execution_count": 22
},
{
"cell_type": "code",
"source": [
"DeltaTable.ConvertToDelta(spark, $\"parquet.`{parquetPath}`\");\n",
"\n",
"//Confirm that the converted data is now in the Delta format\n",
"DeltaTable.IsDeltaTable(parquetPath)"
],
"execution_count": 23
},
{
"cell_type": "markdown",
"source": [
"## SQL Support\n",
"Delta supports table utility commands through SQL. You can use SQL to:\n",
"* Get a DeltaTable's history\n",
"* Vacuum a DeltaTable\n",
"* Convert a Parquet file to Delta\n",
""
]
},
{
"cell_type": "code",
"source": [
"spark.Sql($\"DESCRIBE HISTORY delta.`{deltaTablePath}`\").Show();"
],
"execution_count": 24
},
{
"cell_type": "code",
"source": [
"spark.Sql($\"VACUUM delta.`{deltaTablePath}`\").Show();"
],
"execution_count": 25
},
{
"cell_type": "code",
"source": [
"var parquetId = (new Random()).Next(10000000);\n",
"var parquetPath = $\"/parquet/parquet-table-{sessionId}-{parquetId}\";\n",
"\n",
"var data = spark.Range(0,5);\n",
"data.Write().Parquet(parquetPath);\n",
"\n",
"// Confirm that the data isn't in the Delta format\n",
"DeltaTable.IsDeltaTable(parquetPath);\n",
"\n",
"// Use SQL to convert the parquet table to Delta\n",
"spark.Sql($\"CONVERT TO DELTA parquet.`{parquetPath}`\");\n",
"\n",
"DeltaTable.IsDeltaTable(parquetPath);"
],
"execution_count": 26
}
]
}
}
================================================
FILE: Synapse/pipeline/01-Grandparent.json
================================================
{
"name": "01-Grandparent",
"properties": {
"description": "procfwk grandparent pipeline used optionally to bootstrap any wider processes in your Data Factory that then calls the processing framework.",
"activities": [
{
"name": "procfwk",
"description": "Call procfwk",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "02-Parent",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"BatchName": {
"value": "@pipeline().parameters.BatchName",
"type": "Expression"
}
}
}
}
],
"parameters": {
"BatchName": {
"type": "string",
"defaultValue": "NotUsed"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"procfwk",
"Grandparent"
]
}
}
================================================
FILE: Synapse/pipeline/02-Parent.json
================================================
{
"name": "02-Parent",
"properties": {
"description": "ADF.procfwk parent pipeline used to bootstrap the orchestration framework in perform the first level ForEach calls in sequence for the metadata stages.",
"activities": [
{
"name": "Get Stages",
"description": "Returns a distinct list of execution stages within the framework metadata.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Set Execution Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[procfwk].[GetStages]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@variables('ExecutionId')",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference"
},
"firstRowOnly": false
}
},
{
"name": "Execute Stages",
"description": "Top level ForEach to sequentially call all processing stages within the framework metadata. Items for iteration passed from the Get Stages lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Stages",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Stages').output.value",
"type": "Expression"
},
"isSequential": true,
"activities": [
{
"name": "Stage Executor",
"description": "Call to the framework generic child pipeline for a given execution stage.",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Log Stage Preparing",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "03-Child",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"StageId": {
"value": "@item().StageId",
"type": "Expression"
},
"ExecutionId": {
"value": "@variables('ExecutionId')",
"type": "Expression"
}
}
}
},
{
"name": "Log Stage Preparing",
"description": "Update the current execution table flagging all pipelines within the stage as preparing.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Check and Update Blockers",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogStagePreparing]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@variables('ExecutionId')",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check and Update Blockers",
"description": "Used to double check and stop the next execution stage if failures and blockers have be incurred. This also depends on the failure handling property value which defines the stored procedure behaviour.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[CheckForBlockedPipelines]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@variables('ExecutionId')",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Execution Wrapper",
"description": "Wrapper to reset and restart processing or create a completely new execution instance of the framework metadata.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Clean Up Previous Run",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[procfwk].[ExecutionWrapper]",
"storedProcedureParameters": {
"CallingOrchestratorName": {
"type": "String",
"value": {
"value": "@pipeline().DataFactory",
"type": "Expression"
}
},
"BatchName": {
"type": "String",
"value": {
"value": "@pipeline().parameters.BatchName",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference"
}
}
},
{
"name": "Check Outcome and Update Logs",
"description": "After a successful execution run the current execution metadata is moved to the long term logging table by this stored procedure call. Otherwise an error will be raised.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Stages",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[UpdateExecutionLog]",
"storedProcedureParameters": {
"PerformErrorCheck": {
"value": {
"value": "@bool(1)",
"type": "Expression"
},
"type": "Boolean"
},
"ExecutionId": {
"value": {
"value": "@variables('ExecutionId')",
"type": "Expression"
},
"type": "Guid"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check Previous Execution",
"description": "Query the current execution table for worker pipelines that require a clean up from the previous execution run.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Execute Precursor",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[procfwk].[CheckPreviousExeuction]",
"storedProcedureParameters": {
"BatchName": {
"type": "String",
"value": {
"value": "@pipeline().parameters.BatchName",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference"
},
"firstRowOnly": false
}
},
{
"name": "Clean Up Previous Run",
"description": "Handle Worker pipelines that are reported as Running when the parent pipeline is called again. Get what the actual status of those pipelines is.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Check Previous Execution",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Check Metadata Integrity",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Check Previous Execution').output.value",
"type": "Expression"
},
"isSequential": false,
"batchCount": 50,
"activities": [
{
"name": "Get SPN Details",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": true,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[procfwk].[GetWorkerAuthDetails]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
}
},
"PipelineId": {
"type": "Int32",
"value": {
"value": "@item().PipelineId",
"type": "Expression"
}
},
"StageId": {
"type": "Int32",
"value": {
"value": "@item().StageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference"
}
}
},
{
"name": "Log Pipeline Checking",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogPipelineChecking]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Pipeline Status",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Get SPN Details",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Log Pipeline Checking",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"functionName": "CheckPipelineStatus",
"method": "POST",
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',activity('Get SPN Details').output.firstRow.TenantId,'\",\n \"applicationId\": \"',activity('Get SPN Details').output.firstRow.AppId,'\",\n \"authenticationKey\": \"',activity('Get SPN Details').output.firstRow.AppSecret,'\",\n \"subscriptionId\": \"',activity('Get SPN Details').output.firstRow.SubscriptionId,'\",\n \"resourceGroupName\": \"',item().ResourceGroupName,'\",\n \"orchestratorName\": \"',item().OrchestratorName,'\",\n \"orchestratorType\": \"',item().OrchestratorType,'\",\n \"pipelineName\": \"',item().PipelineName,'\",\n \"runId\": \"',item().PipelineRunId,'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Set Pipeline Status",
"description": "Update the metadata depending on the actual pipeline outcome. Using the status as the case.",
"type": "Switch",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"on": {
"value": "@activity('Get Pipeline Status').output.ActualStatus",
"type": "Expression"
},
"cases": [
{
"value": "Failed",
"activities": [
{
"name": "Pipeline Status Failed",
"description": "Updates the current execution table with a pipeline status of failed if the function outcome is failed. Also blocks pipelines in the downstream execution stage.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogPipelineFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": null,
"type": "Guid"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Succeeded",
"activities": [
{
"name": "Pipeline Status Succeeded",
"description": "Updates the current execution table with a pipeline status of success if the function outcome is succeeded.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogPipelineSuccess]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Queued",
"activities": [
{
"name": "Pipeline Status Queued - Running",
"description": "Updates the current execution table with a pipeline status of running if the function outcome is queued.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "InProgress",
"activities": [
{
"name": "Pipeline Status InProgress - Running",
"description": "Updates the current execution table with a pipeline status of running if the function outcome is in progress.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Cancelled",
"activities": [
{
"name": "Pipeline Status Cancelled",
"description": "Updates the current execution table with a pipeline status of cancelled if the function outcome is cancelled.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogPipelineCancelled]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
},
"CleanUpRun": {
"value": {
"value": "@bool(1)",
"type": "Expression"
},
"type": "Boolean"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
],
"defaultActivities": [
{
"name": "Pipeline Status Unknown",
"description": "Updates the current execution table with a pipeline status of unknown if the function returns an unexpected outcome.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogPipelineUnknown]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
},
"CleanUpRun": {
"value": {
"value": "@bool(1)",
"type": "Expression"
},
"type": "Boolean"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Set Last Check DateTime",
"description": "Update the current execution table with a date time from when the function last checked the pipeline status.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogPipelineLastStatusCheck]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@item().LocalExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@item().PipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@item().StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Execute Precursor",
"description": "Uses the database property value ExecutionPrecursorProc to run any custom logic against the metadata database before the execution run starts.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[ExecutePrecursorProcedure]"
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Set Execution Id",
"description": "Set the local execution Id to a pipeline variable for each in several downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Execution Wrapper",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "ExecutionId",
"value": {
"value": "@activity('Execution Wrapper').output.firstRow.ExecutionId",
"type": "Expression"
}
}
},
{
"name": "Check Metadata Integrity",
"description": "Performs a series of checks on all metadata held in the framework SQLDB. This is intended to raise errors before an execution run even starts.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Precursor",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[CheckMetadataIntegrity]",
"storedProcedureParameters": {
"BatchName": {
"value": {
"value": "@pipeline().parameters.BatchName",
"type": "Expression"
},
"type": "String"
},
"DebugMode": {
"value": {
"value": "@bool(0)",
"type": "Expression"
},
"type": "Boolean"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
],
"parameters": {
"BatchName": {
"type": "string",
"defaultValue": "NotUsed"
}
},
"variables": {
"ExecutionId": {
"type": "String"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"procfwk",
"Parent"
]
}
}
================================================
FILE: Synapse/pipeline/03-Child.json
================================================
{
"name": "03-Child",
"properties": {
"description": "procfwk child pipeline used to execute Worker pipelines within a given execution stage. This pipeline will be called once for each stage, then execute all Workers in parallel.",
"activities": [
{
"name": "Get Pipelines",
"description": "Returns all pipelines from the metadata to be executed within a given processing stage.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[procfwk].[GetPipelinesInStage]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
}
},
"StageId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference"
},
"firstRowOnly": false
}
},
{
"name": "Execute Pipelines",
"description": "Second level ForEach to run in parallel all pipelines within the stage. Items for iteration passed from the Get Pipelines lookup activity.",
"type": "ForEach",
"dependsOn": [
{
"activity": "Get Pipelines",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Get Pipelines').output.value",
"type": "Expression"
},
"isSequential": false,
"batchCount": 50,
"activities": [
{
"name": "Worker Pipeline Executor",
"description": "Run the required worker pipeline and wait for its completion. Update metadata once done.",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "04-Infant",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"executionId": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"stageId": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"pipelineId": {
"value": "@item().PipelineId",
"type": "Expression"
}
}
}
}
]
}
}
],
"parameters": {
"StageId": {
"type": "int"
},
"ExecutionId": {
"type": "string"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"procfwk",
"Child"
]
}
}
================================================
FILE: Synapse/pipeline/04-Infant.json
================================================
{
"name": "04-Infant",
"properties": {
"description": "procfwk infant pipeline used to check when the processing pipeline called by the Child completes and passes the resulting status back to the metadata database.",
"activities": [
{
"name": "Execute Worker Pipeline",
"description": "The lowest level executor with the metadata framework to call existing processing pipelines within Data Factory. The function called will block processing and wait for an outcome.",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Log Pipeline Running",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Get Pipeline Params",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"functionName": "ExecutePipeline",
"method": "POST",
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',variables('WorkerCoreDetails')[0].tenantId,'\",\n \"applicationId\": \"',variables('WorkerCoreDetails')[0].applicationId,'\",\n \"authenticationKey\": \"',variables('WorkerCoreDetails')[0].authenticationKey,'\",\n \"subscriptionId\": \"',variables('WorkerCoreDetails')[0].subscriptionId,'\",\n \"resourceGroupName\": \"',variables('WorkerCoreDetails')[0].resourceGroupName,'\",\n\t\"orchestratorName\": \"',variables('WorkerCoreDetails')[0].orchestratorName,'\",\n \"orchestratorType\": \"',variables('WorkerCoreDetails')[0].orchestratorType,'\",\n \"pipelineName\": \"',variables('WorkerCoreDetails')[0].pipelineName,'\"',activity('Get Pipeline Params').output.firstRow.Params,'\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Pipeline Params",
"description": "Returns any parameters from metadata required for the processing pipeline being called. The output can be an empty string if no parameters are required.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[procfwk].[GetPipelineParameters]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference"
}
}
},
{
"name": "Log Pipeline Running",
"description": "Sets the current pipeline with a status of running within the current execution database table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Is Target Worker Validate",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogPipelineRunning]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Execute Function Activity Failure",
"description": "Handle true failures from calling out to the Azure Function and update the current execution table accordingly so a restart can occur.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Execute Worker Pipeline",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
},
"CallingActivity": {
"value": "ExecuteWorkerPipeline",
"type": "String"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Update Run Id",
"description": "Provide the actual ADF run ID back to the current execution table for long term logging and alignment between the metadata other Azure monitoring tools.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Set Run Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogPipelineRunId]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@variables('WorkerRunId')",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Check For Alerts",
"description": "Checks the properties tables and if any recipients in the database require alerts sending for the current pipeline ID.",
"type": "Lookup",
"dependsOn": [
{
"activity": "Update Run Id",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Pipeline Result",
"dependencyConditions": [
"Completed"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[procfwk].[CheckForEmailAlerts]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference"
},
"firstRowOnly": true
}
},
{
"name": "Send Alerts",
"description": "True = alerts need sending.\nFalse = do nothing.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Check For Alerts",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@activity('Check For Alerts').output.firstRow.SendAlerts",
"type": "Expression"
},
"ifTrueActivities": [
{
"name": "Get Email Parts",
"description": "Return all required content from the metadata database to send an email alerting using the procfwk. The lookup returns the exact content for the function body request.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": true,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[procfwk].[GetEmailAlertParts]",
"storedProcedureParameters": {
"PipelineId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference"
},
"firstRowOnly": true
}
},
{
"name": "Call Email Sender",
"description": "Pass off email request to Utils Send Email pipeline.",
"type": "ExecutePipeline",
"dependsOn": [
{
"activity": "Get Email Parts",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "Email Sender",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"Recipients": {
"value": "@activity('Get Email Parts').output.firstRow.emailRecipients",
"type": "Expression"
},
"CcRecipients": {
"value": "@activity('Get Email Parts').output.firstRow.emailCcRecipients",
"type": "Expression"
},
"BccRecipients": {
"value": "@activity('Get Email Parts').output.firstRow.emailBccRecipients",
"type": "Expression"
},
"Subject": {
"value": "@activity('Get Email Parts').output.firstRow.emailSubject",
"type": "Expression"
},
"Body": {
"value": "@activity('Get Email Parts').output.firstRow.emailBody",
"type": "Expression"
},
"Importance": {
"value": "@activity('Get Email Parts').output.firstRow.emailImportance",
"type": "Expression"
}
}
}
}
]
}
},
{
"name": "Wait Until Pipeline Completes",
"description": "Loops until the Worker pipeline called completes.\n\nSimple status:\n- Running = new iteration.\n- Done = break.",
"type": "Until",
"dependsOn": [
{
"activity": "Get Wait Duration",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Execute Worker Pipeline",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Run Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@variables('WorkerPipelineState')",
"type": "Expression"
},
"activities": [
{
"name": "Get Worker Pipeline Status",
"description": "Checks the status of a given processing pipeline and provides the value for the downstream framework activities to act upon.",
"type": "AzureFunctionActivity",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"functionName": "CheckPipelineStatus",
"method": "POST",
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',variables('WorkerCoreDetails')[0].tenantId,'\",\n \"applicationId\": \"',variables('WorkerCoreDetails')[0].applicationId,'\",\n \"authenticationKey\": \"',variables('WorkerCoreDetails')[0].authenticationKey,'\",\n \"subscriptionId\": \"',variables('WorkerCoreDetails')[0].subscriptionId,'\",\n \"resourceGroupName\": \"',variables('WorkerCoreDetails')[0].resourceGroupName,'\",\n\t\"orchestratorName\": \"',variables('WorkerCoreDetails')[0].orchestratorName,'\",\n \"orchestratorType\": \"',variables('WorkerCoreDetails')[0].orchestratorType,'\",\n \"pipelineName\": \"',variables('WorkerCoreDetails')[0].pipelineName,'\",\n \"runId\": \"',variables('WorkerRunId'),'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Wait If Running",
"description": "True = Do nothing.\nFalse = Wait, before the next iteration.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Set Worker State",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@variables('WorkerPipelineState')",
"type": "Expression"
},
"ifFalseActivities": [
{
"name": "Wait for Pipeline",
"description": "The processing pipeline is still running so Wait before checking its status again.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@activity('Get Wait Duration').output.firstRow.PropertyValue",
"type": "Expression"
}
}
}
]
}
},
{
"name": "Set Last Check DateTime",
"description": "Update the current execution table with a date time from when the Worker pipeline status was last checked as part of the Until iterations.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Worker Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogPipelineLastStatusCheck]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Check Function Activity Failure",
"description": "Report to the current execution table that the framework pipeline activity has failed. This failure is outside of the scope of the framework and is probably related to a wider platform problem.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Worker Pipeline Status",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"CallingActivity": {
"value": "GetWorkerPipelineStatus",
"type": "String"
},
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Set Worker State",
"description": "Set the bool state of the Worker pipeline to be used by the Until and If expressions. True = Complete, False = Running.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Worker Pipeline Status",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerPipelineState",
"value": {
"value": "@equals('Complete',activity('Get Worker Pipeline Status').output.SimpleStatus)",
"type": "Expression"
}
}
}
],
"timeout": "0.00:10:00"
}
},
{
"name": "Set Pipeline Result",
"description": "Receives the outcome from the function execution for a given processing pipeline and updates the current execution table with different pipelines status values depending on the result (case).",
"type": "Switch",
"dependsOn": [
{
"activity": "Wait Until Pipeline Completes",
"dependencyConditions": [
"Completed"
]
}
],
"userProperties": [],
"typeProperties": {
"on": {
"value": "@activity('Get Worker Pipeline Status').output.ActualStatus",
"type": "Expression"
},
"cases": [
{
"value": "Succeeded",
"activities": [
{
"name": "Pipeline Status Succeeded",
"description": "Updates the current execution table with a pipeline status of success if the function outcome is succeeded.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogPipelineSuccess]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Failed",
"activities": [
{
"name": "Pipeline Status Failed",
"description": "Updates the current execution table with a pipeline status of failed if the function outcome is failed. Also blocks pipelines in the downstream execution stage.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogPipelineFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"RunId": {
"value": {
"value": "@variables('WorkerRunId')",
"type": "Expression"
},
"type": "Guid"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Worker Pipeline Error Details",
"description": "Get the activity error details for the run ID of the worker pipeline called. Returns an array of all errors.",
"type": "AzureFunctionActivity",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"functionName": "GetActivityErrors",
"method": "POST",
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',variables('WorkerCoreDetails')[0].tenantId,'\",\n \"applicationId\": \"',variables('WorkerCoreDetails')[0].applicationId,'\",\n \"authenticationKey\": \"',variables('WorkerCoreDetails')[0].authenticationKey,'\",\n \"subscriptionId\": \"',variables('WorkerCoreDetails')[0].subscriptionId,'\",\n \"resourceGroupName\": \"',variables('WorkerCoreDetails')[0].resourceGroupName,'\",\n\t\"orchestratorName\": \"',variables('WorkerCoreDetails')[0].orchestratorName,'\",\n \"orchestratorType\": \"',variables('WorkerCoreDetails')[0].orchestratorType,'\",\n \"pipelineName\": \"',variables('WorkerCoreDetails')[0].pipelineName,'\",\n \"runId\": \"',variables('WorkerRunId'),'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Error Details",
"description": "Parses pipeline error details and persists them to the metadata database error log table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Get Worker Pipeline Error Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetErrorLogDetails]",
"storedProcedureParameters": {
"JsonErrorDetails": {
"value": {
"value": "@string(activity('Get Worker Pipeline Error Details').output)",
"type": "Expression"
},
"type": "String"
},
"LocalExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
},
{
"value": "Cancelled",
"activities": [
{
"name": "Pipeline Status Cancelled",
"description": "Updates the current execution table with a pipeline status of cancelled if the function outcome is cancelled.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogPipelineCancelled]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
],
"defaultActivities": [
{
"name": "Pipeline Status Unknown",
"description": "Updates the current execution table with a pipeline status of unknown if the function returns an unexpected outcome.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogPipelineUnknown]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Get Wait Duration",
"description": "Return wait duration in seconds from database properties table to be used during each Until iteration when the Worker pipeline is still running.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "PipelineStatusCheckDuration"
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference"
}
}
},
{
"name": "Set Run Id",
"description": "Set local variable from activity output once for value reuse in downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Execute Worker Pipeline",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerRunId",
"value": {
"value": "@activity('Execute Worker Pipeline').output.RunId",
"type": "Expression"
}
}
},
{
"name": "Validate Pipeline",
"description": "Query the target data factory and establish if the provided worker pipeline name is valid.",
"type": "AzureFunctionActivity",
"dependsOn": [
{
"activity": "Log Pipeline Validating",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Capture Worker Core Details as an Array",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": true
},
"userProperties": [],
"typeProperties": {
"functionName": "ValidatePipeline",
"method": "POST",
"body": {
"value": "@concat('\n{\n \"tenantId\": \"',variables('WorkerCoreDetails')[0].tenantId,'\",\n \"applicationId\": \"',variables('WorkerCoreDetails')[0].applicationId,'\",\n \"authenticationKey\": \"',variables('WorkerCoreDetails')[0].authenticationKey,'\",\n \"subscriptionId\": \"',variables('WorkerCoreDetails')[0].subscriptionId,'\",\n \"resourceGroupName\": \"',variables('WorkerCoreDetails')[0].resourceGroupName,'\",\n\t\"orchestratorName\": \"',variables('WorkerCoreDetails')[0].orchestratorName,'\",\n \"orchestratorType\": \"',variables('WorkerCoreDetails')[0].orchestratorType,'\",\n \"pipelineName\": \"',variables('WorkerCoreDetails')[0].pipelineName,'\"\n}')",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
},
{
"name": "Is Target Worker Validate",
"description": "True = the worker pipeline name is valid.\nFalse = the worker pipeline name is invalid. Raise an exception.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Validate Pipeline",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@bool(activity('Validate Pipeline').output.PipelineExists)",
"type": "Expression"
},
"ifFalseActivities": [
{
"name": "Throw Exception - Invalid Infant",
"description": "Throw an exception with details about the invalid worker pipeline name.",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "Throw Exception",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"Message": {
"value": "@concat('Worker pipeline [',variables('WorkerCoreDetails')[0].pipelineName,'] is not valid in target Orchestrator [',variables('WorkerCoreDetails')[0].orchestratorName,']')",
"type": "Expression"
}
}
}
},
{
"name": "Update Execution With Invalid Worker",
"description": "Update the current execution table with an informed status for the worker pipeline that couldn't be executed.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"CallingActivity": {
"value": "InvalidPipelineName",
"type": "String"
},
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
},
{
"name": "Log Validate Function Activity Failure",
"description": "Handle true failures from calling out to the Azure Function and update the current execution table accordingly so a restart can occur.",
"type": "SqlServerStoredProcedure",
"dependsOn": [
{
"activity": "Validate Pipeline",
"dependencyConditions": [
"Failed"
]
}
],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogActivityFailed]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
},
"CallingActivity": {
"value": "ValidatePipeline",
"type": "String"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Log Pipeline Validating",
"description": "Sets the current pipeline with a status of validating within the current execution database table.",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[procfwk].[SetLogPipelineValidating]",
"storedProcedureParameters": {
"ExecutionId": {
"value": {
"value": "@pipeline().parameters.ExecutionId",
"type": "Expression"
},
"type": "Guid"
},
"PipelineId": {
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
},
"type": "Int32"
},
"StageId": {
"value": {
"value": "@pipeline().parameters.StageId",
"type": "Expression"
},
"type": "Int32"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
},
{
"name": "Get Worker Core Details",
"description": "Return worker pipeline information for metadata database. Including target data factory, pipeline name and resource group. Return the SPN ID and Secret for the worker pipeline being executed. Called at this level as each pipeline can have a different SPN.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": true,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[procfwk].[GetWorkerDetailsWrapper]",
"storedProcedureParameters": {
"ExecutionId": {
"type": "Guid",
"value": {
"value": "@pipeline().parameters.executionId",
"type": "Expression"
}
},
"PipelineId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.pipelineId",
"type": "Expression"
}
},
"StageId": {
"type": "Int32",
"value": {
"value": "@pipeline().parameters.stageId",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference"
}
}
},
{
"name": "Capture Worker Core Details as an Array",
"description": "Add all worker pipeline details to a local variable array that can be accessed by each function call requiring the values.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Worker Core Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "WorkerCoreDetails",
"value": {
"value": "@array(activity('Get Worker Core Details').output.firstRow)",
"type": "Expression"
}
}
}
],
"parameters": {
"executionId": {
"type": "string"
},
"stageId": {
"type": "int"
},
"pipelineId": {
"type": "int"
}
},
"variables": {
"WorkerPipelineState": {
"type": "Boolean"
},
"WorkerRunId": {
"type": "String"
},
"WorkerCoreDetails": {
"type": "Array"
}
},
"folder": {
"name": "_ProcFwk"
},
"annotations": [
"procfwk",
"Infant"
]
}
}
================================================
FILE: Synapse/pipeline/Check For Running Pipeline.json
================================================
{
"name": "Check For Running Pipeline",
"properties": {
"description": "For a given pipeline and optional batch name establish if a pipeline run is already in progress. Throw an exception if it it.",
"activities": [
{
"name": "Filter Running Pipelines",
"description": "Filter the pipeline runs results for pipelines that exclude the current triggered run and that are currently running (in progress or queued).",
"type": "Filter",
"dependsOn": [
{
"activity": "Switch For Orchestrator Type",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@variables('PipelineRuns')",
"type": "Expression"
},
"condition": {
"value": "@and(not(equals(item().runId,pipeline().parameters.ThisRunId)),or(equals(item().status,'InProgress'),equals(item().status,'Queued')))",
"type": "Expression"
}
}
},
{
"name": "Get Framework Orchestrator Details",
"description": "Using the metadata orchestrators return details about the resource running the framework pipelines.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[procfwk].[GetFrameworkOrchestratorDetails]",
"storedProcedureParameters": {
"CallingOrchestratorName": {
"type": "String",
"value": {
"value": "@pipeline().DataFactory",
"type": "Expression"
}
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference"
}
}
},
{
"name": "Get Query Run Days Value",
"description": "Using the metadata properties table return the run days value to provide the API request with a date range for pipeline executions.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "PreviousPipelineRunsQueryRange"
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference"
}
}
},
{
"name": "If Pipeline Is Running",
"description": "If the running pipeline count is greater than or equal to one.\nTrue = raise an exception.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "If Using Batch Executions",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@greaterOrEquals(int(variables('RunCount')),1)",
"type": "Expression"
},
"ifTrueActivities": [
{
"name": "Throw Exception - Pipeline Running",
"description": "Using the utils pipeline raise an exception to stop the new trigger while a run is already in progress.",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "Throw Exception",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"Message": {
"value": "@concat('Provided pipeline name (',pipeline().parameters.PipelineName,') still has a run in progress or queued given the query range parameters set in the properties table.')",
"type": "Expression"
}
}
}
}
]
}
},
{
"name": "Get Execution Batch Status",
"description": "Using the metadata properties table return the flag to indicate if batch execution setting are enabled or disabled.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderStoredProcedureName": "[procfwk].[GetPropertyValue]",
"storedProcedureParameters": {
"PropertyName": {
"type": "String",
"value": "UseExecutionBatches"
}
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference"
}
}
},
{
"name": "If Using Batch Executions",
"description": "True = batch executions are enabled.\nFalse = batch execution are disabled.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Get Execution Batch Status",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Filter Running Pipelines",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@equals(activity('Get Execution Batch Status').output.firstRow.PropertyValue,string(1))",
"type": "Expression"
},
"ifFalseActivities": [
{
"name": "Set Run Count Without Batch",
"description": "Set the pipelines running count variable to be tested later.",
"type": "SetVariable",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"variableName": "RunCount",
"value": {
"value": "@string(activity('Filter Running Pipelines').output.FilteredItemsCount)",
"type": "Expression"
}
}
}
],
"ifTrueActivities": [
{
"name": "Filter for Batch Name",
"description": "Further filter the return pipeline runs for any running pipelines with the same batch name value.",
"type": "Filter",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"items": {
"value": "@activity('Filter Running Pipelines').output.value",
"type": "Expression"
},
"condition": {
"value": "@equals(item().parameters.BatchName,pipeline().parameters.BatchName)",
"type": "Expression"
}
}
},
{
"name": "Set Run Count for Batch",
"description": "Set the resulting pipeline running count variable to be tested later.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Filter for Batch Name",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "RunCount",
"value": {
"value": "@string(activity('Filter for Batch Name').output.FilteredItemsCount)",
"type": "Expression"
}
}
}
]
}
},
{
"name": "Set Subscription Id",
"description": "Set the subscription Id value to a local variable for use in various downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Framework Orchestrator Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "SubscriptionId",
"value": {
"value": "@activity('Get Framework Orchestrator Details').output.firstRow.SubscriptionId",
"type": "Expression"
}
}
},
{
"name": "Set Resource Group Name",
"description": "Set the resource group name value to a local variable for use in various downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Framework Orchestrator Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "ResourceGroupName",
"value": {
"value": "@activity('Get Framework Orchestrator Details').output.firstRow.ResourceGroupName",
"type": "Expression"
}
}
},
{
"name": "Set Orchestrator Type",
"description": "Set the orchestrator type value to a local variable for use in various downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Framework Orchestrator Details",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "OrchestratorType",
"value": {
"value": "@toUpper(activity('Get Framework Orchestrator Details').output.firstRow.OrchestratorType)",
"type": "Expression"
}
}
},
{
"name": "Switch For Orchestrator Type",
"description": "Switch and handle requests for both Azure Data Factory (ADF) and Azure Synapse Analytics (SYN).",
"type": "Switch",
"dependsOn": [
{
"activity": "Set Orchestrator Type",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Query Run Days",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Resource Group Name",
"dependencyConditions": [
"Succeeded"
]
},
{
"activity": "Set Subscription Id",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"on": {
"value": "@variables('OrchestratorType')",
"type": "Expression"
},
"cases": [
{
"value": "ADF",
"activities": [
{
"name": "Check for Valid ADF Pipeline Name",
"description": "Use the Azure Management API to return and establish if the framework pipeline exists in the target Data Factory instance, including being deployed.",
"type": "WebActivity",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"url": {
"value": "https://management.azure.com/subscriptions/@{variables('SubscriptionId')}/resourceGroups/@{variables('ResourceGroupName')}/providers/Microsoft.DataFactory/factories/@{pipeline().DataFactory}/pipelines/@{pipeline().parameters.PipelineName}?api-version=2018-06-01",
"type": "Expression"
},
"method": "GET",
"authentication": {
"type": "MSI",
"resource": "https://management.core.windows.net/"
}
}
},
{
"name": "Get ADF Pipeline Runs",
"description": "Use the Azure Management API to return a list of data factory pipeline runs within the given time window.",
"type": "WebActivity",
"dependsOn": [
{
"activity": "Check for Valid ADF Pipeline Name",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"url": {
"value": "https://management.azure.com/subscriptions/@{variables('SubscriptionId')}/resourceGroups/@{variables('ResourceGroupName')}/providers/Microsoft.DataFactory/factories/@{pipeline().DataFactory}/queryPipelineRuns?api-version=2018-06-01",
"type": "Expression"
},
"method": "POST",
"body": {
"value": "{\n \"lastUpdatedAfter\": \"@{adddays(utcnow(),int(variables('QueryRunDays')))}\",\n \"lastUpdatedBefore\": \"@{utcnow()}\",\n \"filters\": [\n {\n \"operand\": \"PipelineName\",\n \"operator\": \"Equals\",\n \"values\": [\n \"@{pipeline().parameters.PipelineName}\"\n ]\n }\n ]\n}",
"type": "Expression"
},
"authentication": {
"type": "MSI",
"resource": "https://management.core.windows.net/"
}
}
},
{
"name": "Set ADF Runs Output",
"description": "Set output to local array for use in downstream filtering and pipeline checks. Use the same array output for both switch cases.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get ADF Pipeline Runs",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "PipelineRuns",
"value": {
"value": "@activity('Get ADF Pipeline Runs').output.value",
"type": "Expression"
}
}
}
]
},
{
"value": "SYN",
"activities": [
{
"name": "Check for Valid SYN Pipeline Name",
"description": "Use the Azure Management API to return and establish if the framework pipeline exists in the target Synapse instance, including being deployed.\n\nSee: https://docs.microsoft.com/en-us/rest/api/synapse/data-plane/pipeline/getpipeline",
"type": "WebActivity",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"url": {
"value": "https://@{pipeline().DataFactory}.dev.azuresynapse.net/pipelines/@{pipeline().parameters.PipelineName}?api-version=2019-06-01-preview",
"type": "Expression"
},
"method": "GET",
"authentication": {
"type": "MSI",
"resource": "https://management.core.windows.net/"
}
}
},
{
"name": "Get SYN Pipeline Runs",
"description": "Use the Azure Management API to return a list of synapse pipeline runs within the given time window.\n\nSee: https://docs.microsoft.com/en-us/rest/api/synapse/data-plane/pipelinerun/querypipelinerunsbyworkspace",
"type": "WebActivity",
"dependsOn": [
{
"activity": "Check for Valid SYN Pipeline Name",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"url": {
"value": "https://@{pipeline().DataFactory}.dev.azuresynapse.net/queryPipelineRuns?api-version=2019-06-01-preview",
"type": "Expression"
},
"method": "POST",
"body": {
"value": "{\n \"lastUpdatedAfter\": \"@{adddays(utcnow(),int(variables('QueryRunDays')))}\",\n \"lastUpdatedBefore\": \"@{utcnow()}\",\n \"filters\": [\n {\n \"operand\": \"PipelineName\",\n \"operator\": \"Equals\",\n \"values\": [\n \"@{pipeline().parameters.PipelineName}\"\n ]\n }\n ]\n}",
"type": "Expression"
},
"authentication": {
"type": "MSI",
"resource": "https://management.core.windows.net/"
}
}
},
{
"name": "Set SYN Runs Output",
"description": "Set output to local array for use in downstream filtering and pipeline checks. Use the same array output for both switch cases.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get SYN Pipeline Runs",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "PipelineRuns",
"value": {
"value": "@activity('Get SYN Pipeline Runs').output.value",
"type": "Expression"
}
}
}
]
}
],
"defaultActivities": [
{
"name": "Throw Exception Invalid Orchestrator Type",
"description": "Throw exception if switch cases are not met.",
"type": "ExecutePipeline",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"pipeline": {
"referenceName": "Throw Exception",
"type": "PipelineReference"
},
"waitOnCompletion": true,
"parameters": {
"Message": "Invalid orchestrator type provided. Unable to check pipeline running state."
}
}
}
]
}
},
{
"name": "Set Query Run Days",
"description": "Set the query run days value to a local variable for use in various downstream activities.",
"type": "SetVariable",
"dependsOn": [
{
"activity": "Get Query Run Days Value",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"variableName": "QueryRunDays",
"value": {
"value": "@activity('Get Query Run Days Value').output.firstRow.PropertyValue",
"type": "Expression"
}
}
}
],
"parameters": {
"BatchName": {
"type": "string",
"defaultValue": "NotUsed"
},
"PipelineName": {
"type": "string"
},
"ThisRunId": {
"type": "string"
}
},
"variables": {
"SubscriptionId": {
"type": "String"
},
"RunCount": {
"type": "String"
},
"ResourceGroupName": {
"type": "String"
},
"OrchestratorType": {
"type": "String"
},
"QueryRunDays": {
"type": "String"
},
"PipelineRuns": {
"type": "Array"
}
},
"folder": {
"name": "_ProcFwk/_ProcFwkUtils"
},
"annotations": [
"procfwk",
"Utils"
]
}
}
================================================
FILE: Synapse/pipeline/Email Sender.json
================================================
{
"name": "Email Sender",
"properties": {
"description": "Provide a simple abstract over the send email function with request body item exposed as pipeline parameters.",
"activities": [
{
"name": "Send Email",
"description": "Use an Azure Function to perform an SMTP client email send operation.",
"type": "AzureFunctionActivity",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"functionName": "SendEmail",
"method": "POST",
"body": {
"value": "{\n\"emailRecipients\": \"@{pipeline().parameters.Recipients}\",\n\"emailCcRecipients\": \"@{pipeline().parameters.CcRecipients}\",\n\"emailBccRecipients\": \"@{pipeline().parameters.BccRecipients}\",\n\"emailSubject\": \"@{pipeline().parameters.Subject}\",\n\"emailBody\": \"@{pipeline().parameters.Body}\",\n\"emailImportance\": \"@{pipeline().parameters.Importance}\"\n}",
"type": "Expression"
}
},
"linkedServiceName": {
"referenceName": "FrameworkFunctions",
"type": "LinkedServiceReference"
}
}
],
"parameters": {
"Recipients": {
"type": "string"
},
"CcRecipients": {
"type": "string"
},
"BccRecipients": {
"type": "string"
},
"Subject": {
"type": "string"
},
"Body": {
"type": "string"
},
"Importance": {
"type": "string"
}
},
"folder": {
"name": "_ProcFwk/_ProcFwkUtils"
},
"annotations": [
"procfwk",
"Utils"
]
}
}
================================================
FILE: Synapse/pipeline/Intentional Error.json
================================================
{
"name": "Intentional Error",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait1",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
},
{
"name": "Raise Errors or Not",
"description": "Framework development worker simulator.",
"type": "IfCondition",
"dependsOn": [
{
"activity": "Wait1",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@equals(pipeline().parameters.RaiseErrors,'true')",
"type": "Expression"
},
"ifTrueActivities": [
{
"name": "Call Fail Procedure",
"type": "SqlServerStoredProcedure",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"storedProcedureName": "[dbo].[FailProcedure]",
"storedProcedureParameters": {
"RaiseError": {
"value": {
"value": "@pipeline().parameters.RaiseErrors",
"type": "Expression"
},
"type": "String"
}
}
},
"linkedServiceName": {
"referenceName": "SupportDatabase",
"type": "LinkedServiceReference"
}
}
]
}
}
],
"parameters": {
"RaiseErrors": {
"type": "string",
"defaultValue": "false"
},
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
}
}
================================================
FILE: Synapse/pipeline/Throw Exception.json
================================================
{
"name": "Throw Exception",
"properties": {
"description": "Provide a simple way of throwing an exception within Data Factory using TSQL error handling.",
"activities": [
{
"name": "Raise Error",
"description": "Using a SQL database to raise an error/exception but wrapped up as a data factory pipeline. Error message information exposed as a pipeline parameter.",
"type": "Lookup",
"dependsOn": [],
"policy": {
"timeout": "0.00:10:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "AzureSqlSource",
"sqlReaderQuery": {
"value": "RAISERROR('@{pipeline().parameters.Message}',16,1);",
"type": "Expression"
},
"queryTimeout": "02:00:00",
"partitionOption": "None"
},
"dataset": {
"referenceName": "GetSetMetadata",
"type": "DatasetReference"
},
"firstRowOnly": false
}
}
],
"parameters": {
"Message": {
"type": "string"
}
},
"folder": {
"name": "_ProcFwk/_ProcFwkUtils"
},
"annotations": [
"procfwk",
"Utils"
]
}
}
================================================
FILE: Synapse/pipeline/Wait 1.json
================================================
{
"name": "Wait 1",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait1",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
}
}
================================================
FILE: Synapse/pipeline/Wait 10.json
================================================
{
"name": "Wait 10",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait10",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
}
}
================================================
FILE: Synapse/pipeline/Wait 2.json
================================================
{
"name": "Wait 2",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait2",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
}
}
================================================
FILE: Synapse/pipeline/Wait 3.json
================================================
{
"name": "Wait 3",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait3",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
}
}
================================================
FILE: Synapse/pipeline/Wait 4.json
================================================
{
"name": "Wait 4",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait4",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
}
}
================================================
FILE: Synapse/pipeline/Wait 5.json
================================================
{
"name": "Wait 5",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait5",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
}
}
================================================
FILE: Synapse/pipeline/Wait 6.json
================================================
{
"name": "Wait 6",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait6",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
}
}
================================================
FILE: Synapse/pipeline/Wait 7.json
================================================
{
"name": "Wait 7",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait7",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
}
}
================================================
FILE: Synapse/pipeline/Wait 8.json
================================================
{
"name": "Wait 8",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait8",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 5
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
}
}
================================================
FILE: Synapse/pipeline/Wait 9.json
================================================
{
"name": "Wait 9",
"properties": {
"description": "Used just so the procfwk has something to call during development.",
"activities": [
{
"name": "Wait9",
"description": "Framework development worker simulator.",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": {
"value": "@pipeline().parameters.WaitTime",
"type": "Expression"
}
}
}
],
"parameters": {
"WaitTime": {
"type": "int",
"defaultValue": 15
}
},
"folder": {
"name": "_Workers"
},
"annotations": [
"_ProcFwkWorker"
]
}
}
================================================
FILE: Synapse/trigger/FunctionalTestingTrigger.json
================================================
{
"name": "FunctionalTestingTrigger",
"properties": {
"description": "Used for functional testing of the framework in a dedicated environment.",
"annotations": [
"procfwk"
],
"runtimeState": "Stopped",
"pipelines": [
{
"pipelineReference": {
"referenceName": "01-Grandparent",
"type": "PipelineReference"
}
}
],
"type": "ScheduleTrigger",
"typeProperties": {
"recurrence": {
"frequency": "Hour",
"interval": 2,
"startTime": "2020-04-06T15:00:00Z",
"timeZone": "UTC"
}
}
}
}