Commit | Line | Data |
25e4a0c4 |
1 | package DBIx::Class::Schema::Role::AtQueryInterval; |
2 | |
3 | use Moose::Role; |
4 | use MooseX::AttributeHelpers; |
5 | use DBIx::Class::Schema::Job; |
6 | use DBIx::Class::Schema::QueryInterval; |
7 | use DBIx::Class::Schema::AtQueryInterval; |
8 | |
9 | =head1 NAME |
10 | |
11 | DBIx::Class::Schema::Role::AtQueryInterval; Execute code at query intervals |
12 | |
13 | =head1 SYNOPSIS |
14 | |
15 | The follow will execute the 'do_something' method each and every 10 queries, |
16 | excute a subref each 20 queries, and do both each 30 queries. This first |
17 | example is the long, hard way. |
18 | |
19 | ## ISA DBIx::Class::Schema::Job |
20 | |
21 | my $job1 = $schema->create_job( |
22 | runs => 'do_something', |
23 | ); |
24 | |
25 | my $job2 = $schema->create_job( |
26 | runs => sub {warn 'queries counted'}, |
27 | ); |
28 | |
29 | |
30 | ## ISA DBIx::Class::Schema::QueryInterval |
31 | |
32 | my $interval_10 = $schema->create_query_interval(every => 10); |
33 | my $interval_20 = $schema->create_query_interval(every => 20); |
34 | my $interval_30 = $schema->create_query_interval(every => 30); |
35 | |
36 | |
37 | ## USA DBIx::Class::Schema::AtQueryInterval |
38 | |
39 | my $at1 = $schema->create_at_query_interval( |
40 | interval => $interval_10, job => $job1, |
41 | ); |
42 | |
43 | my $at2 = $schema->create_at_query_interval( |
44 | interval => $interval_20, job => $job2, |
45 | ); |
46 | |
47 | my $at3 = $schema->create_at_query_interval( |
48 | interval => $interval_30, job=>$job1, |
49 | ); |
50 | |
51 | my $at4 = $schema->create_at_query_interval( |
52 | interval => $interval_30, job=>$job2, |
53 | ); |
54 | |
55 | $schema->query_intervals([$1, $at2, $at3, $at4]); |
56 | |
57 | Or you can take the express trip (assuming you are not creating any custom |
58 | Query Intervals, Jobs, etc.) Notice that this method allows jobs to be defined |
59 | as an arrayref to make it easier to defined multiple jobs for a given interval. |
60 | |
61 | In order to perform the needed object instantiation, this class will use the |
62 | methods 'query_interval_class', 'job_class' and 'at_query_interval_class'. |
63 | |
64 | $schema->create_and_add_at_query_intervals( |
65 | {every => 10} => { |
66 | runs => 'do_something', |
67 | }, |
68 | {every => 20} => { |
69 | runs => sub { |
70 | warn 'queries counted'; |
71 | }, |
72 | }, |
73 | {every => 30} => [ |
74 | {runs => 'do_something'}, |
75 | {runs => sub{ |
76 | warn 'queries counted'; |
77 | }}, |
78 | ], |
79 | ); |
80 | |
81 | All the above sit in a DBIx::Class::Schema that consumes the proper roles and |
82 | defines a function which receives three arguments: |
83 | |
84 | sub do_something { |
85 | my ($job, $schema, $at_query_interval) = @_; |
86 | } |
87 | |
88 | =head1 DESCRIPTION |
89 | |
90 | Sometime you'd like to perform certain housekeeping activities at preset query |
91 | intervals. For example, every 100 queries you want to update a reporting table |
92 | that contains denormalized information. This role allows you to assign a |
93 | scalar containing the name of a method in your schema class, an anonymous sub, |
94 | or an arrayref of either to a particular interval. |
95 | |
96 | =head1 ATTRIBUTES |
97 | |
98 | This package defines the following attributes. |
99 | |
100 | =head2 query_interval_class |
101 | |
102 | The default class used to create an interval class from a hash of initializing |
103 | information. |
104 | |
105 | =cut |
106 | |
107 | has 'query_interval_class' => ( |
108 | is=>'ro', |
109 | isa=>'ClassName', |
110 | required=>1, |
111 | default=>'DBIx::Class::Schema::QueryInterval', |
112 | handles=> { |
113 | 'create_query_interval' => 'new', |
114 | }, |
115 | ); |
116 | |
117 | |
118 | =head2 job_class |
119 | |
120 | The default class used to create an job class from a hash of initializing |
121 | information. |
122 | |
123 | =cut |
124 | |
125 | has 'job_class' => ( |
126 | is=>'ro', |
127 | isa=>'ClassName', |
128 | required=>1, |
129 | default=>'DBIx::Class::Schema::Job', |
130 | handles=> { |
131 | 'create_job' => 'new', |
132 | }, |
133 | ); |
134 | |
135 | |
136 | =head2 at_query_interval_class |
137 | |
138 | The default class used to create an job class from a hash of initializing |
139 | information. |
140 | |
141 | =cut |
142 | |
143 | has 'at_query_interval_class' => ( |
144 | is=>'ro', |
145 | isa=>'ClassName', |
146 | required=>1, |
147 | default=>'DBIx::Class::Schema::AtQueryInterval', |
148 | handles=> { |
149 | 'create_at_query_interval' => 'new', |
150 | }, |
151 | ); |
152 | |
153 | |
154 | =head2 at_query_intervals |
155 | |
156 | This is an arrayref of L<DBIx::Class::Schema::AtQueryInterval> objects which |
157 | holds all the jobs that need to be run at the given interval. |
158 | |
159 | =cut |
160 | |
161 | has 'at_query_intervals' => ( |
162 | is=>'rw', |
163 | metaclass => 'Collection::Array', |
164 | auto_deref => 1, |
165 | isa=>'ArrayRef[DBIx::Class::Schema::AtQueryInterval]', |
166 | provides => { |
167 | push => 'add_at_query_interval', |
168 | }, |
169 | ); |
170 | |
171 | |
172 | =head1 METHODS |
173 | |
174 | This module defines the following methods. |
175 | |
176 | =head2 execute_jobs_at_query_interval ($int) |
177 | |
178 | Execute all the jobs which match the given interval |
179 | |
180 | =cut |
181 | |
182 | sub execute_jobs_at_query_interval { |
183 | my ($self, $query_count, @args) = @_; |
184 | my @responses; |
185 | foreach my $at ($self->at_query_intervals) { |
186 | push @responses, |
187 | $at->execute_if_matches($query_count, $self, @args); |
188 | } |
189 | return @responses; |
190 | } |
191 | |
192 | |
193 | =head2 create_and_add_at_query_intervals (%definitions) |
194 | |
195 | Uses the shortcut method shown above to quickly build a plan from a simple perl |
196 | array of hashes. |
197 | |
198 | =cut |
199 | |
200 | sub create_and_add_at_query_intervals { |
201 | my ($self, @definitions) = @_; |
202 | while (@definitions) { |
203 | my $interval = $self->normalize_query_interval(shift @definitions); |
204 | my @jobs = $self->normalize_to_jobs(shift @definitions); |
205 | foreach my $job (@jobs) { |
206 | my $at = $self->create_at_query_interval(interval=>$interval, job=>$job); |
207 | $self->add_at_query_interval($at); |
208 | } |
209 | } |
210 | } |
ae89f08e |
211 | |
25e4a0c4 |
212 | |
213 | =head2 normalize_query_interval ($hash||$obj) |
214 | |
215 | Given an argument, make sure it's a L<DBIx::Class::Schema::QueryInterval>, |
216 | coercing it if neccessary. |
217 | |
218 | =cut |
219 | |
220 | sub normalize_query_interval { |
221 | my ($self, $arg) = @_; |
222 | if(blessed $arg && $arg->isa('DBIx::Class::Schema::QueryInterval')) { |
223 | return $arg; |
224 | } else { |
225 | return $self->create_query_interval($arg); |
226 | } |
227 | } |
228 | |
ae89f08e |
229 | |
25e4a0c4 |
230 | =head2 normalize_to_jobs ($hash||$obj||$arrayref) |
231 | |
232 | Incoming jobs need to be normalized to an array, so that we can handle adding |
233 | multiple jobs per interval. |
234 | |
235 | =cut |
236 | |
237 | sub normalize_to_jobs { |
238 | my ($self, $arg) = @_; |
239 | my @jobs = ref $arg eq 'ARRAY' ? @$arg : ($arg); |
240 | return map {$self->normalize_job($_)} @jobs; |
241 | } |
242 | |
243 | |
244 | =head2 normalize_job ($hash||$obj) |
245 | |
246 | Given an argument, make sure it's a L<DBIx::Class::Schema::Job>, |
247 | coercing it if neccessary. |
248 | |
249 | =cut |
250 | |
251 | sub normalize_job { |
252 | my ($self, $arg) = @_; |
253 | if(blessed $arg && $arg->isa('DBIx::Class::Schema::Job')) { |
254 | return $arg; |
255 | } else { |
256 | return $self->create_job($arg); |
257 | } |
258 | } |
259 | |
260 | |
261 | =head1 AUTHORS |
262 | |
263 | See L<DBIx::Class> for more information regarding authors. |
264 | |
265 | =head1 LICENSE |
266 | |
267 | You may distribute this code under the same terms as Perl itself. |
268 | |
269 | =cut |
270 | |
271 | |
272 | 1; |