En el caso de scripts de monitorización, que se ejecutan a intervalos regulares, es necesario controlar estos procesos secundarios para así evitar que multiples procesos secundarios no terminen y queden abiertos en el sistema. Este control podemos hacerlo desde el propio script.
El código siguiente es un ejemplo de como realizarlo para el caso de un script que testea una conexión a una base de datos. El comando que se ejecuta es "sqlplus.exe" y queda parado sin terminar porque la linea "exit" del fichero que ejecuta esta comentada. De esta forma simulamos un problema que tendrá que resolver el script:
'-----------------------------------------------------------------------
' Constantes
'-----------------------------------------------------------------------
Const ORA_SID="XE"
Const ORA_PORT="1521"
Const operuser="sys"
Const operpwd="manager"
'-----------------------------------------------------------------------
On Error Resume Next
IdProceso= ScriptProcessID()
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set WshShell = CreateObject("WScript.Shell")
scriptPath=WshShell.CurrentDirectory
PathFileConexSQL=scriptPath & "\conexion.sql"
PathFileConexLog=scriptPath & "\conexion.log"
If objFSO.FileExists(PathFileConexLog) Then objFSO.DeleteFile(PathFileConexLog)
If objFSO.FileExists(PathFileConexSQL) Then objFSO.DeleteFile(PathFileConexSQL)
Set objPathFileConexSQL = objFSO.CreateTextFile(PathFileConexSQL)
objPathFileConexSQL.WriteLine("spool " & PathFileConexLog & ";")
objPathFileConexSQL.WriteLine("column host_name format A20;")
objPathFileConexSQL.WriteLine("select host_name, instance_name, status from v$instance;")
objPathFileConexSQL.WriteLine("spool off;")
'objPathFileConexSQL.WriteLine("exit;")
objPathFileConexSQL.Close
comando="sqlplus -L """ & operuser & "/" & operpwd & "@" & ORA_SID & " as sysdba"" @" & PathFileConexSQL
WshShell.Run(comando),2,false
wscript.sleep 10000
Set colProcessList=Nothing
Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")
Set colProcessList = objWMIService.ExecQuery("SELECT * FROM Win32_Process WHERE Name = 'sqlplus.exe' And ParentProcessId = " & IdProceso)
If colProcessList.count>0 Then
For Each objProcess in colProcessList
MsgBox("Terminando proceso bloqueado ...")
objProcess.Terminate()
Next
End If
'If objFSO.FileExists(PathFileConexLog) Then objFSO.DeleteFile(PathFileConexLog)
'If objFSO.FileExists(PathFileConexSQL) Then objFSO.DeleteFile(PathFileConexSQL)
WScript.Quit
'-----------------------------------------------------------------------
' Función obtener el processID de este script
'-----------------------------------------------------------------------
Function ScriptProcessID()
Set objSWbemServices = GetObject ("WinMgmts:Root\Cimv2")
Set colProcess = objSWbemServices.ExecQuery("Select * From Win32_Process Where Name='wscript.exe' Or Name='cscript.exe'")
For Each objProcess In colProcess
if instr(objProcess.CommandLine,WScript.ScriptFullName)<>0 Then
ScriptProcessID=objProcess.ProcessID
End If
Next
End Function
'-----------------------------------------------------------------------
Lo primero es identificar el ID del proceso de sistema del propio script; esto se hace en la linea:
IdProceso= ScriptProcessID()
La función ScriptProcessID utiliza el ScriptFullName y una consulta WMI para encontrar dicho ID.
Generamos el fichero PathFileConexSQL con la consulta SQL que lanzaremos a la base de datos una vez conectados; dejamos la sentencia "exit" comentada para simular un proceso que no termina:
spool C:\Oracle\conexion.log;
column host_name format A20;
select host_name, instance_name, status from v$instance;
spool off;
Después generamos el comando que vamos a ejecutar, un sqlplus con su cadena de conexión generada a partir de las variables definidas al inicio del script y que una vez conectado a la base de datos ejecutara el fichero anterior:
comando="sqlplus -L """ & operuser & "/" & operpwd & "@" & ORA_SID & " as sysdba"" @" & PathFileConexSQL
Lanzamos el comando y damos un tiempo de espera (10 segundos):
WshShell.Run(comando),2,false
wscript.sleep 10000
wscript.sleep 10000
Es el momento de confirmar que nuestro comando ha terminado. Lo hacemos mediante una consulta WMI que utiliza el nombre del comando ejecutado, sqlplus.exe, y el ID del proceso padre que lo lanzo, que es el ID de nuestro script obtenido al principio:
Set colProcessList=Nothing
Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")
Set colProcessList = objWMIService.ExecQuery("SELECT * FROM Win32_Process WHERE Name = 'sqlplus.exe' And ParentProcessId = " & IdProceso)
En caso de que la consulta obtenga algún resultado tenemos que matar dicho proceso, en este ejemplo hemos añadido un mensaje que en un entorno real no tendría sentido incluir:
If colProcessList.count>0 Then
For Each objProcess in colProcessList
MsgBox("Terminando proceso bloqueado ...")
objProcess.Terminate()
Next
End If
Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")
Set colProcessList = objWMIService.ExecQuery("SELECT * FROM Win32_Process WHERE Name = 'sqlplus.exe' And ParentProcessId = " & IdProceso)
En caso de que la consulta obtenga algún resultado tenemos que matar dicho proceso, en este ejemplo hemos añadido un mensaje que en un entorno real no tendría sentido incluir:
If colProcessList.count>0 Then
For Each objProcess in colProcessList
MsgBox("Terminando proceso bloqueado ...")
objProcess.Terminate()
Next
End If
La ejecución del script da este resultado:
Si quitamos el comentario a la linea que hacia el "exit" en la conexión a la base de datos el script funciona perfectamente sin ningún problema:
objPathFileConexSQL.WriteLine("exit;")
Un saludo
Un saludo
No hay comentarios:
Publicar un comentario