问题
I have been staring at this problem all day and I'm completely baffled by what I'm seeing. There are two issues occurring, and unfortunately, one of them only happens in Production so I can't test it the way I'd like.
I will give all the background and relevant information up front with the code at the end. Some of what I say in these next couple sections won't make much sense until you review the code.
Background info:
(I have triple verified all this information)
- This class is being called from a TFS 2010 WWF build template. It relies on a library I've created in another tool to deploy files to our Universe environment using UniDK
- The deployment itself is working fine, the problem is with the logging and return codes.
- The build is marked as "Success" if the class below returns a code of 0, "Partial Success" with a return code of 1, and "Failed" if there is any other return code.
- The files are only being deployed one time (objDeploy.DeployFiles() is only called once)
- serverInfo.ServerCount = 2
- serverInfo.ServerActive for the second environment (counter = 1) is False
- To help track down the issues, I have added additional logging in ProcessResults() to output the values of the different collections to a separate file, but I haven't had an opportunity to run it with the additional code
Symptoms:
- In Production, it is exiting with a return code of 1 (exitCode = 1)
- This is what is returned by the results string:
Results for server name
Deployment successful!
***********************
Results for server name
Deployment successful!
***********************
Results for server name
Deployment errors, please review the log
***********************
Results for server name
Deployment successful!
***********************
Results for server name
Deployment successful!
***********************
3. In QA, we have the "results for server name" message 6 times, but each time says the deployment is successful
4. Everything in the deployment log file shows that all files deployed returned with a code of 0 (This means that Result40Collection, BackupErrorCollection, and BadErrorCollection should be empty. I will explain in a moment why this is especially significant)
What I expect to happen:
- exitCode = 0
- Build = succeeded
- results:
Results for server name
Deployment successful!
***********************
What I expect to happen based on the results in the TFS build log: In this section, I'm ignoring the fact that there are multiple entries being returned and only focusing on the one that says there were errors
- exitCode = 2
- Build = Failed
- results:
Results for server name
Deployment errors, please review the log
***********************
Code:
Imports System
Imports Microsoft.TeamFoundation.Build.Client
Imports System.Activities
Imports RMUtilities
<BuildActivity(HostEnvironmentOption.All)>
Public NotInheritable Class DeployU2Files
Inherits CodeActivity
#Region "Arguments"
' In Arguments
Property inServerDataSet As InArgument(Of DataSet) ' Dataset containing the server information
Property inSourcesDirectory As InArgument(Of String) ' Full path to the Source directory being deployed
Property inBuildName As InArgument(Of String) ' Name of the build, to be used for backups
Property inLogDirectory As InArgument(Of String) ' Path to the log folder
' Out Arguments
Property outExitCode As OutArgument(Of Integer) ' Resulting error code, 0 is good
Property outResult As OutArgument(Of String) ' Result string
#End Region ' "Arguments"
#Region "Variables"
' Variables passed in from the build
Dim dsServerDataSet As DataSet
Dim strSourcesDirectory As String
Dim strBuildName As String
Dim strLogDirectory As String
' Variables used by the build
Dim serverInfo As XMLReader
Dim fileList As U2FileListParser
' Result variables
Dim exitCode As Integer = 0
Dim results As String = ""
#End Region '"Variables"
Protected Overrides Sub Execute(context As System.Activities.CodeActivityContext)
' Sets the working variables
dsServerDataSet = context.GetValue(Me.inServerDataSet)
strSourcesDirectory = context.GetValue(Me.inSourcesDirectory)
strBuildName = context.GetValue(Me.inBuildName)
strLogDirectory = context.GetValue(Me.inLogDirectory)
' Creates the base objects needed for the deployment
Try
serverInfo = New XMLReader(dsServerDataSet)
fileList = New U2FileListParser(strSourcesDirectory)
Catch ex As NullReferenceException
Throw New NullReferenceException("Invalid XML Dataset", ex)
Exit Sub
Catch ex As Exception
Throw New Exception("Error processing file list: " & ex.Message, ex)
End Try
' First, determine if there are files to deploy
Dim fileCount As Integer
Try
With fileList
fileCount = .DeployList.Count + .PreDeployList.Count + .PostDeployList.Count
End With
Catch ex As Exception
Throw New ArgumentException("No files to deploy")
End Try
If fileCount = 0 Then Throw New ArgumentException("No files to deploy")
' Then, check to make sure there are servers to deploy to
If serverInfo.ServerCount = 0 Then
Throw New ArgumentException("No servers listed in XML file to deploy to")
End If
' Iterates through each server in the XML file
For counter = 0 To serverInfo.ServerCount - 1
' Sets the current environment
serverInfo.ChosenEnvironment = counter
' Checks to make sure the server is active. If it isn't, it's skipped
If serverInfo.ServerActive Then
' Creates new logging object to log all output to a file with the name of the server being deployed to
Dim logger = New RMLogging(strLogDirectory & "\" & serverInfo.ServerHostName & ".log")
logger.Header = "Automated deploy" & vbCrLf & _
"Build Number: " & strBuildName & vbCrLf & _
"Date: " & DateTime.Now.ToString("MMM ddd d yyyy hh:mm:ss tt")
' Creates the deployment object
Dim objDeploy As New U2Deploy(serverInfo, fileList, logger, strBuildName)
' Deploys the files to the environment, then checks the results to make sure they
objDeploy.DeployFiles()
' This will determine the success level of the deployment, and also parses the message for the log
ProcessResults(objDeploy, serverInfo.ServerHostName)
' If there was a problem writing the log, then add the full text of the log to the results
If objDeploy.FullLog.Length > 0 Then
results &= objDeploy.FullLog & vbCrLf
results &= "**********************************" & vbCrLf
End If ' objDeploy.FullLog.Length > 0
' Disposes the objects
logger = Nothing
objDeploy.Clear()
objDeploy = Nothing
End If ' serverInfo.ServerActive
Next ' counter = 0 To serverInfo.ServerCount - 1
SetResults(exitCode, results, context)
End Sub
''' <summary>
''' Will change the exite code based on the results of the deployment
''' </summary>
''' <param name="objDeploy">U2Deploy object that contains the collections</param>
''' <remarks></remarks>
Private Sub ProcessResults(objDeploy As U2Deploy, serverName As String)
Dim currentErrorCode As Integer = 0
results &= "Results for " & serverName & vbCrLf
If objDeploy.Result40Collection.Count() > 0 Then
currentErrorCode = 1
results &= "Type 40 errors, please review the log" & vbCrLf
End If ' objDeploy.Result40Collection.Count() > 0
If objDeploy.BackupErrorCollection.Count > 0 Then
currentErrorCode = 1
results &= "File backup errors, please review the log" & vbCrLf
End If ' objDeploy.BackupErrorCollection.Count > 0
If objDeploy.BadErrorCollection.Count > 0 Then
currentErrorCode = 2
results &= "Deployment errors, please review the log" & vbCrLf
End If
If currentErrorCode = 0 Then results &= "Deployment successful!" & vbCrLf
results &= "***********************" & vbCrLf
If currentErrorCode > exitCode Then exitCode = currentErrorCode
End Sub
' Sets the outgoing message and exit code. This is used by the workflow to add messages to the buld itself
Private Sub SetResults(ByVal exitCode As Int32, message As String, ByRef context As CodeActivityContext)
context.SetValue(Me.outExitCode, exitCode)
context.SetValue(Me.outResult, message)
End Sub
End Class
UPDATE: I've been able to run this in QA twice with verbose logging turned on, and here are the results (Again, totally inconsistent). I am using VS2013 only to view and run the builds, any code changes to the classes used by the build are done within VS2010.
Run 1:
Run 2:
回答1:
I actually just had a resolution to this last night. The problem was actually with the documentation I had read on the WWF process. This code was actually executing properly, and returned the proper values, but because of the incorrect instructions, it was taking the wrong path in the workflow, which made it appear that this code was wrong.
It took me a while for this error to occur again with the diagnostic logging turned on, and once I saw it, I knew immediately what the problem was.
The root cause was that I was under the impression that WriteBuildError would mark the build as Failed, instead it marked it as Partially Succeeded, which put me on the wrong troubleshooting path.
来源:https://stackoverflow.com/questions/24703871/vb-net-method-appears-to-be-called-multiple-times-when-it-actually-isnt-and-re