quinta-feira, 17 de novembro de 2011

Codeigniter 2 + Gearman + Phpspec


PhpSpec?
Framework de BDD (Behavior-Driven Development) para o desenvolvimento e design de aplicações php orientadas por comportamento.  Para conhecer melhor BDD leia o artigo  http://www.urubatan.com.br/comparacao-entre-tdd-e-bdd-como-aprender-um-me-ajudou-com-o-outro/  do blog do Urubatan que é a fonte da imagem.



Instalar PhpSpec
O pacote do phpspec pode ser instalado pelo pear
$ sudo pear config-set preferred_state beta
$ sudo pear channel-discover pear.phpspec.net
$ sudo pear install --all-deps phpspec/PHPSpec

Criar estrutura inicial
Criar o diretório spec na rais do projeto com a seguinte estrutura para acomodar os arquivos de especificação.



Bootstrap da stack do Codeigniter
Criar o arquivo codeigniter-academic/spec/spec_helper.php que será importado a cada nova spec. A primeira linha do código inclui a stack do codeigniter utilizando o mesmo bootstrap customizado do CIUnit, isso possibilita a uitilização de qualquer bibliotecas do framework.

photo.png
Fixture
Copiar uma imagem-fixture qualquer no diretório
codeigniter-academic/spec/fixtures/photo.png para validar os testes e verificar se a classe ResizeImageJob faz corretamente o redimensionamento de uma imagem.

Após cada exemplo de teste a classe de especificação deve limpar as imagens thumbs geradas para que não inflencie nos demais exemplos.


Refatorar o worker 
O worker feito no post anterior foi refatorado para reutilizar as bibliotecas de manipulação de imagem do próprio Codeiginiter. Esta refatoração foi orientada por BDD com o uso do framework PhpSpec.

A classe ResizeImageJob:
 - Cria novas imagens de thumbs a partir da original
 - Preserva a imagem original
 - Permite desfazer a tarefa executada
 - Lança uma exception caso não receba um array com parametros

Criar o arquivo da especificação em codeigniter-academic/spec/ResizeImageJobSpec.php. 

O código é bem simples, antes de cada exemplo é criado um array com parâmetros com o path para a imagem de fixture, um array com a especificação dos tamanhos dos novos thumbs a serem criados além de outros. Os dois métodos privados server apenas como auxiliares para diminuir a repetição de código e deixá-lo mais DRY.

Extrair a classe responsável pela tarefa 
O código do worker (application/workers/resize_worker.php) do post anterior anterior possui mais de uma responsabilidade. Além de administrar o serviço do worker ele ainda manipula as imagens.  O objetivo é extrair a responsabilidade de redimensionar as imagens para uma nova classe de job.

A nova classe application/workers/resize_image_job.php encapsula a única responsabilidade de redimensionar as imagens.  Ela segue um pouco o design pattern command, recebendo parametros no construtor e executando a tarefa de sua responsabilidade no método execute(). Também possui um método undo() que reotrnar o estado antes da execução da sua tarefa.

Refatorar o script de inicialização do worker
Agora o scrip que inicializa o worker tem somente esta responsabilidade e a tarefa que o worker realiza pode ser feita alterando a classe ResizeImageJob sem a necessidade de parar e reiniciar o worker.  O script refatorado application/workers/resize_image_worker.php

Convenção nos nomes de arquivo
Para facilitar a manutenção dos workers e o carregamento automático das classes de jobs do projeto foi criado um helper que carrega a classe de job de mesmo prefixo do arquivo worker inicializado. Assim um arquivo worker resize_image_worker.php inclui sua classe job resize_image_job.phpO arquivo application/workers/worker_helper.php deve ser incluido na primeira linha de cada novo worker.

Rodando a suite de specs
Rodar as specs a partir do diretório raiz do projeto
(gearman) $ phpspec spec/ --formatter documentation --color
O resultado deve ser o mesmo da próxima a imagem afirmando que todos os exemplos da specificação definida no início da refatoração estão passado (green).


