File Coverage

blib/lib/Util/Task.pm
Criterion Covered Total %
statement 9 18 50.0
branch n/a
condition n/a
subroutine 3 6 50.0
pod 3 3 100.0
total 15 27 55.5


line stmt bran cond sub pod time code
1              
2             =head1 NAME
3              
4             Util::Task - Abstract class representing a possibly-coalescable task.
5              
6             =head1 SYNOPSIS
7              
8             my $task = Util::Task::SomeSubclass->new();
9             $task->execute();
10              
11             =head1 DESCRIPTION
12              
13             The goal of this class is to allow work to be described in advance of actually doing the work.
14             The first implication of this is that expensive work (usually I/O) is explicitly executed
15             rather than hidden away behind innocent-looking accessor methods.
16              
17             The second implication is that tasks can, in theory, be executed in batch by coalescing
18             atomic operations into single multi-request calls.
19              
20             =cut
21              
22             package Util::Task;
23              
24 1     1   737 use strict;
  1         2  
  1         37  
25 1     1   5 use warnings;
  1         1  
  1         29  
26 1     1   13 use Scalar::Util;
  1         1  
  1         256  
27              
28             our $VERSION = '0.01_1';
29              
30             =head1 METHODS
31              
32             This is an abstract class. Subclasses should override the following methods as appropriate.
33              
34             =cut
35              
36             =pod
37              
38             =head2 $self->execute()
39              
40             Actually run the deferred task and return the result. This is just a convenience method
41             for running a single task; it actually does an C call behind the scenes.
42             Subclasses should not override this unless they have a good reason to; override C
43             instead.
44              
45             =cut
46              
47             sub execute {
48 0     0 1   my ($self) = @_;
49              
50 0           my ($class, $batch_key) = $self->batching_keys;
51 0           my $results = {};
52 0           $class->execute_multi($batch_key, {r => $self}, $results);
53 0           return $results->{r};
54             }
55              
56             =pod
57              
58             =head2 $self->batching_keys()
59              
60             When called in batch via L, the system will attempt to coalesce
61             multiple atomic requests into a single batch request.
62              
63             To do this it needs two pieces of information: the class that will handle the resulting
64             batch request, and a batching key that allows that class to batch its tasks
65             into multiple distinct buckets. Tasks within a given multi-task set that have the
66             same ($class, $task_key) tuple will ultimately be handled by a single call to
67             C<$class->execute_multi>.
68              
69             It is recommended to also include a task key that uniquely identifies the operation
70             that this specific task instance will perform when combined with the $class and $coalesce_key.
71             If included, the system will assume that multiple tasks with the same task key can be handled by a single call.
72             Otherwise, each instance will be handled separately.
73              
74             Overriden versions of this method should return a list of (C<$class>, C<$coalesce_key>, C<$task_key>),
75             where C<$task_key> is optional. The default is to return the class which C<$self> belongs to
76             as the class, 'default' as the batching key (which causes all tasks of this class to be handled
77             in a single batch) and no task key.
78              
79             =cut
80              
81             sub batching_keys {
82 0     0 1   my ($self) = @_;
83 0           return (Scalar::Util::blessed($self), 'default', undef);
84             }
85              
86             =pod
87              
88             =head2 $class->execute_multi($batch_key, $tasks, $results)
89              
90             Given an HASH ref of keys mapped to task instances that belong to classes that returned $class from their
91             coalesce_class method, execute all of the tasks in the most efficient way possible and insert the results
92             into C<$results> (a HASH ref) with the keys matching the corresponding tasks in $tasks.
93             Tasks should be designed to never use exceptions to signal failure.
94              
95             The $batch_key is the class-specific batching key that was returned by the C method
96             on all of the supplied tasks. It's included for convenience though it's also available by explicitly calling
97             C on any of the supplied tasks. In the default implementation of C, this
98             is the string 'default'.
99              
100             This should not be called directly. Instead, use L to create a single
101             task that represents the set of tasks you wish to execute and call C on it. This will
102             allow the task set to be optimized and dispatched to the correct task classes.
103              
104             The request keys passed in should only contain word characters. This is not currently checked, but
105             other keys may conflict with reserved keys used internally and make weird things happen.
106              
107             FIXME: Figure out what should happen if execute_multi *does* C.
108              
109             All subclasses that are returned by some implementation of C must override this.
110             The default implementation just dies.
111              
112             =cut
113              
114             sub execute_multi {
115 0     0 1   my ($class, $tasks) = @_;
116 0           die "No execute_multi() implementation for $class";
117             }
118              
119             1;