]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/support-scripts/action_trigger_runner.pl
Stamping upgrade for relaxing rank_ou sorting
[working/Evergreen.git] / Open-ILS / src / support-scripts / action_trigger_runner.pl
1 #!/usr/bin/perl
2 # ---------------------------------------------------------------
3 # Copyright (C) 2009 Equinox Software, Inc
4 # Author: Bill Erickson <erickson@esilibrary.com>
5 #
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
10
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 # ---------------------------------------------------------------
16 use strict;
17 use warnings;
18 use Getopt::Long;
19 use OpenSRF::System;
20 use OpenSRF::AppSession;
21 use OpenSRF::Utils::JSON;
22 use OpenSRF::Utils::Logger qw/$logger/;
23 use OpenSRF::EX qw(:try);
24 use OpenILS::Utils::Fieldmapper;
25 my $req_timeout = 10800;
26
27 # DEFAULT values
28
29 my $opt_lockfile      = '/tmp/action-trigger-LOCK';
30 my $opt_osrf_config   = '/openils/conf/opensrf_core.xml';
31 my $opt_custom_filter = '/openils/conf/action_trigger_filters.json';
32 my $opt_max_sleep     = 3600;  # default to 1 hour
33 my $opt_run_pending   = 0;
34 my $opt_debug_stdout  = 0;
35 my $opt_help          = 0;
36 my $opt_verbose;
37 my $opt_hooks;
38 my $opt_process_hooks = 0;
39 my $opt_granularity   = undef;
40 my $opt_gran_only     = undef;
41
42 (-f $opt_custom_filter) or undef($opt_custom_filter);   # discard default if no file exists
43
44 GetOptions(
45     'max-sleep'        => \$opt_max_sleep,
46     'osrf-config=s'    => \$opt_osrf_config,
47     'run-pending'      => \$opt_run_pending,
48     'hooks=s'          => \$opt_hooks,
49     'granularity=s'    => \$opt_granularity,
50     'granularity-only' => \$opt_gran_only,
51     'process-hooks'    => \$opt_process_hooks,
52     'debug-stdout'     => \$opt_debug_stdout,
53     'custom-filters=s' => \$opt_custom_filter,
54     'lock-file=s'      => \$opt_lockfile,
55     'verbose'          => \$opt_verbose,
56     'help'             => \$opt_help,
57 );
58
59 my $max_sleep = $opt_max_sleep;
60
61 #XXX need to figure out why this is required...
62 $opt_gran_only = $opt_granularity ? 1 : 0;
63
64 $opt_lockfile .= '.' . $opt_granularity if ($opt_granularity && $opt_gran_only);
65
66 # typical passive hook filters
67 my $hook_handlers = {
68
69     # default overdue circulations
70     'checkout.due' => {
71         context_org => 'circ_lib',
72         filter => {
73             checkin_time => undef, 
74             '-or' => [
75                 {stop_fines => ['MAXFINES', 'LONGOVERDUE']}, 
76                 {stop_fines => undef}
77             ]
78         }
79     }
80 };
81
82 if ($opt_custom_filter) {
83     open FILTERS, $opt_custom_filter or die "Cannot read custom filters at $opt_custom_filter";
84     $hook_handlers = OpenSRF::Utils::JSON->JSON2perl(join('',(<FILTERS>)));
85     close FILTERS;
86 }
87
88 sub help {
89     print <<HELP;
90
91 $0 : Create and process action/trigger events
92
93     --osrf-config=<config_file>
94         OpenSRF core config file.  Defaults to:
95             /openils/conf/opensrf_core.xml
96
97     --custom-filters=<filter_file>
98         File containing a JSON Object which describes any hooks that should
99         use a user-defined filter to find their target objects.  Defaults to:
100             /openils/conf/action_trigger_filters.json
101
102     --run-pending
103         Run pending events
104
105     --process-hooks
106         Create hook events
107
108     --max-sleep=<seconds>
109         When in process-hooks mode, wait up to <seconds> for the lock file to
110         go away.  Defaults to 3600 (1 hour).
111
112     --hooks=hook1[,hook2,hook3,...]
113         Define which hooks to create events for.  If none are defined,
114         it defaults to the list of hooks defined in the --custom-filters option.
115
116     --granularity=<label>
117         Run events with {label} granularity setting, or no granularity setting
118
119     --granularity-only
120         Used in combination with --granularity, prevents the running of events with no granularity setting
121
122     --debug-stdout
123         Print server responses to stdout (as JSON) for debugging
124
125     --lock-file=<file_name>
126         Lock file
127
128     --help
129         Show this help
130
131     Examples:
132
133         # To run all pending events.  This is what you tell CRON to run at
134         # regular intervals
135         perl $0 --osrf-config /openils/conf/opensrf_core.xml --run-pending
136
137         # To batch create all "checkout.due" events
138         perl $0 --osrf-config /openils/conf/opensrf_core.xml --hooks checkout.due
139
140 HELP
141 }
142
143
144 # create events for the specified hooks using the configured filters and context orgs
145 sub process_hooks {
146     $opt_verbose and print "process_hooks: " . ($opt_process_hooks ? '(start)' : 'SKIPPING') . "\n";
147     return unless $opt_process_hooks;
148
149     my @hooks = ($opt_hooks) ? split(',', $opt_hooks) : keys(%$hook_handlers);
150     my $ses = OpenSRF::AppSession->create('open-ils.trigger');
151
152     for my $hook (@hooks) {
153         my $config = $$hook_handlers{$hook};
154         $opt_verbose and print "process_hooks: $hook " . ($config ? ($opt_granularity || '') : ' NO HANDLER') . "\n";
155         $config or next;
156
157         my $method = 'open-ils.trigger.passive.event.autocreate.batch';
158         $method =~ s/passive/active/ if $config->{active};
159         
160         my $req = $ses->request($method, $hook, $config->{context_org}, $config->{filter}, $opt_granularity);
161
162         my $debug_hook = "'$hook' and filter ".OpenSRF::Utils::JSON->perl2JSON($config->{filter});
163         $logger->info("at_runner: creating events for $debug_hook");
164
165         my @event_ids;
166         while (my $resp = $req->recv(timeout => $req_timeout)) {
167             push(@event_ids, $resp->content);
168         }
169
170         if(@event_ids) {
171             $logger->info("at_runner: created ".scalar(@event_ids)." events for $debug_hook");
172         } elsif($req->complete) {
173             $logger->info("at_runner: no events to create for $debug_hook");
174         } else {
175             $logger->warn("at_runner: timeout occurred during event creation for $debug_hook");
176         }
177     }
178 }
179
180 sub run_pending {
181     $opt_verbose and print "run_pending: " .
182         ($opt_run_pending ?
183             ($opt_granularity ?
184                 ( $opt_granularity . (
185                     $opt_gran_only ?
186                         ' ONLY' : 
187                         ' and NON-GRANULAR'
188                     )
189                 ) :
190                 'NON-GRANULAR'
191             ) :
192             'SKIPPING'
193         ) . "\n";
194
195     return unless $opt_run_pending;
196     my $ses = OpenSRF::AppSession->create('open-ils.trigger');
197     my $req = $ses->request('open-ils.trigger.event.run_all_pending' => $opt_granularity => $opt_gran_only);
198
199     my $check_lockfile = 1;
200     while (my $resp = $req->recv(timeout => $req_timeout)) {
201         if ($check_lockfile && -e $opt_lockfile) {
202             open LF, $opt_lockfile;
203             my $contents = <LF>;
204             close LF;
205             unlink $opt_lockfile if ($contents == $$);
206             $check_lockfile = 0;
207         }
208         $opt_debug_stdout and print OpenSRF::Utils::JSON->perl2JSON($resp->content) . "\n";
209     }
210 }
211
212 help() and exit if $opt_help;
213 help() and exit unless ($opt_run_pending or $opt_process_hooks);
214
215 # check the lockfile
216 if (-e $opt_lockfile) {
217     die "I'm already running with lockfile $opt_lockfile\n" unless ($opt_process_hooks or $opt_granularity);
218     # sleeping loop if we're in --process-hooks mode
219     while ($max_sleep >= 0 && sleep(1)) {
220         last unless ( -e $opt_lockfile ); 
221         $max_sleep--;
222     }
223 }
224
225 # there's a tiny race condition here ... oh well
226 die "Someone else has been holding the lockfile $opt_lockfile for at least $opt_max_sleep. Giving up now ...\n" if (-e $opt_lockfile);
227
228 # set the lockfile
229 open(F, ">$opt_lockfile") or die "Unable to open lockfile $opt_lockfile for writing\n";
230 print F $$;
231 close F;
232
233 try {
234         OpenSRF::System->bootstrap_client(config_file => $opt_osrf_config);
235         Fieldmapper->import(IDL => OpenSRF::Utils::SettingsClient->new->config_value("IDL"));
236     process_hooks();
237     run_pending();
238 } otherwise {
239     my $e = shift;
240     warn "$e\n";
241 };
242
243 if (-e $opt_lockfile) {
244     open LF, $opt_lockfile;
245     my $contents = <LF>;
246     close LF;
247     unlink $opt_lockfile if ($contents == $$);
248 }