Question

Creating a package that will loop through all the servers in our different environments(DEV, UAT, PROD). We use service accounts and there is one service account for DEV and UAT and another for PROD. I am using a ForEach Loop Container/variables to set the connection string.

The issue: When the data flow in the loop trys to connect to the PROD servers they fail because they are using the DEV/UAT service account which obviously doesnt have access to PROD, which is fine. The problem is this kills the loop. Normally I would just put an event handler on the data flow and set the event handler's System Variable Propagate:OnError = False so that the error doesn't bubble up to the loop and kill it. Well this doesn't work because the OLE DB connection inside the data flow fails during validation(while the package is running) and apparently the Propagate = False setting only keeps an error from bubbling up if it occurs during the execution of a task and not the validation of a task.

I can set the MaximumErrorCount = 0 on everything including the package itself but that is a bit heavy handed and the package would always report that it ran successfully no matter what errors were encountered.

Running SQL Server 2008-R2

Link to an article on how to not kill your loop using the Propagate setting if someone isn't familiar with it.

Was it helpful?

Solution

One suggestion would be to put a Script Task before the Data Flow tasks that checks access to the connection string with a try-catch block and sets a variable upon failure, and then use that variable in a conditional split to determine whether to run the Data Flow or log that the connection string failed.

Alternatively, if you don't care about why it failed (since you already know it's because of permissions) you could just use a Precedence Constraint and only run Data Flows where the connection succeeded.

UPDATE:

Here's some working code for the Script Task:

 public void Main()         {

string connString = Dts.Variables["ConnectionStringToTest"].Value;

                try                {
                    using (OleDbConnection connection = new OleDbConnection()) {
                        connection.ConnectionString = connString;
                        connection.Open();
                    }
                    Dts.Variables["User::DatabaseCanConnect"].Value = true;                
                }
                catch (Exception ex) {
                    Dts.Variables["User::DatabaseCanConnect"].Value = false;
                }

                Dts.TaskResult = (int)ScriptResults.Success;
            }
  1. Create a variable called DatabaseCanConnect at the package scope. Set it to Boolean, it'll default to False.
  2. Create a Script Task. Edit the ReadWriteVariables property and add your new variable.
  3. Add to your ReadOnlyVariables whatever variable you're using to build the connection string out of your ForEach loop. I've named mine ConnectionStringToTest.
  4. Add the script code above as your Main() function. Note that this using an OleDbConnection. This should mimic whatever connection you're using for the connection manager you're modifying in your data flow. So if it's a SQL connection, use a SqlConnection instead.
  5. In your code, use the DatabaseCanConnect variable to determine flow from here. You can use it in a Precedence Constraint to prevent flow to the Data Flow, or use it in a Conditional Split (my preference, more visible to other developers) to log connection errors on failure and proceed as normal otherwise.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top