Referências:
http://www.phpspec.net
http://www.slideshare.net/marcello.duarte/phpspec-bdd-for-php
http://techportal.ibuildings.com/2011/07/21/outside-in-behaviour-driven-development-in-php
http://techportal.ibuildings.com/2011/08/03/outside-in-behaviour-driven-development-in-php-part-2
http://www.urubatan.com.br/comparacao-entre-tdd-e-bdd-como-aprender-um-me-ajudou-com-o-outro/

segunda-feira, 14 de novembro de 2011

Codeigniter 2 + Background Job + Gearman


Continuando o post anterior vamos criar os scripts para administrar o servidor Gearman e seus workers e instalar e configurar o Monit para monitorará-los. Os fontes podem ser emcontrados no repositório público do projeto em https://github.com/fcm/codeigniter-academic/tree/gearman

Iniciar e parar os workers
Criar o arquivo /etc/init.d/gearman-workers com o conteúdo abaixo.  Mais tarde o correto é refatorar o script para obter um path relativo ao worker, mas por hora isso é o suficiente.

Criar o arquivo /etc/init.d/pskiller.sh com o conteúdo abaixo que foi adaptado do script disponível em http://www.vivaolinux.com.br/script/pskiller

Agora é possível iniciar ou parar determinados workers pelo console. Depois de iniciar os workers é possível vizualizar no monitor (http://localhost/gearman-monitor/) os 5 workers registrados para atender as solcitações.
$ sudo /etc/init.d/gearman-job-server start
$ sudo /etc/init.d/gearman-workers start resize_worker.php # para iniciar 5 workers
$ sudo /etc/init.d/gearman-workers stop resize_worker.php # para parar todos

Instalar e configurar o Monit
O Monit serve para monitorar os serviços de um ou mais servidores, ele pode ser configurado para enviar notificações e/ou tomar alguma decisão assim que um serviço ficar fora do ar ou seu consumo chegar a um determinado nível crítico.

Para instalar no Ubuntu digite na linha de comando:
$ sudo apt-get install monit
Criar um arquivo de configuração de monitoramento
$ sudo vi /etc/monit/conf.d/gearman.conf
Incluir o conteúdo no arquivo /etc/monit/conf.d/gearman.conf
check process gearmand with pidfile /var/run/gearman/gearmand.pid
   start program = "/etc/init.d/gearman-job-server start; /etc/init.d/gearman-workers stop"
   stop program = "/etc/init.d/gearman-job-server stop"
   group gearman

Alterar as configurações gerias em /etc/monit/conf.d/general.conf
set alert fabrizio.machado@gmail.com
set alert fabrizio@gmail.com
set mailserver smtp.gmail.com port 587
        username "fabrizio@gmail.com" password "xxxxxx"
        using tlsv1
        with timeout 30 seconds
set daemon 60
set logfile /var/log/monit.log

Interface web de monitoramento
O Monit possui uma interface web de monitoramento disponível por padrão em http://localhost:6874/  com o usuário e senha de acesso admin e monit

É possível alterar as configurações de portas e login descomentando o bloco referente as configurações de acesso no arquivo /etc/monit/monitrc.
## Monit has an embedded web server which can be used to view status of 
## services monitored and manage services from a web interface. See the
## Monit Wiki if you want to enable SSL for the web server. 
#
# set httpd port 2812 and
#     use address localhost  # only accept connection from localhost
#     allow localhost        # allow localhost to connect to the server and
#     allow admin:monit      # require user 'admin' with password 'monit'
#     allow @monit           # allow users of group 'monit' to connect (rw)
#     allow @users readonly  # allow users of group 'users' to connect 

Referências:
http://gearman.org/
http://mmonit.com/
http://www.phpclasses.org/blog/post/108-Distributing-PHP-processing-with-Gearman.html
http://imasters.com.br/artigo/21385/php/processamento-distribuido-em-php-utilizando-gearman-parte-1
http://pecl.php.net/package/gearman

quinta-feira, 10 de novembro de 2011

Codeigniter 2 + Background Job + Gearman


O Gearman distribui o processamento de tarefas em vários workers, permite executar tarefas em paralelo e até mesmo tarefas em hosts separados.  É possível trabalhar com tarefas síncronas ou assíncronas usando uma fila de jobs que pode ser persistente ou armazenada em memória.



Instalando Gearman no Ubuntu
Instalar o pacote via apt-get
$ sudo apt-get install gearman-job-server
Incluir as linhas no arquivo /etc/default/gearman-job-server para persistir a fila de tarefas.
# Parameters to pass to gearmand.
PARAMS="--listen=127.0.0.1 -q libsqlite3 --libsqlite3-db=/tmp/gearman.sqlite"
Reiniciar o serviço com as novas configurações:
$ sudo /etc/init.d/gearman-job-server restart
Para consultar a lista de tarefas pendentes na fila:
$ sqlite3 /tmp/gearman.sqlite
sqlite> select * from gearman_queue;

Configurando o Gearman-Monitor
Baixar os arquivos do projeto em https://github.com/yugene/Gearman-Monitor no  diretório público do servidor http.  As configurações podem ser modificadas no arquivo /var/www/gearman-monitor/_config.php

É possivel monitorar os servidores disponíveis, a quantidade de workers registrados a quantidade de jobs rodando e aguardando na fila.


Configurando extensão PHP
Instalar o pacote pelo pecl http://pecl.php.net/package/gearman
$ sudo pecl install gearman

Configurando a Lib Gearman no Codeigniter

Basta copiar os arquivos e configurar conforme as instruções do link http://codeigniter.com/wiki/Gearman


Criando o Worker
A idéia é que o redimensionamento das imagens não trave a navegação do cliente.  De maneira assíncrona o worker redimensiona a  imagem para todos os tamanhos necessários e quando concluído envia um email para o cliente ou até poderia atualizar as imagens em real-time com o uso de alguma tecnologia de pushing com websockets.

Criar o arquivo application/workers/resize_worker.php com o conteúdo abaixo.  Este é o worker que recebe e realizar o trabalho de redimensionar as imagens em background.

Para iniciar o worker basta executar o script php.  Depois é possível observar no Gearman-Monitor este worker registrado e aguardando a solicitação dos clientes.
$ sudo php <app>/application/workers/resize_worker.php

Continuação:
Nos próximos posts continuarei com a configuração dos serviços de monitoramento e scripts para administração do Gearman usando o Monit e também como integrar melhor os workers com a stack do Codeigniter para reutilizar as bibliotecas padrões do framework.

Referências:
http://gearman.org/
http://www.phpclasses.org/blog/post/108-Distributing-PHP-processing-with-Gearman.html
http://imasters.com.br/artigo/21385/php/processamento-distribuido-em-php-utilizando-gearman-parte-1
http://pecl.php.net/package/gearman


quarta-feira, 9 de novembro de 2011

Codeigniter 2 + BDD com Behat + Mink

Instalar os pacotes

Instalar o pacote do Behat
$ pear channel-discover pear.symfony.com
$ pear channel-discover pear.behat.org
$ pear install behat/behat
$ behat
Instalar o pacote do Mink
$ pear channel-discover pear.behat.org
$ pear install behat/mink-beta
Instalar o Sahi conforme instruções no site http://sahi.co.in/w/using-sahi

Após a instalação será criado o diretório ~/sahi. Abra um novo terminal, execute o programa e configure o navegador para usar o proxy na porta 9999.


 Esta configuração e outras podem ser modificadas em ~/sahi/config/sahi.properties
$ cd ~/sahi/bin
$ ./sahi

Teste funcional do login com a conta do Twitter.

Fazer o bootstrap para criar o diretório /features e os arquivos necessário para os testes.

$ cd <projeto>
$ behat --init
Alterar o arquivo  features/bootstrap/FeatureContext.php

Criar arquivo de configuração geral em /features/config/behat.yml

Criar o arquivo para descrever os cenários de teste da funcionalidade em /features/auth_twitter.features

Tudo configurado volte a aba do terminal do projeto e execute

$ cd features
$ behat auth_twitter.feature
O resultado será algo como a tela abaixo, perceba que na outra aba esta rodando o proxy do Sahi




Referências:
http://docs.behat.org/quick_intro.html
http://docs.behat.org/cookbook/behat_and_mink.html
http://techportal.ibuildings.com/2011/07/27/behaviour-driven-development-in-php-with-behat/
http://sahi.co.in/w/

Codeigniter 2 + Design Pattern + OAuth



Alterando o Modelando de Classes
Foram inseridas as novas classes (em verde) para contemplar o novo requisito de autenticação de usuários do sistema.  Definimos que no sistema uma Pessoa pode ter mais de uma conta de acesso, ou seja, ela vai poder logar no sistema usando seu usuário de sistema ou de outros serviços como twitter, facebook, etc.


Alterando as tabelas do banco

Criar a tabela Accounts para armazenar as propriedades das conta de usuário
CREATE TABLE  `academico_test`.`accounts` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`provider` varchar(100) DEFAULT NULL,
`login` varchar(150) NOT NULL,
`password` varchar(150) NOT NULL,
`oauth_token` varchar(255) DEFAULT NULL,
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1

Incluir o campo person_id em Accounts que é necessário para relacionar  uma conta a uma pessoa
ALTER TABLE `academico_test`.`accounts` ADD COLUMN `person_id` INT  NOT NULL AFTER `id`;


TDD

Começamos com a classe de teste tests/models/AccountTest.php para validar a criação do modelo.




Fixtures

Criar a fixture de dados em tests/fixtures/accounts_fixt.yml
1:
    provider: 'twitter'
    login: 'fabriziocolombo'
    password: ''
    oauth_token: ''
    person_id: 6
    
2:
    provider: 'facebook'
    login: 'fernandamontenegro'
    password: ''
    oauth_token: ''
    person_id: 4

2:
    provider: 'erp'
    login: 'jms'
    password: '123456'
    oauth_token: ''
    person_id: 7   
Implementação 


Implementar a classe de modelo application/models/Account.php

Agora ao rodar os testes eles devem passar
$  phpunit --testdox --color models/AccountTest.php
------------------
Account
 [x] Should success with valid provider
 [x] Should error message with invalid provider


Configurando a biblioteca Twitter no Ci

Baixar a biblioteca para twitter em http://www.haughin.com/code/twitter/ e seguir os para para instalação e configuração.


Serviço de autenticação com o Padrão de Projeto Strategy
Como a aplicação possibilita mais de uma opção de conta de acesso, vamos aplicar um padrão de projeto conhecido como Strategy, que possibilita implementar mais de um tipo de estatégia para uma finalidade de forma flexível.

Criamos um aquivo de teste em tests/models/AuthenticationServiceTest.php para guiar o desenvolvimento da funcionalidade. Observe que a classe real de acesso ao Twitter foi mockada (Mock)  para os testes.  Isso é possível graças a Injeção de Depêndencia (DI) implementada no método construtor da classe AuthenticationService.

A classe application/model/Authentication.php define a interface que as classes que implementarem a autenticação devem respeitar.

A classe application/model/TwitterAuthentication.php implementa as regras para logar com a conta do twitter no sistema

A classe application/model/ErpAuthentication.php implementa as regras para logar com a conta do próprio sistema. Ela deve ser refatorada para prover maior segurança.

E por fim a classe application/model/AuthenticationService.php que vai servir como uma fábrica de objetos para instanciar em tempo de execução os objetos que implementam a autenticação dependendo da necessidade.



Também foi criada uma pequena Domain Specific Language (DSL) para a autenticação com o uso de Method Chaining do Php 5 que possibilita chamadas com a seguinte API.

$current_user = AuthenticationService::register($account)->using('twitter');