Interface visual do Advpl – SmartClient

Introdução

Nos posts anteriores, vimos um pouco do que o SmartClient é capaz de fazer, mas há muito mais a ser visto. O que não vimos ainda são alguns detalhes, particularidades e características do SmartClient. Agora que já vimos um pouco do que ele faz, vamos ver mais algumas coisas, e um pouco de como isto é feito por dentro.

Conexão TCP

Entre o SmartClient e o Application Server, existe uma conexão TCP estabelecida, que parte do SmartClient. No arquivo de configuração do SmartClient, chamado smartclient.ini, podemos criar seções nomeadas para especificar IP e Porta para a conexão com um Application Server. Na tela inicial do SmartClient, podemos especificar o programa a ser executado, qual a conexão nomeada deve ser utilizada, e qual o nome do ambiente (Environment) no Application Server deve atender esta requisição de processamento.

Time-Out de Comunicação

Quando ativamos uma interface, como por exemplo uma janela ou caixa de diálogo, o APPlication Server permanece dentro do método Activate(), aguardando por interações de interface. Nesta situação, o controle de execução da aplicação está na interface. Mesmo que o operador não faça nada na interface, apenas fique olhando para a tela, a cada 60 segundos o SmartClient envia um pulso na conexão com o Application  Server, apenas para informar que ele (SmartClient) está “vivo”.

Existe um mecanismo de time-out de inatividade de comunicação TCP no Application Server, ativo quando o controle de execução está na interface. Caso o Application  Server não receba nada (nem mesmo um pulso) em 3 minutos, ele (AppServer) assume que algo horrivel aconteceu com o SmartClient, ou com a conexão de rede entre ele e o Application  Server. Neste caso, o APPlication Server encerra a conexão, mostrando uma mensagem no log de console do Application  Server “MsgManager – TimeOut waiting for data”, e encerra a aplicação em execução, fecha as conexões em uso com gateways de dados ( DBAccess, c-Tree), solta locks de tabelas, e todos os demais recursos consumidos e alocados para aquele programa. Afinal, se a interface não está mais lá, não faz sentido manter o contexto da aplicação aberto segurando recursos.

Time-Out por Inatividade de Interface

Existe uma configuração diferenciada para o ambiente, chamada de “INACTIVETIMEOUT”, que significa um tempo de inatividade de interação do usuário na interface. Quando o servidor está aguardando por interação do usuário, se este fica apenas olhando para a tela, o Application  Server recebe a cada um minuto um pulso, mas este pulso não conta como interação do usuário. Deve haver o disparo de algum evento de componente de interface para que este contador de inatividade retorne ao zero novamente, como por exemplo uma troca de foco entre componentes. Caso esta configuração esteja habilitada, e o operador ficar mais do que o tempo configurado sem interagir com a interface, o SmartClient deste operador é encerrado com uma mensagem de Time-Out atingido por inatividade.

Balanceamento de Carga

O TOTVS Application Server permite, de forma nativa, configurar um serviço para balanceamento de conexões de SmartClient entre vários serviços do Application Server, na mesma máquina e/ou em outras máquinas. Todo o procedimento de configuração desta funcionalidade está documentada na TDN, vide link http://tdn.totvs.com/pages/viewpage.action?pageId=6064861

Uma característica interessante do balanceamento de carga do TOTVS Application Server, é que o serviço de balanceamento não atua como um gateway ou proxy reverso. O balanceador mantém uma conexão persistente de monitoramento com cada serviço slave configurado nele, e no momento que o balanceador recebe uma conexão do SmartClient, ele verifica entre os serviços disponívels, quem está com o menor número de processos em execução, e retorna ao SmartClient uma informação de redirecionamento, para que o SmartClient conecte diretamente no serviço slave que ele escolheu.

Por isso, se o serviço do balanceador for interrompido, isto não interfere nas conexões já estabelecidas e em execução nos serviços slave. E, também por esta razão, todos os IPs e portas de todos os serviços slaves devem estar visíveis para que qualquer SmartClient que conectar com o Balance, seja capaz de conectar com qualquer um dos slaves utilizazdos para balanceamento.

Outro ponto interessante é que o serviço de Balance leva em conta um flag de aceite de conexão por parte do Slave. Meso que o serviço slave esteja no ar, caso você use o TOTVS Monitor, e bloqueie as conexões naquele serviço, o serviço de Balance vai saber que as conexões daquele slave estão bloqueadas, e não vai mais considerar aquele slave na distribuição, até que ele seja novamente desbloqueado para aceitar novas conexões. Esta característica foi muito útil quando foi implementado um mecanismo de proteção de alocação de memória no Application Server, onde caso a memória em uso por um Slave ultrapasse 90% do limite suportado pelo Application Server, este Slave automaticamente desabilita a entrada de novas conexões, e o Balance passa a desconsiderá-lo. Somente quando a memória daquele slave volta ao patamar de 80% do limite, o slave automaticamente libera novas conexões, e o Balance volta a considerá-lo no algoritmo de distribuição.

