6 use OpenSRF::AppSession;
7 use OpenSRF::Utils::SettingsClient;
8 use OpenILS::Utils::Fieldmapper;
9 #----------------------------------------------------------------
10 # Batch hold (re)targeter
13 # ./hold_targeter.pl /openils/conf/opensrf_core.xml
14 #----------------------------------------------------------------
17 my $osrf_config = '/openils/conf/opensrf_core.xml';
18 my $lockfile = '/tmp/hold_targeter-LOCK';
23 my $retarget_interval;
24 my $recv_timeout = 3600;
25 my $parallel_init_sleep = 0;
27 # how often the server sends a summary reply per backend.
28 my $return_throttle = 50;
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=s' => \$retarget_interval,
38 'parallel-init-sleep=i' => \$parallel_init_sleep,
40 ) || die "\nSee --help for more\n";
48 --osrf-config /openils/conf/opensrf_core.xml \
49 --lockfile /tmp/hold_targeter-LOCK \
55 --osrf-config [/openils/conf/opensrf_core.xml]
58 --lockfile [/tmp/hold_targeter-LOCK]
59 Full path to lock file
67 --parallel <parallel-process-count>
68 Number of parallel hold processors to run. This overrides any
69 value found in opensrf.xml
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.
80 Target all active holds, regardless of when they were last targeted.
83 Avoid modifying holds that currently target viable copies. In
84 other words, only (re)target holds in a non-viable state.
87 Override the 'circ.holds.retarget_interval' global_flag value.
98 OpenSRF::System->bootstrap_client(config_file => $osrf_config);
100 IDL => OpenSRF::Utils::SettingsClient->new->config_value("IDL"));
103 my $settings = OpenSRF::Utils::SettingsClient->new;
104 $parallel = $settings->config_value(hold_targeter => 'parallel') || 1;
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
114 my $ses = OpenSRF::AppSession->create('open-ils.hold-targeter');
117 for my $slot (1..$parallel) {
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;
125 $verbose && print "Starting targeter slot=$slot\n";
127 my $req = $ses->request(
128 'open-ils.hold-targeter.target', {
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
139 $req->{_parallel_slot} = $slot; # for grouping/logging below
145 $ses->queue_wait($recv_timeout); # wait for a response
147 # As a fail-safe, exit if no responses have arrived
148 # within the timeout interval.
149 last if (time - $start) >= $recv_timeout;
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},
162 @reqs = grep {!$_->complete} @reqs;
168 die "I seem to be running already. If not remove $lockfile, try again\n"
171 open(LOCK, ">$lockfile") or die "Cannot open lock file: $lockfile : $@\n";
172 print LOCK $$ or die "Cannot write to lock file: $lockfile : $@\n";
175 eval { # Make sure we can delete the lock file.
183 my $minutes = sprintf('%0.2f', (time - $start) / 60.0);
185 $verbose && print "Processing took $minutes minutes.\n";
188 warn "Hold processing exited with error: $@\n" if $@;