Suppose you need to perform a task. That task may take a lot of memory or a lot of time. For whatever reason it's too expensive right now. You need to do it later, in another process, when and where you have resources available.
(In context, today this was "extract data from a spreadsheet uploaded to a web application and create models, then save them to the database".)
You've probably done this before. Many of you have probably come up with a solution to this before. That's fine; I'm writing here to people new to Perl or other dynamic languages who haven't yet seen the joys of dynamic dispatch.
Suppose you have a generic Task
class which somehow knows how
to serialize its arguments to a persistent data storage mechanism, such as a
database or a queue of some kind. If all of the asynchronous tasks you want to
run conform to a simple interface, you can model any task you want to run with
four attributes:
package Task {
use Moose;
use Class::Load 'load_class';
has [qw( class_name method_name )], is => 'ro', required => 1;
has [qw( constructor_args method_args )], is => 'ro', default => sub { {} };
sub execute_task {
my $self = shift;
my $class = $self->class_name;
load_class( $class );
my $entity = $class_name->new( $self->constructor_args );
my $method = $self->method_name;
$entity->$method( $self->method_args );
}
}
Thus, to create a task which knows how to import ice cream flavors from a spreadsheet, you might write:
my $task = Task->new(
class_name => 'IceCream::Flavor',
method_name => 'import_from_spreadsheet',
method_args => { filename => $some_filename },
);
Then save or queue the task as necessary. When you want to run the task,
dequeue or instantiate it from storage, then run its
execute_task()
method.
It's not much code. You could have invented it. (Most of the programmers I know have already invented something like this.) Yet for people new to dynamic languages and dynamic dispatch, this is one of the cases where the performance penalty for dynamic dispatch is worth it, simply because of all of the code I didn't have to write.
Leave a comment