Conexão SSL

A conexão TCP entre SmartClient e Application Server troca pacotes em formato proprietário, que não é interpretável facilmente, porém nesta camada não é aplicada nenhuma criptografia. Dependendo do tamanho do pacote, ao utilizar por exemplo um “Sniffer” de rede, você poderá eventualmente ver strings com textos e dados de campos serem trafegados. Para oferecer uma forma de criptografia segura das informações trafegadas entre Application Server e SmartClient, podemos configurar o Application Server para utilizar um certificado digital — seção SSLCONFIGURE — e configurar uma porta SSL para receber as conexões do SmartClient. Assim, desta forma, os dados trafegados entre estas aplicações vão estar efetivamente criptografados.

Log de comunicação

Todas as mensagens trocadas entre o APPlication Server e o SmartClient podem ser registradas no log de console (Console.log) do APPlication Server, utilizando a chave LOGMESSAGES=1 na seção [GENERAL] do arquivo de configuração do APPlication Server (Appserver.ini). Experimente pegar um destes exemplos de interface, e executar com este log habilitado no APPlication Server, e você vai ver quais e quando são trocadas as mensagens entre as aplicações. Faça isso em um ambiente separado, de testes, pois a geração deste log ao mesmo tempo por múltiplas conexões pode onerar um ambiente de produção. Este tipo de LOG somente é necessário e utilizado quando existe a necessidade de investigar um comportamento anormal da interface ou do APPlication Server relacionado ao uso de algum componente de interface, habilitado em ambientes específicos de desenvolvimento e testes.

Versões e Plataformas de Smartclient

Até o momento, o AdvPL possui 3 versões de interface SmartClient: O SmartClient em formato executável, compilado para as plataformas Windows, Linux e MAC; o SmartClient ActiveX, que pode ser publicado em um servidor HTTP / WEB e instalado como uma extensão / Plug-In do Internet Explorer, e por último o SmartClient HTML, que pode ser instanciado pela maioria dos Internet Browses de mercado sem a necessidade de instalação de nenhuma extensão ou Plug-In. Existem algumas limitações no Smartclient ActiveX e no SmartClient HTML, por exemplo a impossibilidade de usar as funções de baixo nível de arquivo ( fopen, fcreate, … ) no sistema de arquivos da máquina onde o SmartClient está sendo utilizado.

Como ainda não falamos nada sobre o sistema de arquivos do AdvPL, por hora vamos apenas saber que, usando as funções de acesso a disco e arquivos do AdvPL, podemos endereçar arquivos na máquina onde está sendo executado o TOTVS Application Server, a partir do RootPath do ambiente, e podemos também acessar o sistema de arquivos da máquina onde o SmartClient que iniciou a execução de uma aplicação está rodando. Este tema também será abordado posteriormente, em tópico específico.

Boas práticas

O cenário ideal para a utilização de interface Client-Server persistente é para processamento de requisições de retorno rápido. Relatórios extensos ou processamentos que demoram mais do que alguns minutos devem ser evitados de serem iniciados através de uma conexão de interface, afinal se esta conexão cair por qualquer razão durante o processamento, normalmente em até 3 minutos o APPlication Server deve perceber que a conexão com o SmartClient foi perdida, e assim que isso acontecer, ele vai encerrar a execução da aplicação, não importa se ela tenha terminado o seu processamento ou não. Em ambientes intranet, onde pressupõe-se uma estabilidade maior na conexão, isto pode não ser tão impactante, mas em um acesso remoto ou via internet, isso pode ser um pouco traumático.

Para situações como essas, existem relatórios que podem ser executados no sistema ERP em Job (processo sem interface), ou colocados para serem executados em um Scheduler (agendador) do ERP, onde você pode programar a execução de um relatório ou recalculo que vai demorar muitas horas, e programá-lo para ser executado durante a noite, o processamento não vai depender de interface, e se tudo correr bem, estará pronto na manhã seguinte.

As boas práticas de interface vão um pouco além do código, vão desde a disposição dos componentes em tela de forma visualmente agradável e lógica, dada a sequência da operação do sistema, até a coerência e clareza das mensagens e informações solicitadas aos usuários ou operadores durante o uso da aplicação. Nem sempre uma mensagem que é muito clara para o programador é entendida pelo usuário. Normalmente colca-se uma mensagem com teor explicativo ao operador do sistema, e em um segundo ponto da mensagem, informações técnicas úteis para o departamento de suporte e programação.

