Job Scheduling com vRaptor3 e Spring

terça-feira, 17/11/2009

Este artigo tem como objetivo mostrar um caminho simples para fazer job scheduling no vRaptor3 quando o Spring for o seu container IoC sem que seja necessário o uso de XML para configuração.

Versões utilizadas:

  • vRaptor 3.0.2
  • Spring 3.0.0.RC2

O Task Scheduler

O Spring já vem com suporte a task scheduling/executing, ele precisa apenas que uma implementação de org.springframework.scheduling.TaskScheduler esteja disponível no escopo de aplicação (singleton no Spring). Para isso precisamos implementar um ComponentFactory:

@Component
@ApplicationScoped
public class TaskSchedulerFactory implements ComponentFactory<TaskScheduler> {

private ThreadPoolTaskScheduler scheduler;

@PostConstruct
public void create() {
    scheduler = new ThreadPoolTaskScheduler();
    scheduler.initialize();
}

public TaskScheduler getInstance() {
    return scheduler;
}

@PreDestroy
public void destroy() {
    scheduler.destroy();
}

}

Neste exemplo utilizaremos o ThreadPoolTaskScheduler como implementação para o TaskScheduler, porém várias outras classes vem com o Spring e podem ser usadas da mesma maneira (documentação).

As Tasks/Jobs

Vamos criar interfaces para nossas tasks.

public interface Task extends Runnable {
    void schedule(TaskScheduler scheduler);
}

public interface ApplicationTask extends Task {
}

public interface RequestTask extends Task {
}

Registrando tasks em escopo de application

Para registrar esse tipo de task, precisaremos de um componente em escopo de application:

@Component
@ApplicationScoped
public class MyFirstApplicationTask implements ApplicationTask {
    public MyFirstApplicationTask(TaskScheduler scheduler) { //Aqui você poderá receber componentes que não estejam em escopo de request ou session
        ...
        this.schedule(scheduler);
    }
    public void schedule(TaskScheduler scheduler) {
        scheduler.schedule(this, new CronTrigger("0 0 23 * * *")); //Neste caso, a task rodará sempre às 23h0min0s
    }
}

Registrando tasks em escopo de request

Para registrar esse tipo de task, basta receber o scheduler no construtor do seu Resource e registrar a task no método adequado.

@Component
@RequestScoped
public class MyFirstRequestTask implements RequestTask {
    public MyFirstApplicationTask() { //Aqui você poderá receber qualquer componente que precisar
        ...
    }
    public void schedule(TaskScheduler schedule) {
        Calendar now = GregorianCalendar.getInstance();
        now.add(Calendar.MINUTE,5);
        scheduler.schedule(this, now.getTime()); //Neste caso, a task rodará apenas uma vez, 5 min depois da execução deste método
    }
}
@Resource
public class MyResource {
    private MyFirstRequestTask task;
    private TaskScheduler scheduler;
    public MyResource(MyFirstRequestTask task, TaskScheduler scheduler) {
        this.task = task;
        this.scheduler = scheduler;
    }
    ...
    public void taskInit() {
        task.schedule(scheduler);
    }
    ...
}

Observações

Criamos 3 interfaces, pois deste modo ficará mais fácil injetar diferentes tipos de tasks no construtor, por exemplo podemos receber todas as tasks em escopo de request dentro de um resource assim:

@Resource
public class MyResource {
    private List<RequestTask> tasks;
    private TaskScheduler scheduler;
    public MyResource(List<RequestTask> tasks, TaskScheduler scheduler) {
        this.tasks = tasks;
        this.scheduler = scheduler;
    }
    ...
    public void tasksInit() {
        for (RequestTask task : tasks) {
            task.schedule(scheduler);
        }
    }
    ...
}

O escopo Prototype

O Spring possui um escopo chamado prototype que define que o componente terá uma nova instância sempre que for requisitada, este escopo ainda não existe no vRaptor3 mas será implementado em breve. Este escopo servirá para definir compenentes utilizados por tasks em escopo de application que naturalmente não são singletons, como DAO’s.

Você não poderá receber a Session no construtor do seu DAO prototyped pois geralmente ela está em escopo de request, e o vRaptor ainda não possui suporte às scoped-proxies do Spring. Então precisará fazer assim:

@Component
@PrototypeScoped
public class MyPrototypedDAO extends ... implements ... {

    private Session session;

    public MyPrototypedDAO(SessionFactory sessionFactory) {
        this.session = sessionFactory.openSession();
    }

    ...
}

Deste modo, será criado uma instância do seu DAO para cada requisição de instância (lê-se: sempre que você receber uma instância pelo construtor, será uma nova), assim como uma Session separada.

Tudo o que você precisará quando o universo acabar é de uma toalha

terça-feira, 30/09/2008

“A toalha é um dos objetos mais úteis para um mochileiro interestelar. Em parte devido a seu valor prático: você pode usar a toalha como agasalho quando atravessar as frias luas de Beta de Jagla; pode deitar-se sobre ela nas reluzentes praias de areia marmórea de Santragino V, respirando os inebriantes vapores marítimos; você pode dormir debaixo dela sob as estrelas que brilham avermelhadas no mundo desértico de Kakrafoon; pode usa-la como vela para descer numa minijangada as águas lentas e pesadas do rio Moth; pode umedecê-la e utilizá-la para lutar em um combate corpo a corpo; enrolá-la em torno da cabeça para proteger-se de emanações tóxicas ou para evitar o olhar da Terrível Besta Voraz de Traal (animal estonteantemente burro, que acha que, se você não pode vê-lo, ele também não pode ver você – estúpido feito uma anta, mas muito, muito voraz); você pode agitar a toalha em situações de emergência para pedir socorro; e naturalmente pode usá-la para enxugar-se com ela se ainda estiver razoalvemente limpa. Porém o mais importante é o imenso valor psicológico da toalha. Por algum motivo, quando um estrito (isto é, um não-mochileiro) descobre que um mochileiro tem uma toalha, ele automaticamente conclui que ele tem também escova de dentes, esponja, sabonete, lata de biscoitos, repelente, capa de chuva, traje espacial, etc., etc.
Além disso, o estrito terá prazer em emprestar ao mochileiro qualquer um desses objetos, ou muito outros, que o mochileiro por acaso tenha “acidentalmente perdido”. O que o estrito vai pensar é que, se um sujeito é capaz de rodar toda a Galáxia, acampar, pedir carona, lutar contra terríveis obstáculos, dar a volta por cima e ainda assim saber onde está a sua toalha, esse sujeito claramente merece respeito.” (Douglas Adams)