2 # ---------------------------------------------------------------
3 # Copyright (C) 2009 Equinox Software, Inc
4 # Author: Bill Erickson <erickson@esilibrary.com>
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.
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 # ---------------------------------------------------------------
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;
29 my $opt_lockfile = '/tmp/action-trigger-LOCK';
30 my $opt_osrf_config = '@sysconfdir@/opensrf_core.xml';
31 my $opt_custom_filter = '@sysconfdir@/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;
38 my $opt_process_hooks = 0;
39 my $opt_granularity = undef;
40 my $opt_gran_only = undef;
42 (-f $opt_custom_filter) or undef($opt_custom_filter); # discard default if no file exists
45 'max-sleep=i' => \$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,
59 my $max_sleep = $opt_max_sleep;
61 #XXX need to figure out why this is required...
62 $opt_gran_only = $opt_granularity ? 1 : 0;
64 $opt_lockfile .= '.' . $opt_granularity if ($opt_granularity && $opt_gran_only);
66 # typical passive hook filters
69 # default overdue circulations
71 context_org => 'circ_lib',
73 checkin_time => undef,
75 {stop_fines => ['MAXFINES']},
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>)));
91 $0 : Create and process action/trigger events
93 --osrf-config=<config_file>
94 OpenSRF core config file. Defaults to:
95 @sysconfdir@/opensrf_core.xml
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 @sysconfdir@/action_trigger_filters.json
103 Run pending events to send emails or take other actions as specified
104 by the reactor in the event definition.
109 --max-sleep=<seconds>
110 When in process-hooks mode, wait up to <seconds> for the lock file to
111 go away. Defaults to 3600 (1 hour).
113 --hooks=hook1[,hook2,hook3,...]
114 Define which hooks to create events for. If none are defined,
115 it defaults to the list of hooks defined in the --custom-filters option.
116 Requires --process-hooks
118 --granularity=<label>
119 Limit creating events and running pending events to those only
120 with <label> granularity setting.
123 Print server responses to stdout (as JSON) for debugging
125 --lock-file=<file_name>
129 Show details of script processing.
136 # To run all pending events that have no granularity set. This is what
137 # you tell CRON to run at regular intervals
138 perl $0 --run-pending
140 # To batch create all "checkout.due" events
141 perl $0 --hooks=checkout.due --process-hooks
143 # To batch create all events for a specific granularity and to send notices for all pending
144 # events with that same granularity.
145 perl $0 --run-pending --granularity=Hourly --process-hooks
151 # create events for the specified hooks using the configured filters and context orgs
153 $opt_verbose and print "process_hooks: " . ($opt_process_hooks ? '(start)' : 'SKIPPING') . "\n";
154 return unless $opt_process_hooks;
156 my @hooks = ($opt_hooks) ? split(',', $opt_hooks) : keys(%$hook_handlers);
157 my $ses = OpenSRF::AppSession->create('open-ils.trigger');
159 for my $hook (@hooks) {
160 my $config = $$hook_handlers{$hook};
161 $opt_verbose and print "process_hooks: $hook " . ($config ? ($opt_granularity || '') : ' NO HANDLER') . "\n";
164 my $method = 'open-ils.trigger.passive.event.autocreate.batch';
165 $method =~ s/passive/active/ if $config->{active};
167 my $req = $ses->request($method, $hook, $config->{context_org}, $config->{filter}, $opt_granularity);
169 my $debug_hook = "'$hook' and filter ".OpenSRF::Utils::JSON->perl2JSON($config->{filter});
170 $logger->info("at_runner: creating events for $debug_hook");
173 while (my $resp = $req->recv(timeout => $req_timeout)) {
174 push(@event_ids, $resp->content);
178 $logger->info("at_runner: created ".scalar(@event_ids)." events for $debug_hook");
179 } elsif($req->complete) {
180 $logger->info("at_runner: no events to create for $debug_hook");
182 $logger->warn("at_runner: timeout occurred during event creation for $debug_hook");
188 $opt_verbose and print "run_pending: " .
191 ( $opt_granularity . (
202 return unless $opt_run_pending;
203 my $ses = OpenSRF::AppSession->create('open-ils.trigger');
204 my $req = $ses->request('open-ils.trigger.event.run_all_pending' => $opt_granularity => $opt_gran_only);
206 my $check_lockfile = 1;
207 while (my $resp = $req->recv(timeout => $req_timeout)) {
208 if ($check_lockfile && -e $opt_lockfile) {
209 open LF, $opt_lockfile;
212 unlink $opt_lockfile if ($contents == $$);
215 $opt_debug_stdout and print OpenSRF::Utils::JSON->perl2JSON($resp->content) . "\n";
219 help() and exit if $opt_help;
220 help() and exit unless ($opt_run_pending or $opt_process_hooks);
223 if (-e $opt_lockfile) {
224 die "I'm already running with lockfile $opt_lockfile\n" unless ($opt_process_hooks or $opt_granularity);
225 # sleeping loop if we're in --process-hooks mode
226 while ($max_sleep >= 0 && sleep(1)) {
227 last unless ( -e $opt_lockfile );
232 # there's a tiny race condition here ... oh well
233 die "Someone else has been holding the lockfile $opt_lockfile for at least $opt_max_sleep. Giving up now ...\n" if (-e $opt_lockfile);
236 open(F, ">$opt_lockfile") or die "Unable to open lockfile $opt_lockfile for writing\n";
241 OpenSRF::System->bootstrap_client(config_file => $opt_osrf_config);
242 Fieldmapper->import(IDL => OpenSRF::Utils::SettingsClient->new->config_value("IDL"));
250 if (-e $opt_lockfile) {
251 open LF, $opt_lockfile;
254 unlink $opt_lockfile if ($contents == $$);