Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   General/Noticias (https://www.clubdelphi.com/foros/forumdisplay.php?f=64)
-   -   Ver si proceso en ejecución en máquina remota (https://www.clubdelphi.com/foros/showthread.php?t=97110)

razorxxx 09-12-2024 11:13:29

Ver si proceso en ejecución en máquina remota
 
Buenas a todos!

En mi empresa tenemos múltiples sistemas de facturación ya que programamos a medida para nuestros clientes. Es por ello que la adaptación a Veri*Factu la haremos haciendo uso de un subprograma que mostrará el registro de facturación asociado a una factura, gestionará los envíos y respuestas, las firmas, los registros de eventos, etc.

Como la mayoría de nuestras instalaciones son de tipo cliente-servidor, el subprograma en cuestión se ejecutará en el servidor y estará siempre disponible, y se mantendrá a la escucha para enviar los registros cada 60 segundos.

Lo que pasa es que este subprograma, por razones diversas, podría ocurrir que de repente se cuelgue y deje de estar disponible para el envío de las facturas. Por tanto, cada uno de nuestros SIF debería detectar antes o después de generar el registro de una factura si dicho subprograma está en ejecución en la máquina remota para, en caso contrario, ejecutarlo o que nos avise por mail de que no está ejecutándose, pues de lo contrario no se podrían remitir los registros de facturación a la AEAT.

¿Alguno de ustedes sabe cómo puede consultarse desde un equipo si en otro equipo de la red existe un proceso en ejecución? Tras algunas consultas a Google y otras a Copilot, he estado probando la api de WMI pero hasta ahora no consigo que funcione. Mi código es el siguiente:

Código:

var
  SWbemLocator: OLEVariant;
  SWbemServices: OLEVariant;
  SWbemObjectSet: OLEVariant;
  SWbemObject: OLEVariant;
  Enum: IEnumVariant;
  Value: Cardinal;
begin
    Result := False;
    SWERROR := 0;
    try
        CoInitialize(nil);
            try
                SWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
                If CBCredenciales.Checked Then  // Si la máquina remota tiene autenticación
                    SWbemServices := SWbemLocator.ConnectServer(RemoteMachine, 'root\CIMV2', Usuario.Text, Password.Text)
                Else
                    SWbemServices := SWbemLocator.ConnectServer(RemoteMachine, 'root\CIMV2', '', '');
                SWbemObjectSet := SWbemServices.ExecQuery(Format('SELECT * FROM Win32_Process WHERE Name = "%s"', [ProcessName]));
                Enum := IUnknown(SWbemObjectSet._NewEnum) as IEnumVariant;
                while Enum.Next(1, SWbemObject, Value) = S_OK do
                begin
                    Result := True;
                    SWbemObject := Unassigned;
                end;
            finally
                    CoUninitialize;
            end;
    except
          on E: EOleException do
          begin
                SWERROR := 1;
                Memo1.Lines.Add(Format('Error %d : ($%x) Mensaje : %s', [E.ErrorCode, E.ErrorCode, E.Message]));
          end;
          on E: Exception do
          begin
                SWERROR := 1;
                Memo1.Lines.Add('Error ' + E.Classname + ': ' + E.Message);
          end;
    end;
end;

Casi seguro está relacionado con temas de firewall y puertos en la máquina remota, porque si activo o desactivo el Firewall recibo errores diferentes.

ermendalenda 09-12-2024 12:16:15

Cita:

Empezado por razorxxx (Mensaje 560588)
Buenas a todos!

En mi empresa tenemos múltiples sistemas de facturación ya que programamos a medida para nuestros clientes. Es por ello que la adaptación a Veri*Factu la haremos haciendo uso de un subprograma que mostrará el registro de facturación asociado a una factura, gestionará los envíos y respuestas, las firmas, los registros de eventos, etc.

Como la mayoría de nuestras instalaciones son de tipo cliente-servidor, el subprograma en cuestión se ejecutará en el servidor y estará siempre disponible, y se mantendrá a la escucha para enviar los registros cada 60 segundos.

Lo que pasa es que este subprograma, por razones diversas, podría ocurrir que de repente se cuelgue y deje de estar disponible para el envío de las facturas. Por tanto, cada uno de nuestros SIF debería detectar antes o después de generar el registro de una factura si dicho subprograma está en ejecución en la máquina remota para, en caso contrario, ejecutarlo o que nos avise por mail de que no está ejecutándose, pues de lo contrario no se podrían remitir los registros de facturación a la AEAT.

¿Alguno de ustedes sabe cómo puede consultarse desde un equipo si en otro equipo de la red existe un proceso en ejecución? Tras algunas consultas a Google y otras a Copilot, he estado probando la api de WMI pero hasta ahora no consigo que funcione. Mi código es el siguiente:

Código:

var
  SWbemLocator: OLEVariant;
  SWbemServices: OLEVariant;
  SWbemObjectSet: OLEVariant;
  SWbemObject: OLEVariant;
  Enum: IEnumVariant;
  Value: Cardinal;
begin
    Result := False;
    SWERROR := 0;
    try
        CoInitialize(nil);
            try
                SWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
                If CBCredenciales.Checked Then  // Si la máquina remota tiene autenticación
                    SWbemServices := SWbemLocator.ConnectServer(RemoteMachine, 'root\CIMV2', Usuario.Text, Password.Text)
                Else
                    SWbemServices := SWbemLocator.ConnectServer(RemoteMachine, 'root\CIMV2', '', '');
                SWbemObjectSet := SWbemServices.ExecQuery(Format('SELECT * FROM Win32_Process WHERE Name = "%s"', [ProcessName]));
                Enum := IUnknown(SWbemObjectSet._NewEnum) as IEnumVariant;
                while Enum.Next(1, SWbemObject, Value) = S_OK do
                begin
                    Result := True;
                    SWbemObject := Unassigned;
                end;
            finally
                    CoUninitialize;
            end;
    except
          on E: EOleException do
          begin
                SWERROR := 1;
                Memo1.Lines.Add(Format('Error %d : ($%x) Mensaje : %s', [E.ErrorCode, E.ErrorCode, E.Message]));
          end;
          on E: Exception do
          begin
                SWERROR := 1;
                Memo1.Lines.Add('Error ' + E.Classname + ': ' + E.Message);
          end;
    end;
end;

Casi seguro está relacionado con temas de firewall y puertos en la máquina remota, porque si activo o desactivo el Firewall recibo errores diferentes.

Puedes crear un archivo bloqueado(locked mode) y lo dejas abierto en el programa del srvidor, cuando esté cerrado dicho programa, el archivo se desbloqueará y los programas de cliente que intenten escribir algo en ese archivo y si deja (no devolviendo error de bloqueo) es que está cerrado.

Neftali [Germán.Estévez] 09-12-2024 12:16:57

Cita:

Empezado por razorxxx (Mensaje 560588)
Lo que pasa es que este subprograma, por razones diversas, podría ocurrir que de repente se cuelgue y deje de estar disponible para el envío de las facturas. Por tanto, cada uno de nuestros SIF debería detectar antes o después de generar el registro de una factura si dicho subprograma está en ejecución en la máquina remota para, en caso contrario, ejecutarlo o que nos avise por mail de que no está ejecutándose, pues de lo contrario no se podrían remitir los registros de facturación a la AEAT.

¿Porqué no usáis un servicio?
Yo creo que sería lo adecuado para este escenario.
Para consultar si un servicio está en marcha, se podría utilizar WMI.

nincillo 11-12-2024 09:45:13

Cita:

Empezado por Neftali [Germán.Estévez] (Mensaje 560592)
¿Porqué no usáis un servicio?
Yo creo que sería lo adecuado para este escenario.
Para consultar si un servicio está en marcha, se podría utilizar WMI.

Yo había pensado en abrir un puerto y por sockets hacer llamadas cada vez que se genera una factura para que el programa "externo" proceda al envío y sino hay respuesta a la petición avisar del problema.

Pero si ese programa remoto fuera ejecutado como un servicio, creo que mucho mejor.

¿Podrías orientarnos un poco el como hacer un programa que funcione como un servicio?

Neftali [Germán.Estévez] 11-12-2024 10:36:27

Cita:

Empezado por nincillo (Mensaje 560640)
Yo había pensado en abrir un puerto y por sockets hacer llamadas cada vez que se genera una factura para que el programa "externo" proceda al envío y sino hay respuesta a la petición avisar del problema.


Si es posible, lo más sencillo (creo yo) es que tantos los programas cliente (ERP) como el servicio (o la app. que habías pensado) estén conectados a la Base de Datos.
Los ERP van colocando ficheros en la cola (es una o varias tablas dependiendo del diseño) y el servicio los va procesando y en la misma Base de Datos va generando las respuestas.
La lógica de envío sólo está en el servicio.



Cita:

Empezado por nincillo (Mensaje 560640)
¿Podrías orientarnos un poco el como hacer un programa que funcione como un servicio?


Nosotros diseñamos el servicio en 2 piezas (EXE + DLL). En realidad para facilitar debug y pruebas, se diseña un servicio y una aplicación.
Para no "repetir" código, toda la lógica se encuentra en la DLL y esa DLL se llama desde una APP y desde un SERVICIO.
Como he dicho la APP y el SERVICIO sólo tienen una llamada al método de "procesar" de la DLL (que tiene toda la lógica).


¿Porqué se hace esto? Porque los servicios no pueden tener parte visual y los LOGs para debug se envían al registro de eventos de Windows, en el caso de la APP sí puede tener parte visual y los LOGs para debug se envían a un fichero. Para todo el proceso de desarrollo se usa la APP+DLL y para el cliente final SERVICIO+DLL.



Si buscas por los foros encontrarás muchos hilos al respecto y posiblemente en el FTP encontrarás algún ejemplo:
https://www.clubdelphi.com/foros/showthread.php?t=89341
https://www.clubdelphi.com/foros/showthread.php?t=48843
https://www.clubdelphi.com/foros/showthread.php?t=12776
https://www.clubdelphi.com/foros/showthread.php?t=20913
https://www.intitec.com/varios/delph...io_windows.pdf

RUBEN_SP 11-12-2024 18:51:02

Cita:

Empezado por Neftali [Germán.Estévez] (Mensaje 560646)
Si es posible, lo más sencillo (creo yo) es que tantos los programas cliente (ERP) como el servicio (o la app. que habías pensado) estén conectados a la Base de Datos.
Los ERP van colocando ficheros en la cola (es una o varias tablas dependiendo del diseño) y el servicio los va procesando y en la misma Base de Datos va generando las respuestas.
La lógica de envío sólo está en el servicio.

Y que paso si en el mismo servidor hay varias instancias de la Base de Datos porque hay varias instalaciones ¿Cómo sabe el servicio a cual tiene que atender?

ermendalenda 11-12-2024 21:24:12

Cita:

Empezado por RUBEN_SP (Mensaje 560674)
Y que paso si en el mismo servidor hay varias instancias de la Base de Datos porque hay varias instalaciones ¿Cómo sabe el servicio a cual tiene que atender?

Lo más rápido es un registro de índice único autonumerico y controlar poner en bucle los reintentos por si coinciden 2 escrituras. Cuando te deje escribir obtienes el número que será único.
Los servicios se atienden a quien los pide, no se entremezclan y además puedes mandarles parámetros para identificar desde donde lo envías para que se registre.

RUBEN_SP 12-12-2024 09:31:03

Cita:

Empezado por ermendalenda (Mensaje 560676)
Lo más rápido es un registro de índice único autonumerico y controlar poner en bucle los reintentos por si coinciden 2 escrituras. Cuando te deje escribir obtienes el número que será único.
Los servicios se atienden a quien los pide, no se entremezclan y además puedes mandarles parámetros para identificar desde donde lo envías para que se registre.

No entiendo donde pones ese registro de índice único, ni tampoco se como se pasan parámetros a un servicio que está en ejecución

Neftali [Germán.Estévez] 12-12-2024 11:39:40

Cita:

Empezado por RUBEN_SP (Mensaje 560674)
Y que paso si en el mismo servidor hay varias instancias de la Base de Datos porque hay varias instalaciones ¿Cómo sabe el servicio a cual tiene que atender?


Es cuestión de buscar soluciones a los problemas.
En nuestro caso hay un único Servidor de Base de Datos, pero puede haber varias Bases de Datos dentro de ese servidor.
Cada base de datos es una empresa/obligado diferente (no se si es también tu caso); El servicio hace y una rueda y se va conectando a las diferentes Bases de Datos para enviar los datos de esa empresa. Una vez acabado se apunta en tiempo de espera (o el tiempo hasta el siguiente envío) para esa empresa.

Es decir, en nuestro caso, un único servicio se encarga de todos los envíos de las diferentes empresas/obligados tributarios. Por ahora en el Thread principal, porque no contemplamos que la "rueda de envío" pueda tardar más de 60 sg. Actualmente se hace muy rápido. Si en su día esa "rueda de envíos" empezara a tardar mucho, nos planteamos crear Threads (ya lo tenemos pensado).

rci 12-12-2024 13:05:22

Cita:

Empezado por Neftali [Germán.Estévez] (Mensaje 560685)
Es cuestión de buscar soluciones a los problemas.
En nuestro caso hay un único Servidor de Base de Datos, pero puede haber varias Bases de Datos dentro de ese servidor.
Cada base de datos es una empresa/obligado diferente (no se si es también tu caso); El servicio hace y una rueda y se va conectando a las diferentes Bases de Datos para enviar los datos de esa empresa. Una vez acabado se apunta en tiempo de espera (o el tiempo hasta el siguiente envío) para esa empresa.

Es decir, en nuestro caso, un único servicio se encarga de todos los envíos de las diferentes empresas/obligados tributarios. Por ahora en el Thread principal, porque no contemplamos que la "rueda de envío" pueda tardar más de 60 sg. Actualmente se hace muy rápido. Si en su día esa "rueda de envíos" empezara a tardar mucho, nos planteamos crear Threads (ya lo tenemos pensado).

Nosotros lo tenemos montado igual que vosotros Neftali, pero además en una misma base de datos puede haber varias empresas.
También estamos considerando hacer threads independientes para cada empresa (obligado tributario) para que se vayan enviando en paralelo las facturas de cada OT.
Pero como es un proceso que se va ejecutando repetidamente, si hacemos threads asíncronos, el proceso volverá a iniciarse y podría ser que el anterior no hubiera terminado y dos procesos estuviesen intentando enviar las mismas facturas. No tengo claro como hacerlo, porque si espero a que termine un envío (proceso síncrono) ya no tengo procesos en paralelo... le tendremos que dar una vuelta.
Saludos

YellowStone 12-12-2024 13:33:00

De momento nosotros lo estamos controlando en desarrollo con un campo en la base de datos, cada vez que comienza un envío, se marca ese campo, y no se desmarca hasta que el propio proceso de envío lo desmarca al final, así si se intenta realizar un nuevo envío estando el campo marcado, no se permite.

El único problema que le veo a esto, que estoy pensando cómo solucionarlo, es que el proceso se interrumpa por cualquier motivo (un pantallazo azul de la muerte, por ejemplo) y no se desmarque el campo, y se queden las facturas sin enviar porque el proceso no arranca de nuevo.

ermendalenda 12-12-2024 14:07:50

Ojo con eso para no verifactu
Las bases de datos y datos tienen que estar claramente separadas para distintos obligados tributariosm
Y según cono tengas el sif también para verifactu.

rci 12-12-2024 15:19:35

Cita:

Empezado por ermendalenda (Mensaje 560696)
Ojo con eso para no verifactu
Las bases de datos y datos tienen que estar claramente separadas para distintos obligados tributariosm
Y según cono tengas el sif también para verifactu.

:eek:Anda no sabia nada de eso.
nosotros en principio solo haremos modo Veri*Factu.
En cada tabla hay un campo que indica de que obligado tributario es esa información... eso sirve para lo que dices ermendalenda?

razorxxx 12-12-2024 15:50:44

Cita:

Empezado por ermendalenda (Mensaje 560696)
Ojo con eso para no verifactu
Las bases de datos y datos tienen que estar claramente separadas para distintos obligados tributariosm
Y según cono tengas el sif también para verifactu.

¿Puedes indicar en qué artículo del reglamento pone que esto es así?

Neftali [Germán.Estévez] 12-12-2024 16:01:50

Cita:

Empezado por ermendalenda (Mensaje 560696)
Las bases de datos y datos tienen que estar claramente separadas para distintos obligados tributarios


No se que quiere decir eso.
En un ERP con multiempresa puedes una Base de Datos con diferentes obligados tributarios. Creo que es lo habitual si piensas en empresas con varias sucursales, por ejemplo; o en un despacho/gestoría que gestiona N clientes.

razorxxx 12-12-2024 16:24:08

Cita:

Empezado por Neftali [Germán.Estévez] (Mensaje 560706)
No se que quiere decir eso.
En un ERP con multiempresa puedes una Base de Datos con diferentes obligados tributarios. Creo que es lo habitual si piensas en empresas con varias sucursales, por ejemplo; o en un despacho/gestoría que gestiona N clientes.

Pues claro. Es que de lo contrario puedes tener centenares o miles de bases de datos y gestionar eso no veas...

ermendalenda 12-12-2024 19:40:38

He podido mal interpretarlo o no, no explica muy bien si. Pueden estar en el mismo conjunto pero respetando la separación de obligados tributarios y respetando el artículo
Ya que habla de "respetar la gestión" mas bien puede que sea eso y que permita la misma bd.
8. Lo veis claro?
Artículo 2(a)
Cita:

a) Deberá realizar de forma separada la gestión de los registros de facturación y, en su caso, de evento de cada obligado tributario, garantizando siempre las características indicadas en el artículo 8 del Reglamento para cada obligado tributario, de acuerdo con las especificaciones técnicas y funcionales de esta orden.

razorxxx 13-12-2024 09:06:45

Cita:

Empezado por ermendalenda (Mensaje 560711)
He podido mal interpretarlo o no, no explica muy bien si. Pueden estar en el mismo conjunto pero respetando la separación de obligados tributarios y respetando el artículo
Ya que habla de "respetar la gestión" mas bien puede que sea eso y que permita la misma bd.
8. Lo veis claro?
Artículo 2(a)

Cito textualmente lo que me han respondido por mail los del Veri*Factu:

P: Muchos de nuestros SIF multiempresa tienen una única base de datos para todos los obligados tributarios. ¿Obliga el reglamento a que los datos de cada obligado estén en bases de datos distintas?
R: No hay inconvenientes o restricciones en el uso de las BBDD internas, por lo que pueden organizarlas de la forma que mejor convenga.

Neftali [Germán.Estévez] 13-12-2024 09:10:29

Cita:

Empezado por ermendalenda (Mensaje 560711)
Ya que habla de "respetar la gestión" mas bien puede que sea eso y que permita la misma bd.
8. Lo veis claro?

Yo creo que cuando habla de "Deberá realizar de forma separada la gestión de los registros de facturación y, en su caso, de evento de cada obligado tributario...", se refiere justo a eso, a la gestión, no a cómo estén organizados físicamente esos registros.

razorxxx 13-12-2024 09:19:35

A la pregunta "El SIF que actúa en modo VERI*FACTU, ¿puede guardar los XML generados en una carpeta en disco hasta su envío, u obligatoriamente deben guardarse en base de datos para cumplir con los principios de integridad e inalterabilidad?" me han respondido lo siguiente:

La remisión a la AEAT de los registros en este tipo de sistemas es prácticamente inmediata. Durante el intervalo de segundos entre su generación y la remisión pueden almacenarlos de la forma interna que como desarrolladores ustedes decidan.


La franja horaria es GMT +2. Ahora son las 20:16:59.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi