Já faz um tempo que não publico nada, mas esta semana um outro colega esteve trabalhando num caso muito interessante. Ele estava fazendo o diagnóstico de uma aplicação Web que havia sido migrada para o Windows 2008 R2.
Esta aplicação usa componentes COM+ e em algum momento, o componente simplesmente travava (cenário típico de Hang).
Os componentes são antigos, e não se tem o código-fonte dos mesmos. Após muita investigação, descobriu-se que o componente iniciava um outro processo no Windows para realizar uma tarefa específica. Quando o COM+, por algum motivo realizava o RECYCLE do processo DLLHOST.exe onde o componente estava sendo executado, este outro processo permanecia em execução.
Na próxima chamada ao componente, o mesmo tentava executar o outro processo, mas já havia uma instância em execução e por isso o componente travava. A melhor solução seria reescrever todo o componente de forma que o mesmo utilize técnicas mais modernas para executar as tarefas a que se propõe, mas infelizmente isso é impossível.
Neste caso, uma solução de contorno foi necessária. Para eliminar o travamento, bastou desabilitar o RECYCLING da aplicação COM+ no snap-in dos serviços de componente (Component Services).
Todavia, um novo problema surge com essa abordagem, que é o fato que agora o processo DLLHOST.exe do COM+ poderá travar em função de algum outro mau comportamento ou até mesmo devido ao processo natural de fragmentação de memória (outro dia faço um post sobre isso).
Para minimizar esse problema seria ideal ter uma ferramenta que monitore o comportamento da aplicação COM+ (“AppBugada”, no exemplo da imagem acima) e em caso de consumo de um certo limite de memória virtual, que ela seja automaticamente encerrada.
Para isso, um script foi usado a fim de monitorar a aplicação COM+. Veja abaixo um exemplo similar que também pode ser usado para fazer este tipo de objetivo:
NOTA: Este script é um código-exemplo, use por sua conta e risco. Não oferecemos suporte a este script e não nos responsabilizamos por eventuais consequências adversas devido ao seu uso num ambiente de produção.
strComputer = "."
strCOMAppName = "AppBugada"
constMemLimit = 999999999 'Bytes
constRunning = false
constCOMAppFound = false
Set objCOMCatalog = CreateObject("COMAdmin.COMAdminCatalog")
Set objCOMApps = objCOMCatalog.GetCollection("Applications")
objCOMApps.PopulateFor each objCOMApp in objCOMApps
If objCOMApp.Name = strCOMAppName then
Set objCOMAppInstances = objCOMApps.GetCollection("ApplicationInstances",objCOMApp.Key)
objCOMAppInstances.Populate
For each objCOMInstance in objCOMAppInstances
PID = objCOMInstance.Value("ProcessID")
constRunning = not ( objCOMInstance.Value("IsPaused") or objCOMInstance.Value("HasRecycled"))
If constRunning then
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" _
& strComputer & "\root\cimv2")
Set objProcesses = objWMIService.ExecQuery _
("Select * from Win32_Process where ProcessId='" & PID & "'")
For Each objProcess in objProcesses
Wscript.Echo "Process: " & objProcess.Name
sngProcessTime = (CSng(objProcess.KernelModeTime) + _
CSng(objProcess.UserModeTime)) / 10000000
Wscript.Echo "Processor Time: " & sngProcessTime
Wscript.Echo "Process ID: " & objProcess.ProcessID
Wscript.Echo "Peak Virtual Size: " _
& objProcess.PeakVirtualSize
Wscript.Echo "Virtual Size: " _
& objProcess.VirtualSize
If objProcess.VirtualSize > constMemLimit then
objProcess.Terminate()
End if
Next
Set objWMIService = nothing
Set objProcesses = nothing
Exit For
Else
Wscript.Echo "COM+ Application not running."
End if
Next
Set objCOMAppInstances = nothing
constCOMAppFound = true
Exit For
End if
NextIf constCOMAppFound = false then
Wscript.Echo "COM+ Application not found."
End ifSet objCOMApps = nothing
Set objCOMCatalog = nothing
O Script usa a interface COMAdmin para monitorar as aplicações COM+ e classes WMI para coletar informações do processo DLLHOST.exe correspondente. Caso o processo atinja um certo limite de uso de memória virtual, o mesmo será terminado.
Valeu pessoal e até a próxima.
PT