6 use OpenSRF::AppSession;
7 use OpenSRF::Utils::SettingsClient;
8 use OpenILS::Utils::Fieldmapper;
9 $ENV{OSRF_LOG_CLIENT} = 1;
10 #----------------------------------------------------------------
11 # Batch hold (re)targeter
14 # ./hold_targeter.pl /openils/conf/opensrf_core.xml
15 #----------------------------------------------------------------
18 my $osrf_config = '/openils/conf/opensrf_core.xml';
19 my $lockfile = '/tmp/hold_targeter-LOCK';
22 my $retarget_interval;
23 my $soft_retarget_interval;
24 my $next_check_interval;
25 my $recv_timeout = 3600;
26 my $parallel_init_sleep = 0;
28 # how often the server sends a summary reply per backend.
29 my $return_throttle = 500;
33 'osrf-config=s' => \$osrf_config,
34 'lockfile=s' => \$lockfile,
35 'parallel=i' => \$parallel,
36 'verbose' => \$verbose,
37 'parallel-init-sleep=i' => \$parallel_init_sleep,
38 'retarget-interval=s' => \$retarget_interval,
39 'next-check-interval=s' => \$next_check_interval,
40 'soft-retarget-interval=s' => \$soft_retarget_interval,
41 ) || die "\nSee --help for more\n";
49 --osrf-config /openils/conf/opensrf_core.xml \
50 --lockfile /tmp/hold_targeter-LOCK \
56 --osrf-config [/openils/conf/opensrf_core.xml]
59 --lockfile [/tmp/hold_targeter-LOCK]
60 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.
79 --soft-retarget-interval
80 Holds whose previous check time sits between the
81 --soft-retarget-interval and the --retarget-interval are
84 1. The list of potential copies is updated for all matching holds.
85 2. Holds that have a viable target are otherwise left untouched,
86 including their prev_check_time.
87 3. Holds with no viable target are fully retargeted.
90 Specify how long after the current run time the targeter will
91 retarget the currently affected holds. Applying a specific
92 interval is useful when the retarget_interval is shorter than
93 the time between targeter runs.
95 This value is used to determine if an org unit will be closed
96 during the next iteration of the targeter. It overrides the
97 default behavior of calculating the next retarget time from the
101 Retarget holds whose previous check time occured before the
103 Overrides the 'circ.holds.retarget_interval' global_flag value.
114 OpenSRF::System->bootstrap_client(config_file => $osrf_config);
116 IDL => OpenSRF::Utils::SettingsClient->new->config_value("IDL"));
119 my $settings = OpenSRF::Utils::SettingsClient->new;
120 $parallel = $settings->config_value(hold_targeter => 'parallel') || 1;
126 # Hanging all of the parallel requests off the same app session
127 # lets us operate the same as a MultiSession batch with additional
128 # fine-grained controls over the receive timeout and real-time
130 my $ses = OpenSRF::AppSession->create('open-ils.hold-targeter');
133 for my $slot (1..$parallel) {
135 if ($slot > 1 && $parallel_init_sleep) {
136 $verbose && print "Sleeping $parallel_init_sleep ".
137 "seconds before targeter slot=$slot launch\n";
138 sleep $parallel_init_sleep;
141 $verbose && print "Starting targeter slot=$slot\n";
143 my $req = $ses->request(
144 'open-ils.hold-targeter.target', {
146 return_throttle => $return_throttle,
147 parallel_count => $parallel,
148 parallel_slot => $slot,
149 retarget_interval => $retarget_interval,
150 next_check_interval => $next_check_interval,
151 soft_retarget_interval => $soft_retarget_interval
155 $req->{_parallel_slot} = $slot; # for grouping/logging below
161 $ses->queue_wait($recv_timeout); # wait for a response
163 # As a fail-safe, exit if no responses have arrived
164 # within the timeout interval.
165 last if (time - $start) >= $recv_timeout;
167 for my $req (@reqs) {
168 # Pull all responses off the receive queues.
169 while (my $resp = $req->recv(0)) {
170 die $req->failed . "\n" if $req->failed;
172 $verbose && print sprintf(
173 "Targeter [%d] processed %d holds\n",
174 $req->{_parallel_slot},
180 @reqs = grep {!$_->complete} @reqs;
186 die "I seem to be running already. If not remove $lockfile, try again\n"
189 open(LOCK, ">$lockfile") or die "Cannot open lock file: $lockfile : $@\n";
190 print LOCK $$ or die "Cannot write to lock file: $lockfile : $@\n";
193 eval { # Make sure we can delete the lock file.
201 my $minutes = sprintf('%0.2f', (time - $start) / 60.0);
203 $verbose && print "Processing took $minutes minutes.\n";
206 warn "Hold processing exited with error: $@\n" if $@;