mirror of
https://github.com/KeymonSoft/jRDC-Multi.git
synced 2026-04-17 21:06:24 +00:00
- VERSION 5.09.18
- feat(manager): Implementa recarga granular (Hot-Swap). - Actualiza manager.html para solicitar la DB Key a recargar (ej: DB2). - Se modifica Manager.bas para leer este parámetro y ejecutar el Hot-Swap de forma atómica solo en el pool de conexión especificado, lo cual mejora la eficiencia y la disponibilidad del servicio.
This commit is contained in:
@@ -105,17 +105,34 @@ Sub Handle(req As ServletRequest, resp As ServletResponse)
|
||||
|
||||
con = Connector.GetConnection(dbKey) ' ¡La conexión a la BD se obtiene aquí del pool de conexiones!
|
||||
|
||||
' <<<< ¡BUSY_CONNECTIONS YA SE CAPTURABA BIEN! >>>>
|
||||
' Este bloque captura el número de conexiones actualmente ocupadas en el pool
|
||||
' *después* de que esta petición ha obtenido la suya.
|
||||
If Connector.IsInitialized Then
|
||||
Dim poolStats As Map = Connector.GetPoolStats
|
||||
If poolStats.ContainsKey("BusyConnections") Then
|
||||
' <<<< ¡CORRECCIÓN CLAVE: Aseguramos que el valor sea Int! >>>>
|
||||
poolBusyConnectionsForLog = poolStats.Get("BusyConnections").As(Int) ' Capturamos el valor.
|
||||
Log($">>>>>>>>>> ${poolStats.Get("BusyConnections")} "$)
|
||||
End If
|
||||
End If
|
||||
' <<<< ¡FIN DE CAPTURA! >>>>
|
||||
|
||||
Dim cachedStatsB4X As Map = Main.LatestPoolStats.Get(dbKey).As(Map)
|
||||
|
||||
If cachedStatsB4X.IsInitialized Then
|
||||
' 1. Actualizar Busy Connections y Active Requests
|
||||
cachedStatsB4X.Put("BusyConnections", poolBusyConnectionsForLog)
|
||||
cachedStatsB4X.Put("HandlerActiveRequests", requestsBeforeDecrement)
|
||||
|
||||
' 2. Capturar TotalConnections y IdleConnections (ya disponibles en poolStats)
|
||||
If poolStats.ContainsKey("TotalConnections") Then
|
||||
cachedStatsB4X.Put("TotalConnections", poolStats.Get("TotalConnections"))
|
||||
End If
|
||||
If poolStats.ContainsKey("IdleConnections") Then
|
||||
cachedStatsB4X.Put("IdleConnections", poolStats.Get("IdleConnections"))
|
||||
End If
|
||||
|
||||
' 3. Re-escribir el mapa en el cache global (es Thread-Safe)
|
||||
Main.LatestPoolStats.Put(dbKey, cachedStatsB4X)
|
||||
End If
|
||||
|
||||
' Log("Metodo: " & method) ' Log de depuración para identificar el método de la petición.
|
||||
|
||||
@@ -167,9 +184,16 @@ Sub Handle(req As ServletRequest, resp As ServletResponse)
|
||||
End If
|
||||
|
||||
Catch ' --- CATCH: Maneja errores generales de ejecución o de SQL ---
|
||||
Log(LastException) ' Registra la excepción completa en el log.
|
||||
Main.LogServerError("ERROR", "DBHandlerB4X.Handle", LastException.Message, dbKey, q, req.RemoteAddress) ' <-- Nuevo Log
|
||||
SendPlainTextError(resp, 500, LastException.Message) ' Envía un error 500 al cliente.
|
||||
Dim errorMessage As String = LastException.Message
|
||||
If errorMessage.Contains("ORA-01002") Or errorMessage.Contains("recuperación fuera de secuencia") Then
|
||||
errorMessage = "SE USA EXECUTEQUERY EN LUGAR DE EXECUTECOMMAND: " & errorMessage
|
||||
else If errorMessage.Contains("ORA-17003") Or errorMessage.Contains("Índice de columnas no válido") Then
|
||||
errorMessage = "NUMERO DE PARAMETROS EQUIVOCADO: " & errorMessage
|
||||
End If
|
||||
|
||||
Log(errorMessage) ' Registra la excepción completa en el log.
|
||||
Main.LogServerError("ERROR", "DBHandlerB4X.Handle", errorMessage, dbKey, q, req.RemoteAddress) ' <-- Nuevo Log
|
||||
SendPlainTextError(resp, 500, errorMessage) ' Envía un error 500 al cliente.
|
||||
q = "error_in_b4x_handler" ' Aseguramos un valor para 'q' en caso de excepción.
|
||||
End Try ' --- FIN: Bloque Try principal ---
|
||||
|
||||
@@ -344,11 +368,12 @@ Private Sub ExecuteBatch2(DB As String, con As SQL, in As InputStream, resp As S
|
||||
Dim m As Map = ser.ConvertBytesToObject(Bit.InputStreamToBytes(in))
|
||||
' Obtiene la lista de objetos DBCommand.
|
||||
Dim commands As List = m.Get("commands")
|
||||
Dim totalAffectedRows As Int = 0 ' Contador para acumular el total de filas afectadas.
|
||||
|
||||
' Prepara un objeto DBResult para la respuesta (aunque para batch no devuelve datos, solo confirmación).
|
||||
Dim res As DBResult
|
||||
res.Initialize
|
||||
res.columns = CreateMap("AffectedRows (N/A)": 0) ' Columna simbólica.
|
||||
res.columns = CreateMap("AffectedRows": 0) ' Columna simbólica.
|
||||
res.Rows.Initialize
|
||||
res.Tag = Null
|
||||
|
||||
@@ -390,10 +415,14 @@ Private Sub ExecuteBatch2(DB As String, con As SQL, in As InputStream, resp As S
|
||||
End If
|
||||
|
||||
con.ExecNonQuery2(sqlCommand, validationResult.ParamsToExecute) ' Ejecuta el comando con la lista de parámetros validada.
|
||||
|
||||
totalAffectedRows = totalAffectedRows + 1 ' Acumulamos 1 por cada comando ejecutado sin error.
|
||||
|
||||
' <<< FIN VALIDACIÓN DE PARÁMETROS CENTRALIZADA DENTRO DEL BATCH >>>
|
||||
|
||||
Next
|
||||
|
||||
res.Rows.Add(Array As Object(0)) ' Añade una fila simbólica al resultado para indicar éxito.
|
||||
res.Rows.Add(Array As Object(totalAffectedRows)) ' Añade una fila simbólica al resultado para indicar éxito.
|
||||
con.TransactionSuccessful ' Si todos los comandos se ejecutaron sin error, confirma la transacción.
|
||||
Catch
|
||||
' Si cualquier comando falla, se captura el error.
|
||||
@@ -427,7 +456,7 @@ End Sub
|
||||
|
||||
' Ejecuta un lote de comandos usando el protocolo V1.
|
||||
Private Sub ExecuteBatch(DB As String, con As SQL, in As InputStream, resp As ServletResponse) As String
|
||||
Log($"ExecuteBatch ${DB}"$)
|
||||
' Log($"ExecuteBatch ${DB}"$)
|
||||
' Lee y descarta la versión del cliente.
|
||||
Dim clientVersion As Float = ReadObject(in) 'ignore
|
||||
' Lee cuántos comandos vienen en el lote.
|
||||
@@ -441,18 +470,18 @@ Private Sub ExecuteBatch(DB As String, con As SQL, in As InputStream, resp As Se
|
||||
Try
|
||||
con.BeginTransaction
|
||||
' Itera para procesar cada comando del lote.
|
||||
Log(numberOfStatements)
|
||||
' Log(numberOfStatements)
|
||||
For i = 0 To numberOfStatements - 1
|
||||
Log($"i: ${i}"$)
|
||||
' Log($"i: ${i}"$)
|
||||
' Lee el nombre del comando y la lista de parámetros usando el deserializador V1.
|
||||
Dim queryName As String = ReadObject(in)
|
||||
Dim params As List = ReadList(in)
|
||||
Log(params)
|
||||
' Log(params)
|
||||
If numberOfStatements = 1 Then
|
||||
singleQueryName = queryName 'Capturamos el nombre del query.
|
||||
End If
|
||||
Dim sqlCommand As String = Connector.GetCommand(DB, queryName)
|
||||
Log(sqlCommand)
|
||||
' Log(sqlCommand)
|
||||
' <<< INICIO NUEVA VALIDACIÓN: VERIFICAR SI EL COMANDO EXISTE (V1) >>>
|
||||
If sqlCommand = Null Or sqlCommand = "null" Or sqlCommand.Trim = "" Then
|
||||
con.Rollback ' Deshace la transacción si un comando es inválido.
|
||||
@@ -473,7 +502,7 @@ Private Sub ExecuteBatch(DB As String, con As SQL, in As InputStream, resp As Se
|
||||
Return "error" ' Salida temprana si la validación falla.
|
||||
End If
|
||||
|
||||
Log(validationResult.ParamsToExecute)
|
||||
' Log(validationResult.ParamsToExecute)
|
||||
|
||||
Dim affectedCount As Int = 1 ' Asumimos éxito (1) ya que la llamada directa es la única que ejecuta el SQL sin fallar en runtime.
|
||||
|
||||
@@ -486,14 +515,14 @@ Private Sub ExecuteBatch(DB As String, con As SQL, in As InputStream, resp As Se
|
||||
|
||||
con.TransactionSuccessful ' Confirma la transacción.
|
||||
|
||||
Log("Transaction succesfull")
|
||||
' Log("Transaction succesfull")
|
||||
|
||||
Dim out As OutputStream = cs.WrapOutputStream(resp.OutputStream, "gzip") ' Comprime la salida antes de enviarla.
|
||||
' Escribe la respuesta usando el serializador V1.
|
||||
WriteObject(Main.VERSION, out)
|
||||
WriteObject("batch", out)
|
||||
WriteInt(res.Length, out)
|
||||
Log(affectedCounts.Size)
|
||||
' Log(affectedCounts.Size)
|
||||
For Each r As Int In affectedCounts
|
||||
WriteInt(r, out)
|
||||
Next
|
||||
|
||||
Reference in New Issue
Block a user