As part of our configuration management process with our offshore team, we often have to recreate our database schema in Oracle by dropping the schema owner and recreating that user as part of the create/import scripts delivered with a build. However, when trying to perform this task in our onshore Development, QA or UAT environments we are faced with an issue where the user could not be dropped due to the fact that said user was currently connected:
DROP USER <user_to_drop> CASCADE
*
ERROR at line 1:
ORA-01940: cannot drop a user that is currently connected
However, when checking the V$SESSION system table, the user was not listed as being connected or having an active session with the database. Perplexed, we looked around at some other clues, and determined that while the user did not have an active session with the database, its connection was still valid and pooled by the ASP.NET Web process. Thus, we recycled the AppPool in which the application was hosted and – viola! The drop succeeded.
We've now automated this process and recycle the AppPool programmatically. Below is the Web service used to list the available AppPools and individually recycle them.
using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.DirectoryServices;
using System.Collections.Generic;
[WebService(Namespace = "http://tempuri.org")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class AppServerService : System.Web.Services.WebService
{
public AppServerService ()
{
}
private const string AppPoolDirectoryEntryPath = "IIS://localhost/W3SVC/AppPools";
[WebMethod]
public List<string> GetAppPoolNames()
{
List<string> appPoolList = new List<string>();
using (DirectoryEntry appPoolEntry =
new DirectoryEntry(AppPoolDirectoryEntryPath))
{
foreach (DirectoryEntry appPool in appPoolEntry.Children)
{
appPoolList.Add(appPool.Name);
appPool.Close();
appPool.Dispose();
}
}
return appPoolList;
}
[WebMethod]
public AppPoolRestartResponse RecycleAppPool(string appPoolName)
{
if (appPoolName == null)
{
throw new ArgumentNullException("appPoolName");
}
AppPoolRestartResponse response = new AppPoolRestartResponse();
using (DirectoryEntry appPool = new DirectoryEntry(
String.Format("{0}/{1}", AppPoolDirectoryEntryPath, appPoolName)))
{
try
{
appPool.Invoke("Recycle");
response.Successful = true;
response.Message = String.Format(
"Application Pool \"{0}\" was recycled succesfully at {1:HH:mm:ss}.",
appPool.Name, DateTime.Now);
}
catch (Exception e)
{
response.Successful = true;
response.Message = String.Format(
"Application Pool \"{0}\" failed to recycle: \"{1}\".",
appPool.Name, e.Message);
}
}
return response;
}
/// <summary>
///
/// </summary>
public class AppPoolRestartResponse
{
private bool _successful;
private string _message;
public bool Successful
{
get { return _successful; }
set { _successful = value; }
}
public string Message
{
get { return _message; }
set { _message = value; }
}
}
}
Note that in order for this Web service to work correctly, you must be authenticated to the Web service as an local administrator of the machine, or enable impersonation in Web.config for a user with the appropriate privelleges.
In early 2006, we had a difficult bridge to cross as we were about to enter the Construction phase of our current project. Having 35+ developers building interdependent functional areas of the application, we needed to ensure the autonomy of each functional area, whilst maintaining linkage between shared components. Thus, having used branches in the past (quite successfully with Subversion, might I add,) we decided to leverage TFS branches to provide support for our concurrent development efforts.
While quite sound in theory, this has proven to be quite challenging in practice. We've faced several issues, most troubling of which is error TF14087:
TF14087: Cannot undelete '$/Itd/Implementation/R2/Bvi/Framework/Security/Authorization/Principal.cs' because not all of the deletion is being undeleted.
After some research into this error, I came across this excellent explanation of what's going on. Furthermore, we found that the reason for this error occurring in our structure is due to file renaming in the trunk and branches. Thus, as the aforementioned blog post outlines, TFS cannot perform the merge as the linkage between the file is not correctly synchronized (TFS is looking to merge a "deleted" file, although it's really been renamed.)
Furthermore, we also faced issues in that some developers "merged" their branch by copying files locally in their workspace and added them to Source Control as new items. This completely breaks the linkage between the trunk and branches, which was a big headache when trying to perform the merge.
In the end, we spent more than 4 hours manually merging our two active branches – what a pain! Even though there are some workarounds posted out there (here is a fair approach,) we ended up performing the merge manually due to the fact that some defects had been fixed in one branch while other defects in the next branch. Thus, the only way to effectively manage said changes was to manually merge.
Although I'm now a little jaded with TFS Branching, I would recommend the following guidelines if you choose to use this functionality to manage concurrent development activities:
- Merge often – this is a big one, since many of our issues would have been resolved if this rule was followed by our team.
- Rename in trunk, then move to branches – we found that whenever a rename was required, performing this activity in the trunk allowed us to propagate changes to the desired branch without merge errors
- Document merge guidelines – in our situation, we have 35+ developers offshore with some architecture and development oversight resources onshore. Although some resources had used branches before, many were unfamiliar with the process, resulting in the merge-via-copy-and-paste snafu. Thus, clearly documenting the process could have saved us the headaches we've had.
- Keep shared components in single branch – we found that fewer conflicts existed in shared components. Thus, keeping these items in a single branch reduces the margin for error in merging.
In addition to these tips, it is always a good idea to effectively communicate major changes to the code base between the development teams. We're currently implementing a weekly meeting between team leads to discuss the same, and it's looking bright.
Recommended reading:
The logic and reason behind error message TF14087 (mentioned earlier)
Cheers.
It seems like the only time I have to myself is in airport lounges! As the post would suggest, I'm in the UK en route to Mumbai to visit my team, check up on things, enjoy some good Chicken Tikka... the usual drill.
Will be posting some TFS musings soon... hopefully, will have some goodies on SP1 and hardware migration.
Cheers!