Skip to content

Commit b00f829

Browse files
authored
Merge pull request #7191 from Martchus/clone-job-retry
feat: Retry API calls in `clone-job` like already `openqa-cli` does
2 parents fe66193 + d813ac3 commit b00f829

4 files changed

Lines changed: 44 additions & 19 deletions

File tree

lib/OpenQA/Script/CloneJob.pm

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use Mojo::Base -strict, -signatures;
88
use Cpanel::JSON::XS;
99
use Data::Dump 'pp';
1010
use Exporter 'import';
11-
use OpenQA::Client;
11+
use OpenQA::Command;
1212
use OpenQA::Jobs::Constants;
1313
use Mojo::File 'path';
1414
use Mojo::URL;
@@ -17,6 +17,11 @@ use OpenQA::Script::CloneJobSUSE;
1717
use List::Util 'any';
1818
use HTTP::Status qw(:constants);
1919

20+
package OpenQA::Script::CloneJob::Command {
21+
use Mojo::Base 'OpenQA::Command', -signatures;
22+
sub handle_result ($self, $tx, $orig_tx = undef) { $tx }
23+
}
24+
2025
our @EXPORT = qw(
2126
clone_jobs
2227
clone_job_apply_settings
@@ -89,18 +94,23 @@ sub _handle_txn_error ($tx, $jobid, $ctx) {
8994
_handle_unexpected_return_code($tx) unless $tx->res->code == HTTP_OK;
9095
}
9196

97+
sub _get_with_retry ($url_handler, $url, $jobid, $ctx, $options) {
98+
my $remote = $url_handler->{remote};
99+
my $tx = $url_handler->{command}->retry_tx($remote, $remote->get($url), $options->{retry});
100+
_handle_txn_error($tx, $jobid, $ctx);
101+
return $tx->res->json;
102+
}
103+
92104
sub _get_vars ($jobid, $url_handler, $options) {
93105
my $url = $url_handler->{remote_url}->clone->path("/tests/$jobid/file/vars.json");
94-
_handle_txn_error(my $tx = $url_handler->{remote}->max_redirects(3)->get($url), $jobid, 'vars.json of job');
95-
return $tx->res->json;
106+
return _get_with_retry($url_handler, $url, $jobid, 'vars.json of job', $options);
96107
}
97108

98109
sub clone_job_get_job ($jobid, $url_handler, $options) {
99110
my $url = $url_handler->{remote_url}->clone;
100111
$url->path("jobs/$jobid");
101112
$url->query->merge(check_assets => 1) unless $options->{'ignore-missing-assets'};
102-
_handle_txn_error(my $tx = $url_handler->{remote}->max_redirects(3)->get($url), $jobid, 'job');
103-
my $job = $tx->res->json->{job};
113+
my $job = _get_with_retry($url_handler, $url, $jobid, 'job', $options)->{job};
104114
print STDERR Cpanel::JSON::XS->new->pretty->encode($job) if $options->{verbose};
105115
$job->{vars} = _get_vars($jobid, $url_handler, $options) if $options->{reproduce};
106116
return $job;
@@ -219,7 +229,7 @@ sub split_jobid ($url_string) {
219229
}
220230

221231
sub make_curl_arguments ($options) {
222-
my @args = ('--follow', '--retry', ($options->{retry} // 5), '--retry-connrefused');
232+
my @args = ('--follow', '--retry', $options->{retry}, '--retry-connrefused');
223233
push @args, '--no-progress-meter' unless $options->{'show-progress'};
224234
push @args, '--verbose' if $options->{verbose};
225235
return \@args;
@@ -236,22 +246,30 @@ sub create_url_handler ($options) {
236246
# configure user agent for destination host (usually localhost)
237247
my $local_url = OpenQA::Client::url_from_host($options->{host});
238248
$local_url->path('/api/v1/jobs');
239-
my $local = OpenQA::Client->new(
240-
api => $local_url->host,
249+
my $command = OpenQA::Script::CloneJob::Command->new(
250+
name => 'openqa-clone-job',
241251
apikey => $options->{apikey},
242-
apisecret => $options->{apisecret});
252+
apisecret => $options->{apisecret},
253+
options => $options
254+
);
255+
my $local = $command->client($local_url)->max_redirects(3);
243256
die "API key/secret for '$options->{host}' missing. Check out '$0 --help' for the config file syntax/lookup.\n"
244257
if !$options->{'export-command'} && !($local->apikey && $local->apisecret);
245258

259+
# configure the default for the number of retries and use exponential backoff by default
260+
$options->{retry} //= 5;
261+
$ENV{OPENQA_CLI_RETRY_FACTOR} //= 2;
262+
246263
# configure user agents for the source host (usually a remote host)
247264
my $remote_url = OpenQA::Client::url_from_host($options->{from});
248265
$remote_url->path('/api/v1/jobs');
249266
return {
250267
curl_args => make_curl_arguments($options),
251268
secrets => read_secrets($remote_url->host),
269+
command => $command,
252270
local => $local,
253271
local_url => $local_url,
254-
remote => OpenQA::Client->new(api => $remote_url->host),
272+
remote => $command->client($remote_url)->apikey(undef)->apisecret(undef)->max_redirects(3),
255273
remote_url => $remote_url
256274
};
257275
}
@@ -316,8 +334,10 @@ sub clone_jobs ($jobid, $options) {
316334
clone_job($jobid, $url_handler, $options, my $post_params = {}, my $jobs = {});
317335
for my $counter (1 .. $repeat) {
318336
append_idx_to_test_name($counter, $digits, $post_params) if $repeat > 1;
319-
my $tx = post_jobs($post_params, $url_handler, $options);
320-
handle_tx($tx, $url_handler, $options, $jobs) if $tx;
337+
if (my $tx = post_jobs($post_params, $url_handler, $options)) {
338+
$tx = $url_handler->{command}->retry_tx($url_handler->{local}, $tx, $options->{retry});
339+
handle_tx($tx, $url_handler, $options, $jobs);
340+
}
321341
}
322342
}
323343

@@ -397,7 +417,7 @@ sub post_jobs ($post_params, $url_handler, $options) {
397417
return undef;
398418
}
399419
print STDERR Cpanel::JSON::XS->new->pretty->encode(\%composed_params) if $options->{verbose};
400-
return $local->max_redirects(3)->post($local_url, form => \%composed_params);
420+
return $local->post($local_url, form => \%composed_params);
401421
}
402422

403423
1;

script/openqa-clone-job

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,8 @@ Will create 50 clones of the same job.
166166
167167
=item B<--retry> N
168168
169-
Retries up to N times with exponential backoff on transient errors when
170-
downloading assets. The default number of retries is 5. Can be set to 0 to
171-
disable retrying.
169+
Retries up to N times with exponential backoff on transient download errors. The
170+
default number of retries is 5. Can be set to 0 to disable retrying.
172171
173172
=item B<--show-progress>
174173

t/35-script_clone_job.t

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ package Test::FakeResult {
2727
has json => undef;
2828
} # uncoverable statement
2929

30+
my $command_mock = Test::MockModule->new('OpenQA::Command');
31+
$command_mock->redefine(retry_tx => sub ($self, $client, $tx, $retries) { $tx });
32+
3033
my @argv = (
3134
qw(WORKER_CLASS=local HDD_1=new.qcow2 HDDSIZEGB=40 FOO=value:with:colon),
3235
'WORKER_CLASS:cre:ate+hpc#foo@bar+=-parent'
@@ -64,7 +67,10 @@ subtest 'getting job' => sub {
6467
my $fake_txn = Test::MockObject->new->set_always(res => $fake_res)->set_always(error => undef);
6568
my $fake_ua = Test::MockObject->new->set_always(get => $fake_txn);
6669
$fake_ua->set_always(max_redirects => $fake_ua);
67-
my $url_handler = {remote => $fake_ua, remote_url => Mojo::URL->new('foo')};
70+
my %fake_params = (host => 'host', from => 'from', apikey => 'key', apisecret => 'secret');
71+
my $url_handler = OpenQA::Script::CloneJob::create_url_handler(\%fake_params);
72+
$url_handler->{remote} = $fake_ua;
73+
$url_handler->{remote_url} = Mojo::URL->new('foo');
6874
my $options = {'ignore-missing-assets' => 1, reproduce => 1};
6975
throws_ok { clone_job_get_job(42, $url_handler, $options) } qr/unexpected return code/,
7076
'unexpected return code handled';
@@ -494,7 +500,7 @@ subtest 'invoking curl passing auth headers' => sub {
494500
});
495501
note 'config path: ' . ($ENV{OPENQA_CONFIG} = "$FindBin::Bin/data");
496502

497-
my $args = OpenQA::Script::CloneJob::make_curl_arguments({});
503+
my $args = OpenQA::Script::CloneJob::make_curl_arguments({retry => 5});
498504
my @expected_default_args = qw(--follow --retry 5 --retry-connrefused --no-progress-meter);
499505
is_deeply $args, \@expected_default_args, 'default arguments correct';
500506
my $secrets = OpenQA::Script::CloneJob::read_secrets('testapi');

t/40-openqa-clone-job.t

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ subtest 'usage' => sub {
3939
};
4040

4141
subtest errors => sub {
42-
local @ARGV = (@apiargs, 'http://openqa.local.foo/t1');
42+
local @ARGV = (@apiargs, qw(--retry 0 http://openqa.local.foo/t1));
4343
throws_ok { main::main() } qr/failed to get job '1'/, 'fails with non existing host';
4444
};
4545

0 commit comments

Comments
 (0)