]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/support-scripts/hold_targeter_v2.pl
LP#1677416: unbreak use of egOrgSelector by egEditFmRecord
[working/Evergreen.git] / Open-ILS / src / support-scripts / hold_targeter_v2.pl
1 #!/usr/bin/perl
2 use strict; 
3 use warnings;
4 use Getopt::Long;
5 use OpenSRF::System;
6 use OpenSRF::AppSession;
7 use OpenSRF::Utils::SettingsClient;
8 use OpenILS::Utils::Fieldmapper;
9 #----------------------------------------------------------------
10 # Batch hold (re)targeter
11 #
12 # Usage:
13 #   ./hold_targeter.pl /openils/conf/opensrf_core.xml
14 #----------------------------------------------------------------
15
16 my $help;
17 my $osrf_config = '/openils/conf/opensrf_core.xml';
18 my $lockfile = '/tmp/hold_targeter-LOCK';
19 my $parallel = 0;
20 my $verbose = 0;
21 my $target_all;
22 my $skip_viable;
23 my $retarget_interval;
24 my $recv_timeout = 3600;
25 my $parallel_init_sleep = 0;
26
27 # how often the server sends a summary reply per backend.
28 my $return_throttle = 50;
29
30 GetOptions(
31     'osrf-config=s'     => \$osrf_config,
32     'lockfile=s'        => \$lockfile,
33     'parallel=i'        => \$parallel,
34     'verbose'           => \$verbose,
35     'target-all'        => \$target_all,
36     'skip-viable'       => \$skip_viable,
37     'retarget-interval' => \$retarget_interval,
38     'parallel-init-sleep=i' => \$parallel_init_sleep,
39     'help'              => \$help
40 ) || die "\nSee --help for more\n";
41
42 sub help {
43     print <<HELP;
44
45 Batch hold targeter.
46
47 $0 \
48     --osrf-config /openils/conf/opensrf_core.xml \
49     --lockfile /tmp/hold_targeter-LOCK \
50     --parallel 3
51     --verbose
52
53 General Options
54
55     --osrf-config [/openils/conf/opensrf_core.xml] 
56         OpenSRF config file.
57
58     --lockfile [/tmp/hold_targeter-LOCK]
59         Full path to lock file
60
61
62     --verbose
63         Print process counts
64
65 Targeting Options
66
67     --parallel <parallel-process-count>
68         Number of parallel hold processors to run.  This overrides any
69         value found in opensrf.xml
70
71     --parallel-init-sleep <seconds=0>
72         Number of seconds to wait before starting each subsequent
73         parallel targeter instance.  This gives each targeter backend
74         time to run the large targetable holds query before the next
75         kicks off, so they don't all hit the database at once.
76
77         Defaults to no sleep.
78
79     --target-all
80         Target all active holds, regardless of when they were last targeted.
81
82     --skip-viable
83         Avoid modifying holds that currently target viable copies.  In
84         other words, only (re)target holds in a non-viable state.
85
86     --retarget-interval
87         Override the 'circ.holds.retarget_interval' global_flag value. 
88
89 HELP
90
91     exit(0);
92 }
93
94 help() if $help;
95
96 sub init {
97
98     OpenSRF::System->bootstrap_client(config_file => $osrf_config);
99     Fieldmapper->import(
100         IDL => OpenSRF::Utils::SettingsClient->new->config_value("IDL"));
101
102     if (!$parallel) {
103         my $settings = OpenSRF::Utils::SettingsClient->new;
104         $parallel = $settings->config_value(hold_targeter => 'parallel') || 1;
105     }
106 }
107
108 sub run_batches {
109
110     # Hanging all of the parallel requests off the same app session
111     # lets us operate the same as a MultiSession batch with additional
112     # fine-grained controls over the receive timeout and real-time
113     # response handling.
114     my $ses = OpenSRF::AppSession->create('open-ils.hold-targeter');
115
116     my @reqs;
117     for my $slot (1..$parallel) {
118
119         if ($slot > 1 && $parallel_init_sleep) {
120             $verbose && print "Sleeping $parallel_init_sleep ".
121                 "seconds before targeter slot=$slot launch\n";
122             sleep $parallel_init_sleep;
123         }
124
125         $verbose && print "Starting targeter slot=$slot\n";
126
127         my $req = $ses->request(
128             'open-ils.hold-targeter.target', {
129                 return_count    => 1,
130                 return_throttle => $return_throttle,
131                 parallel_count  => $parallel,
132                 parallel_slot   => $slot,
133                 skip_viable     => $skip_viable,
134                 target_all      => $target_all,
135                 retarget_interval => $retarget_interval
136             }
137         );
138
139         $req->{_parallel_slot} = $slot; # for grouping/logging below
140         push(@reqs, $req);
141     }
142
143     while (@reqs) {
144         my $start = time;
145         $ses->queue_wait($recv_timeout); # wait for a response
146
147         # As a fail-safe, exit if no responses have arrived 
148         # within the timeout interval.
149         last if (time - $start) >= $recv_timeout;
150
151         for my $req (@reqs) {
152             # Pull all responses off the receive queues.
153             while (my $resp = $req->recv(0)) {
154                 $verbose && print sprintf(
155                     "Targeter [%d] processed %d holds\n",
156                     $req->{_parallel_slot},
157                     $resp->content
158                 );
159             }
160         }
161
162         @reqs = grep {!$_->complete} @reqs;
163     }
164 }
165
166 # ----
167
168 die "I seem to be running already. If not remove $lockfile, try again\n" 
169     if -e $lockfile;
170
171 open(LOCK, ">$lockfile") or die "Cannot open lock file: $lockfile : $@\n";
172 print LOCK $$ or die "Cannot write to lock file: $lockfile : $@\n";
173 close LOCK;
174    
175 eval { # Make sure we can delete the lock file.
176
177     init();
178
179     my $start = time;
180
181     run_batches();
182
183     my $minutes = sprintf('%0.2f', (time - $start) / 60.0);
184
185     $verbose && print "Processing took $minutes minutes.\n";
186 };
187
188 warn "Hold processing exited with error: $@\n" if $@;
189
190 unlink $lockfile;
191