Programar é uma arte cheia de surpresas

Às vezes, você até sabe que fazer determinada coisa em software vai ser fácil. Mas sempre haverá alguma coisa para desviá-lo do caminho. Abaixo, um breve conto sobre dificuldades no desenvolvimento de software.

[Cueball sitting in an office chair at his desk typing on his laptop. A person addresses him from the left:] Off-panel voice: What are you working on? Cueball: Trying to fix the problems I created when I tried to fix the problems I created when I tried to fix the problems I created when...
‘Qual era o problema original que você tentava resolver?’ ‘Bem, percebi que uma das ferramentas que eu usava tinha uma ineficiência que que estava desperdiçando o meu tempo.’ – https://www.xkcd.com/1739/
Precisávamos fazer a nossa aplicação se conectar via websocket com outra. Como essa aplicação já usava o Jetty, utilizamos as bibliotecas de websocket do Jetty. Aí, alguém encontrou o seguinte exemplo:

WebSocketContainer container = ContainerProvider.getWebSocketContainer();
container.connectToServer(endpoint, uri);

A gente, como já é esperto, sabe que a aplicação pode ficar temporariamente sem internet, viu que isso podia dar erro e criou uma forma de reconectar em caso de erro:

private void connect() {
  try {
    WebSocketContainer container = ContainerProvider.getWebSocketContainer();
    container.connectToServer(endpoint, uri);
  } catch (Exception ex) {
    LOGGER.warn("No internet!", ex);
    connect();
  }
}


Só que não precisávamos entrar nesse loop infinito, a internet pode demorar para voltar, e talvez até toparíamos com um StackOverflowException. Adicionamos um reconnect:

private void connect() {
  try {
    WebSocketContainer container = ContainerProvider.getWebSocketContainer();
    container.connectToServer(endpoint, uri);
  } catch (Exception ex) {
    LOGGER.warn("No internet!", ex);
    reconnect();
  }
}
/**
 * Reconnect to websocket after X seconds
 */
private void reconnect() {
  new Thread(() -> {
    try {
      TimeUnit.SECONDS.sleep(10);
    } catch (InterruptedException ex) {
      LOGGER.warn("My cat won't let me sleep!", ex);
    }
    connect();
  }).start();
}

Commit, funcionalidade pronta para a próxima versão!

Em seguida, eu precisava mexer nessa outra funcionalidade… mas o telefone tocou. Eu tinha que resolver um pepino em outro andar e deixei o software rodando.

Ao voltar, me deparei com a seguinte mensagem nos logs: "too many open files", vindo de uma função que escrevia arquivos periodicamente. Pesquisando na internet, vi que isso acontece quando os arquivos são abertos mas não são fechados em um bloco de finally, ou quando arquivos não são abertos dentro do try-with-resources.

Mas todos os arquivos abertos estavam sendo fechados, o erro deveria estar vindo de outro lugar. Além disso, o software estava em produção há tempos, não era para dar problemas com apenas alguns minutos – ou horas? – de funcionamento. Voltei aos logs e procurei o primeiro erro que apareceu. Era do Jetty!

Se outra pessoa enfrentasse esse erro, talvez não tivesse se ligado. Talvez tivesse reescrito toda a lógica dos arquivos de texto achando que resolveu. Talvez o erro nunca surgisse para os desenvolvedores, porque reconnect() atrasa sua ocorrência e o desenvolvedor raramente deixa a aplicação rodando por muito tempo. Talvez o erro só fosse explodir no primeiro dia em produção… Ou talvez tivesse ido direto ao primeiro erro e me culpado por ter colocado essa reconexão no websocket do Jetty…

Fui pesquisar sobre o erro no Jetty e me deparei com uma issue no GitHub, em um estado que eu não gostaria de ver:

Tag verde de issue aberta no GitHub.

E o pior. As discussões indicavam que não era um problema do Jetty, e sim de outra biblioteca da qual ele dependia.

Como resolvi? Com alguma atenção, a issue dava algumas dicas sobre a origem do problema. Para resolver, apenas coloquei a linha como atributo de classe:

private WebSocketContainer container = ContainerProvider.getWebSocketContainer();

private void connect() {
  try {
    container.connectToServer(endpoint, uri);
  } catch (Exception ex) {
  [...]

Parece uma solução tão simples! Mas me tomou um bom tempo do dia, provando mais uma vez que programar é uma arte cheia de surpresas.

Anúncios

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 )

Foto do Google

Você está comentando utilizando sua conta Google. 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 )

Conectando a %s

Este site utiliza o Akismet para reduzir spam. Saiba como seus dados em comentários são processados.