[SP-pm] Passando uma string que contém o código de uma classe usando o Gearman

Daniel de Oliveira Mantovani daniel.oliveira.mantovani at gmail.com
Fri May 21 00:09:55 PDT 2010


Estou usando o Gearman para fazer programação distribuída. Para quem
não conhece,
http://gearman.org/index.php

Eu quero fazer uma classe e essa classe ser executa em qualquer "worker".

Para simplificar:

arquivo:Foo.pm

package Foo;

sub new {
  my $class = shift;
  $class = ref $class || $class;
  my $argv = {@_};
  return bless($argv,$class);
}

sub foo {
  my $self = shift;
  $self->{'foo'} = "@_";
}

42;

fim:Foo.pm

Bom, para usar essa classe normalmente fazemos,

arquivo:teste.pl

#!/usr/bin/perl

use strict;
use warnings;
use 5.10.0;
use Foo;

my $o = Foo->new;
say $o->foo(qw(Hello World));

fim:teste.pl

Certo, é isso que eu quero fazer mas o "Foo.pm" vai ser "dinâmico".
Eu quero fazer programação distribuída e executar o "Foo.pm" que no
caso será um Web Scrap. Ou seja eu tenho vários serviços[0] rodando em
servidores no mundo inteiro.
Analisando a arquitetura do Gearman, eu quero enviar uma "classe" para
o meu worker, que no caso vai ser um Web Scrap. Por exemplo, um da
Amazon.


O worker funciona da seguinte maneira,

arquivo:worker.pl

use strict;use warnings;
use Gearman::Worker;
my $worker = Gearman::Worker->new;
$worker->job_servers('xxx.xxx.xxx.xxx:4730');
$worker->register_function( 'load_spider' => \&foo );
$worker->work while 1;

sub foo {
    return(shift->arg);
}

fim:worker.pl


e o cliente,

file:cliente.pl

use strict;use warnings;
use Gearman::Client;

my $client = Gearman::Client->new;
$client->job_servers('xxx.xxx.xxx.xxx:4730');
my $result_ref = $client->do_task( "load_spider" => "Foo" );
print "${$result_ref}\n";

fim:cliente.pl

O resultado será, ao executar o cliente.pl:
$Foo

Até aqui ótimo, só que ao invés de passar simplesmente um arquivo para
uma função, eu quero passar uma classe inteira com o meu Web Scrap.

Um exemplo de como fazer isso localmente:

arquivo:local.pl

use strict;
use warnings;
use 5.10.0;

open my $file,'<','File.pm' or die $!;
my @classe = <$file>;
eval "@classe";
my $o = Foo->new;
say $o->foo(qw(Hello World));

fim:local.pl

Vai imprimir, "Hello World". Eu quero deixar claro que eu *preciso*
fazer as classes serem "dinâmicas", porque eu vou fazer o Web Scrap
local. E quando eu quiser executa-lo eu simplesmente escolho o melhor
servidor, que no caso o Gearman vai fazer isso (escolher o melhor
servidor).


Agora, como fazer isso, como está no local.pl, mandar a "@classe" para
o worker ?

arquivo:worker_carregar_classe.pl

use strict;
use warnings;

use Gearman::Worker;

my $worker = Gearman::Worker->new;
$worker->job_servers('xxx.xxx.xxx.xxx:4730');
$worker->register_function( 'load_spider' => \&foo );
$worker->work while 1;

sub foo {
    eval shift->arg; print $@ if $@;
    my $o = Foo->new();
    return($o->foo("Bar"));
}

fim:worker_carregar_classe.pl


Pronto, o worker vai receber a string que contém o pacote todo em
"shift->arg" o eval vai executar o código que vai carregar a classe
para memória e eu vou poder fazer Foo::new.

O cliente para mandar a string que contém o código pacote, para o
worker_carrega_classe.pl

arquivo:cliente_envia_classe.pl

use strict;
use warnings;
use Gearman::Client;

my $client = Gearman::Client->new;
$client->job_servers('187.22.189.149:4730');

open my $spider, '<', 'Submarino.pm' or die $!;
my @go_spider  = <$spider>;
my $code       = "@go_spider";
my $result_ref = $client->do_task( "load_spider" => "@code");
print "${$result_ref}\n";

fim:cliente_envia_classe.pl

Pronto, isso seria perfeito e deveria funcionar. Mas não funciona,
quando eu tento passar uma string que contém o código de uma classe.
Simplesmente o worker não responde. Ele funciona perfeitamente se você
passa só um argumento como, "hello" como no exemplo. O problema não é
no worker, eu posso retirar a função que contém o eval, e só deixar um
print "Hello World", por exemplo que continua não funcionando. O único
modo de fazer funcionar é retirando o "@code" como parâmetro e
colocando coisas como, "foo","bar". Se eu tento passar o código de uma
classe ele não aceita, nem ao menos chega ao "eval".

Gostaria da ajuda de vocês, para saber uma maneira de fazer o que eu
citei acima.

Obrigado

[]'s




-- 
"If you’ve never written anything thoughtful, then you’ve never had
any difficult, important, or interesting thoughts. That’s the secret:
people who don’t write, are people who don’t think."


More information about the SaoPaulo-pm mailing list