"Arquitetura"/Design pattern para queue e execução de tarefas assíncronas (queue e envio de SMS)

Olá

ScadaBR 1.0 CE

Num sistema que estou a alterar (uma ETAR), o cliente necessita de enviar mensagens de SMS quando certas condições acontecem (boia de água A2 acima de um certo nível durante 20 segundos, etc.).

Estive a ver várias soluções (Modems com AT, Serviços externos por acesso REST, Email to SMS gateways, e Router com capacidade de SMSGateway).

Devido a várias razões (nem todas técnicas), escolhi a opção de usar um Router/SmsGateway para este fim (Teltonika RUT200). Basta colocar um SIM, e permite enviar SMS. É só fazer uma chamada GET ou POST para um dado endpoint do Router com os parâmetros indicados (telefone, mensagem, etc.).

Implementei o seguinte mecanismo: Event Detector no DataPoint e EventHandler que executa um script que faz a chamada de HTTP para envio do SMS.

Este mecanismo está a funcionar, mas tem um eventual problema. No local da ETAR às vezes o sinal GSM da operadora falha por um dado período. Consigo ver isso na página de status do router. Quando não há sinal de rede GSM, a chamada HTTP retorna um erro, a indicar que não conseguiu enviar o SMS.

Estava a pensar alterar o sistema, para ter uma queue de mensagens a enviar. O EventHander apenas teria que colocar na queue o pedido de um novo SMS (na realidade é só a mensagem que altera por cada alarme, o destino é sempre o mesmo: uma lista de números de telefones). Depois “um processo” teria que monitorizar essa queue, e ir enviando os SMS que lá estivessem. Lia uma mensagem a enviar, tentava enviar o SMS, e retirava da queue se sucesso. Se houvesse erro de falta de sinal GSM, poderia esperar um pouco até tentar de novo.

Como não conheço muito bem o ScadaBR, a minha pergunta é:
Quais as formas possíveis de implementar o que pretendo em ScadaBR 1.0 CE? Qual a forma que aconselham e quais as vantagens dessa solução?

Obrigado,
António

Boa noite,

Infelizmente, o ScadaBR e o Scada-LTS atualmente não dispõem de qualquer sistema de enfileiramento de tarefas nativo. Porém, o que se pode fazer nos scripts do ScadaBR é um pequeno “truque” para pôr o script para hibernar e fazer uma nova tentativa posteriormente.

Para isso, basta chamar o método java.lang.Thread.sleep() que põe a Thread do script em espera. Você poderia, em tese, usar isso para gerar um sistema de retries quando uma requisição HTTP retorna erro. Exemplo ilustrativo:

var sucesso = false;
var TIMEOUT = 30000; // 30 segundos

while (sucesso == false) {
    // Faça a requisição HTTP
    var req = simpleGet("http://example.com", params);

    // Verifique se a requisição deu certo (códigos HTTP de sucesso)
    if (req.status >= 200 && req.status <= 299) {
        sucesso = true;
    } else {
        java.lang.Thread.sleep(TIMEOUT);
    }
}

Ou usando for, para limitar a quantidade de retries:

var sucesso = false;
var TIMEOUT = 30000; // 30 segundos
var RETRIES = 5; // Número de tentativas

for (var i = 0; i < RETRIES; i++) {
    // Faça a requisição HTTP
    var req = simpleGet("http://example.com", params);

    // Verifique se a requisição deu certo (códigos HTTP de sucesso)
    if (req.status >= 200 && req.status <= 299) {
        break; // Encerra o for()
    } else {
        java.lang.Thread.sleep(TIMEOUT);
    }
}

Nota: no Scada-LTS, a política de segurança padrão dos scripts bloqueia a chamada direta à classe java.lang.Thread.

Obrigado pela resposta.
Tinha pensado que essa era uma possibilidade (retries dentro da mesma execução do scrip), e provavelmente a mais simples. O .sleep( ) é importante para não termos a thread em espera activa a gastar cpu.

Mas o número de threads pode aumentar, caso haja um problema de alguns minutos no GSM e existam vários alarmes a serem gerados, cujos SMS não consigam ser enviados. Mas suponho que, neste caso, o número de threads não seria problemático. De qq forma a queue de tarefas parece-me interessante para vários cenários.

Estou a partir do princípio que o sistema suporta ter vários scripts a executar em simultâneo em threads diferentes para o mesmo event handler. É assim?

Exemplo: das 5:00:00 às 5:00:59 um datapoint muda de valor em cada segundo (muda 60 vezes), e tem um event handler que executa um script que demora 2 mins a terminar (imaginemos que é trabalho “ativo”, e que não tem sleeps, é só um exemplo para colocar a dúvida :slight_smile:

Isto quer dizer que das 5h01 às 5h02 temos 60 threads a executar (e começam a diminuir das 5h02 às 5h03)? Ou os pedidos são “serializados” para o mesmo event handler? (presumo que não).

Off topic:
A nota “no Scada-LTS, a política de segurança padrão dos scripts bloqueia a chamada direta à classe java.lang.Thread .” é importante. Existe alguma lista (que vá sendo actualizada) das “breaking changes” do LTS?. No grupo do telegram de vez em quando vejo perguntas que estão relacionadas com alterações de comportamento. Normalmente as respostas têm a ver com melhorias de segurança => restrições ao que as apps / user scripts podem fazer.