Existem ainda outras boas práticas da programação para a interface AdvPL. Uma delas é não interromper uma operação transacionada na base de dados com uma operação de interface que aguarde uma decisão de usuário. Isso mantém a transação aberta por tempo indeterminado, e mantém o bloqueio (lock) de registros na base de dados, o que pode prejudicar outros processos concorrentes. Caso o operador tenha iniciado um processo e saído de sua estação para tomar um café, ele somente vai ver a mensagem quando ele voltar, e durante este tempo registros da base de dados permaneceram bloqueados, impedindo outros processos concorrentes que dependam do bloqueio nestes registros para serem executados. Normalmente a operação transacionada em base de dados é realizada usando as instruções BEGIN TRANSACTION e END TRANSACTION. Vamos entrar nesse assunto em maior profundidade em posts posteriores sobre a o acesso a tabelas e dados no AdvPL.

Exemplo AdvPL

E, quase no final do tópico, vamos a mais um exemplo AdvPL, de uma rotina que procura obter o máximo de informações possíveis do SmartClient em execução, que iniciou o programa atual. Segue fonte abaixo:

#include 'protheus.ch'
/* ======================================================================
Função U_RmtDet()
Autor Júlio Wittwer
Data 01/02/2015
Descrição Monta uma caixa de diálogo com todas as informações possíveis
de se obter do SmartClient que iniciou este programa.
====================================================================== */
User Function RmtDet()
Local oDlg
Local nRmtType
Local cRmtType
Local cRmtLib
Local oFont
Local cInfo := ''
// Habilita interface com data mostrada com 4 digitos no ano
// e Habilita data em formato britânico ( Dia/Mes/Ano )
SET CENTURY ON
SET DATE BRITISH
cRmtLib := ''
nRmtType := GetRemoteType ( @cRmtLib )
DO CASE
 CASE nRmtType == -1
 UserException("Invalid JOB/BLIND call to U_RmtDet")
 CASE nRmtType == 0
 cRmtType := 'SmartClient Delphi'
 CASE nRmtType == 1
 cRmtType := 'SmartClient QT Windows'
 CASE nRmtType == 2
 cRmtType := 'SmartClient QT Linux/Mac'
 CASE nRmtType == 5
 cRmtType := 'SmartClient HTML'
 OTHERWISE
 cRmtType := 'Remote Type '+cValToChar(nRmtType)
ENDCASE
If !empty(cRmtLib)
 cRmtType += ' ('+cRmtLib+')'
Endif
// Usa uma fonte mono-espaçada 
DEFINE FONT oFont NAME 'Courier New'
// Cria uma caixa de diálogo com área util de 640x480 PIXELs
DEFINE DIALOG oDlg TITLE (cRmtType) FROM 0,0 TO 480,640 PIXEL
// Informações da Interfae remota
cRmtBuild := GetBuild(.T.)
cRmtIp := GetclientIP()
cUsrName := LogUserName()
dRmtDate := GetRmtDate()
cRmtTime := GetRmtTime()
aRmtInfo := GetRmtInfo()
cRmtTmp := GetTempPath(.T.)
lActivex := IsPlugin()
lSSLConn := IsSecure()
cInfo += 'SmartClient Build ....... ' + cRmtBuild + CRLF
cInfo += 'SmartClient Activex ..... ' + IIF(lActivex,"SIM","NAO") + CRLF 
cInfo += 'SmartClient Connection .. ' + IIF(lSSLConn ,"SSL","TCP") + CRLF 
cInfo += 'Remote IP ............... ' + cRmtIp + CRLF 
cInfo += 'Remote User Name ........ ' + cUsrName + CRLF 
cInfo += 'Remote DateTime ......... ' + dtoc(dRmtDate)+' '+cRmtTime + CRLF
cInfo += 'Remote Temp Path ........ ' + cRmtTmp + CRLF
cInfo += 'Remote Computer Name .... ' + aRmtInfo[1] + CRLF
cInfo += 'Remote O.S. ............. ' + aRmtInfo[2] + CRLF
cInfo += 'Remote O.S. Detais ...... ' + aRmtInfo[3] + CRLF
cInfo += 'Remote Memory (MB) ...... ' + aRmtInfo[4] + CRLF
cInfo += 'Remote CPU Count ........ ' + aRmtInfo[5] + CRLF
cInfo += 'Remote CPU MHZ .......... ' + aRmtInfo[6] + CRLF
cInfo += 'Remote CPU String ....... ' + aRmtInfo[7] + CRLF
cInfo += 'Remote O.S. Language .... ' + aRmtInfo[8] + CRLF
cInfo += 'Remote Web Browser ...... ' + aRmtInfo[9] + CRLF
// Coloca a string com os dados dentro de um Get Multiline
@ 5,5 GET oGet1 VAR cInfo MULTILINE FONT oFont SIZE 310,230 OF oDlg PIXEL

