1. Introdução
Em uma configuração de redundância (Hot-Standby), dois servidores E3 — A e B — rodam o mesmo Domínio, mas apenas um deles está ativo (Running) a cada momento; o outro fica em Standby. É comum precisar automatizar alguma rotina externa (por exemplo, um script Python em execução em cada uma das duas máquinas) que precisa descobrir localmente se o servidor daquela máquina específica é o servidor ativo agora ou não.
A forma correta de responder a essa pergunta é consultar o servidor ativo E3 via o objeto runtime [?Server], especificamente a propriedade State do servidor local. Essa verificação, no entanto, está sujeita a uma condição de conexão frequentemente negligenciada: se a conexão for estabelecida para um endereço de domínio (com failover automático) em vez do host físico local, a leitura sempre indica “ativo”, independentemente do estado real daquele servidor.
2. O que é o objeto [?Server]
[?Server] é um objeto runtime real (não uma macro), exposto pelo próprio E3 Server, que devolve informações sobre o servidor e sua topologia — domínio, hot-standby, sessões de clientes, licenças e domínios remotos. Os colchetes são obrigatórios, pois ? não é um caractere válido em identificadores comuns:
Application.GetObject(":[?Server]").ProductString
Dentro dele, a árvore Domain.Servers expõe o par de redundância:
- LocalServer — sempre presente; é o servidor que está sendo acessado pela conexão atual.
- RemoteServer — presente apenas quando
HotStandby = True; é o par secundário.
Ambos expõem a propriedade State, um Long com o seguinte enum:
| Valor | Significado |
|---|---|
-1 |
Fechado / nenhum Domínio carregado |
0 |
Parado (carregado, mas não em execução) |
1 |
Standby |
2 |
Running (ativo) |
3. Requisito de conexão: servidor local versus endereço de domínio
O fator determinante é para onde a conexão aponta. Se o cliente (Viewer, RemoteDomain ou uma automação externa via COM) se conecta a um endereço “de domínio” que já redireciona automaticamente para quem estiver ativo, a leitura de State quase sempre retorna 2 — porque esse tipo de conexão só consegue se conectar a servidores em execução ativa. Esse é, inclusive, o comportamento documentado da propriedade: em contextos runtime normais, Domain.State é quase sempre 2.
Para que a leitura reflita corretamente o estado daquela máquina específica (A ou B), a conexão precisa ser feita explicitamente para o servidor local daquele host — por exemplo, localhost ou o nome daquela máquina em particular — e não para um endereço com failover automático.
4. Como consultar via script (VBScript, dentro do E3)
Dentro de um script rodando no próprio E3 (por exemplo, em um evento OnStartRunning ou em um Timer), a leitura é direta:
Dim estadoLocal estadoLocal = Application.GetObject(":[?Server].Domain.Servers.LocalServer").State Select Case estadoLocal Case 2 ' Este host é o servidor ativo agora Case 1 ' Este host está em Standby Case 0 ' Domínio parado Case -1 ' Nenhum Domínio carregado End Select
5. Como aplicar isso a partir de um script externo (Python)
A mesma regra vale para qualquer automação externa que se conecte ao E3 via automação COM — e não apenas para scripts internos. As bibliotecas oficiais de conexão externa da Elipse (E3DataAccess, e nas versões mais novas E3AccessLayer, usada inclusive pelo EPM para coletar dados do E3) expõem um objeto cuja propriedade Server recebe o nome do host a que conectar. Por serem bibliotecas COM padrão, qualquer linguagem com suporte a automação COM — incluindo Python, via pywin32 (win32com.client) — pode instanciá-las do mesmo jeito que uma aplicação VBA.
Procedimento recomendado, aplicado na resolução do caso que originou este artigo:
- No projeto local de cada servidor (A e B), um pequeno script VBScript (Timer ou
OnStartRunning) gravaApplication.GetObject(":[?Server].Domain.Servers.LocalServer").Stateem uma Tag comum do projeto — por exemplo,Dados.ServidorLocalAtivo. - O script Python, em execução naquela mesma máquina, conecta-se explicitamente ao servidor local (
Server = "localhost"ou o nome daquele host específico — nunca o endereço de domínio/failover) e lê o valor dessa Tag pelo métodoGetValueda biblioteca de conexão externa. - Resultado:
2= este host é o ativo agora;1= este host está em Standby.
import win32com.client e3 = win32com.client.Dispatch("E3DATAACCESSLib.E3DataAccessManager") e3.Server = "localhost" # host LOCAL da própria máquina — nunca o domínio/failover estado = e3.GetValue("Dados.ServidorLocalAtivo") # 2 = este host é o ativo agora / 1 = este host está em Standby
Requisito obrigatório, independentemente da biblioteca utilizada: a conexão (Server) deve apontar para o host físico local da máquina onde o script Python é executado, e não para um endereço de domínio com failover automático; caso contrário, os dois scripts (A e B) lerão o mesmo valor, sempre “ativo”.
6. Observações e boas práticas
E3DataAccessé documentada oficialmente apenas para aplicações 32-bit; a partir da versão 4.5.208 do E3Server, as conexões viaE3DataAccesseE3AccessLayernão consomem mais licenças de Viewer.- Os métodos
Domain.RefresheDomain.Stopdo objeto[?Server]exigem E3 V6.1 Build 046 ou superior — não usados neste caso, mas fazem parte da mesma árvore[?Server].Domain. - Como o enum de
Stateé o mesmo emDomain.Statee emDomain.Servers.LocalServer.State/RemoteServer.DomainState, é possível montar um dashboard completo do par de redundância (local + remoto) com as mesmas Tags-ponte. - Evite depender de
Domain.State(sem o caminhoServers.LocalServer) para diferenciar A de B — em conexões via domínio ele reflete o servidor ativo, não necessariamente o host onde o script roda.
