Aprendizados PHP com Heroku

Este texto contém alguns dos aprendizados que obtive ao usar o Heroku como plataforma de infraestrutura de um importante projeto em produção. São anotações soltas de pontos específicos sobre o uso da plataforma, possivelmente úteis para quem está avaliando essa opção e precisa de mais informações.

Limite de 30 segundos

https://devcenter.heroku.com/articles/http-routing#timeouts
Todas as requisições possuem um limite máximo de 30 segundos. Ou seja, se você precisar de um processamento mais longo, é impossível via uma requisição tradicional. Nestes casos, você precisará utilizar workers e trabalhar com filas de tarefas.

Processos no Heroku (web e workers)

https://devcenter.heroku.com/articles/process-model
Uma aplicação no Heroku sempre terá um processo web que será o servidor da aplicação e processos do tipo workers. Um worker é um processo que roda em background. Você pode usar um worker para rodar tarefas como processar filas de envio de e-mails, robôs que acessam sistemas externos, processamento de grandes arquivos, etc.

Cada processo, web ou worker, roda em um dyno independente. Isso significa que se você tiver uma aplicação web com dois processos em background, você estará usando 3 dynos (e pagando os 3) na sua aplicação. Os dynos dos processos podem ser desabilitados a qualquer momento (gerando economia).

O loop do Worker

https://devcenter.heroku.com/articles/background-jobs-queueing
Um worker é um arquivo php que contém um loop onde ocorre o processamento. Ou seja, se você precisa de um comportamento que rode a cada minuto por exemplo, você terá que controlar o tempo no loop.

O Heroku não possui uma cron como no Linux. O que existe é o addon scheduler, que atua como uma cron, mas que possui um agendamento espaçado em pelo menos 10 minutos. Se ele não for adequado para o seu caso, o ideal é o uso dos workers.

Neste link há um exemplo de implementação em PHP completa, utilizando Monolog, RabbitMQ e outros componentes. É bacana, mas não é necessário, um simples while(true), como o código abaixo por exemplo, irá funcionar:

<?php

error_log('Iniciando Worker');

while(true) {
error_log('Log a cada 10 segundos');

sleep(10);
}

Edição de arquivos no servidor

https://devcenter.heroku.com/changelog-items/1112
É possível acessar o servidor do Heroku e a pasta com os arquivos. Porém, se você quiser editar algum arquivo diretamente no servidor (para pequenos testes por exemplo), você terá dois problemas.

O primeiro é que o único editor que vem por padrão é o ed. Eu nem conhecia. Você pode instalar o nano ou o vim via plugins.

O segundo é que quando você cria um arquivo novo pelo terminal e tenta acessá-lo via navegador, ele é executado normalmente, se você tentar modificá-lo, ao acessar o arquivo via navegador, é executada a versão anterior. É como se existisse um tipo de cache entre o roteamento e o arquivo, até agora não descobri como resolver, nem sei é possível. Portanto, aquele velho jeito de fazer algum debug direto em produção não é viável, a melhor opção é trabalhar com um log.

Trabalhando com logs

https://devcenter.heroku.com/articles/logging
Tudo no PHP que for logado usando a função error_log() ou que imprima uma saída para “php://stderr” irá aparecer nos logs do Heroku. Os logs podem ser vistos em tempo real pelo CLI com o comando “heroku logs — tail”.

Nesta página o pessoal do Heroku mostra exemplos em frameworks PHP.

Aplicativo de linha de comando do Heroku

https://devcenter.heroku.com/articles/using-the-cli
O Heroku possui um excelente aplicativo de linha de comando que permite ver logs, habilitar e desabilitar dynos e diversas outras funções.

Você não pode armazenar arquivos no servidor do Heroku

https://devcenter.heroku.com/articles/s3
Isso significa que se o seu sistema possui, por exemplo, um mecanismo de upload de fotos, as fotos não poderão ser armazenadas em uma pasta da sua aplicação, como normalmente é feito em servidores tradicionais ou em máquina local (saiba mais aqui). Você precisa usar um serviço externo para persistir os arquivos, que pode ser no banco de dados, em algum addon do Heroku, ou – a opção mais comum – usar o S3 da Amazon.

Para realizar o upload para o S3, existem duas abordagens: 1) enviar o arquivo para o S3 a partir do PHP, após o upload via formulário tradicional (exemplo aqui) ou 2) enviar o arquivo diretamente para o S3 pelo javascript.

A primeira é mais fácil de programar, mas como há a limitação de 30 segundos, se o arquivo for muito grande, pode não funcionar.

A segunda resolve o problema do limite de upload, mas é mais difícil de desenvolver. Para esta opção, também existem duas estratégia, muito bem exemplificadas neste artigo. O Heroku tem um exemplo desta abordagem em Node.js e a Amazon demonstra um destes conceitos usando a SDK do PHP.

O suporte ao PHP é muito bom

https://devcenter.heroku.com/articles/php-support
Como qualquer PaaS, não existe uma máquina disponível para instalarmos o que quisermos, existem limitações. Mas no caso do PHP, a notícia é boa, as versões do PHP disponíveis seguem a liberação oficial do PHP, portanto, a 7.2 já está lá. Há limites também nas extensões disponíveis, mas são várias disponíveis e para instalá-las basta especificar no composer.json.

Também é possível usar arquivos “.htaccess”, mudar a maioria das configurações do php.ini e escolher entre apache ou nginx, tudo explicado aqui: https://devcenter.heroku.com/articles/custom-php-settings

Como o Heroku Funciona (algumas observações gerais)

  • Uma aplicação corresponde a um código fonte com um arquivo que descreve as dependências da aplicação. Em PHP, é usado o composer.json;
  • Uma aplicação roda em um dyno. Em uma comparação “feia”, um dyno corresponde a uma máquina, ou melhor, um dyno é “um contêiner Unix, virtualizado e isolado, que oferece o ambiente no qual roda a aplicação”;
  • O processo que transforma a aplicação em código executável dentro de um dyno gerará um Buildpack que contém o código fonte, o código das dependências especificadas e o que for gerado pelo processo de build;
  • Todas as configurações são feitas utilizando variáveis de ambiente que podem ser controladas pela interface web ou pelo Heroku CLI;

Conclusão

O uso do Heroku é incrível para construir aplicações “resistentes à erosão” com maior potencial para ter um crescimento orgânico e sustentável do software. Em contrapartida, é mais difícil tecnicamente de desenvolver e potencialmente mais cara.

Pela sua natureza distribuída, todo tipo de persistências precisa ser pensada de forma independente e muitas vezes os addons disponíveis se tornam muito caros com o crescimento da aplicação ou são limitados (saiba mais aqui sobre como arquitetar aplicações para o Heroku).

Por exemplo, para uma aplicação como o datapedia que possui uma base de dados na casa dos gigabytes, não há nenhum addon de banco de dados com preço coerente para nós. Resumindo:

  • É um pouco mais difícil de programar;
  • As decisões sobre componentes externos precisam ser muito inteligentes;
  • Monitoramento e log se tornam parte indispensável do desenvolvimento.

Tudo indica que o potencial de longevidade do software compensa os trade-offs. E até que novos aprendizados aconteçam, parece uma ótima escolha.

Extra

Muito bom este manifesto/guia sobre construção de aplicações de software que funcionam em arquitetura distribuída: https://12factor.net/

Este artigo foi escrito em parceria com Fernando Jorge Mota.