ACTIVATE DIALOG oDlg CENTER

Return

O resultado obtido com a execução do programa deve ser algo parecido com a caixa de diálogo abaixo:

Exemplo da execução do programa U_RmtDet
Exemplo da execução do programa U_RmtDet

Conclusão

Como eu já havia dito, com AdvPL podemos fazer muitas coisas, inclusive um ERP. Eu (ainda) não tenho todas as demais interfaces de SmartClient configuradas no meu ambiente, então pode ser que alguma das funções utilizadas no exemplo acima retornem conteúdos em branco ou apresentem erro de execução caso este exemplo seja executado dentro de um SmartClient ActiveX ou SmartClient HTML. De qualquer modo, eles foram concebidos para serem capazes de renderizar a interface da mesma forma.

Muitas vezes o arroz com feijão será usado na maioria das rotinas e interfaces do sistema, porém algumas rotinas podem precisar de algo um pouco mais específico, um pouco mais rebuscado. E a linguagem é capaz de prover isso. Até o próximo post, pessoal 😉

Referências

http://tdn.totvs.com/display/tec/GetRemoteType
http://tdn.totvs.com/display/tec/GetBuild
http://tdn.totvs.com/display/tec/GetComputerName
http://tdn.totvs.com/display/tec/GetRmtDate
http://tdn.totvs.com/display/tec/GetRmtTime
http://tdn.totvs.com/display/tec/GetRmtInfo
http://tdn.totvs.com/display/tec/GetTempPath
http://tdn.totvs.com/display/tec/IsPlugin
http://tdn.totvs.com/display/tec/IsSecure
http://tdn.totvs.com/display/tec/LogUserName

Anúncios

5 comentários sobre “Interface visual do Advpl – SmartClient

  1. Olá, eu fiz um teste configurando dois appservers, sem nenhuma configuração master/slave, considere os ip 192.168.1.10 e 192.168.1.20.

    Configurei 3 smartclientes para acessar o primeiro, e outros 3 smartclientes para acessar o segundo. Nada muito interessante, balanceamento de carga estático/burro, definindo a configuração no cliente.

    Evoluindo o teste, eu configurei duas entradas no meu servidor DNS com o mesmo nome, ex.:

    appserver A 192.168.1.10
    appserver A 192.168.1.20

    Desta forma, a cada tentativa de resolução de nome, eu obtinha o IP diferente (round-robin), nos teste que fiz, nada fora do normal.

    Daí vem minha pergunta.

    O smartclient pode se comportar de alguma forma inesperado neste segundo setup ? Imaginando que ele abra a conexão TCP após a resolução do nome para o IP, haverá outra tentativa de resolução, antes que o socket TCP seja interrompido (não vejo motivo) ?

    Imagino que esta seja uma forma simples de configurar um balanceamento de carga, sem a inteligência de enviar as conexões para o appserver que tenha a menor carga, caso não tenha esta necessidade.

    Curtido por 1 pessoa

    • Opa, em princípio não. Inclusive existem clientes que utilizam balanceamento desta forma. Você apenas deixa de usufruir dos benefícios do mecanismo de balanceamento do Protheus como Load Balance 😀

      Curtir

  2. Excelente artigo! Assim como seu outro artigo sobre load balancing!
    Tenho um ambiente com Master e 2 Slaves e estou buscando a solução para uma situação curiosa.
    Os usuários estão em um ambiente de Terminal Service, onde o acesso ao smartclient é realizado através de um atalho para o executável que está no application server.
    Frequentemente, ao realizar algum processo específico, como por exemplo impressão de Danfe, o usuário recebe uma tela de erro do Windows, do tipo “Smartclient has stopped working” e clicando na opção “Close the program”, o Protheus é encerrado.
    O mais curioso é que conseguimos isolar o seguinte cenário: quando o atalho que mencionei utiliza o nome do servidor, o erro ocorre. Agora, quando apontamos o atalho para o mesmo local, porém utilizando o IP do servidor de aplicação, não ocorre erro nenhum.
    Em teoria, essa alteração (nome por IP) não deveria ter todo esse impacto…como vejo que você conhece tanto a parte de infraestrutura quanto do sistema do Protheus, gostaria de saber se já viu algo semelhante.
    Obrigado!

    Curtido por 1 pessoa

    • Rapaz, eu já vi o SmarClient dar um “falso positivo” de “Crash” — Porem, nunca vi dar problema em atalho usando o hostname versus IP … Definitivamente, isto é “estranho” …rs…

      Curtir

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s