Configuration
sparrowdo:
no_sudo: true
no_index_update: false
bootstrap: false
format: default
repo: https://sparrowhub.io/repo
disabled: false
keep_builds: 100
allow_manual_run: true
Configuration
sparrowdo:
no_sudo: true
no_index_update: false
bootstrap: false
format: default
repo: https://sparrowhub.io/repo
disabled: false
keep_builds: 100
allow_manual_run: true
Job
#!raku
use Sparky::JobApi;
use Ecosystem;
class Pipeline
does Sparky::JobApi::Role
{
method base-dir {
"{%*ENV<HOME>}/.brownie"
}
method stage-main {
#bash "rm -rf {self.base-dir}/agents/*", %(
#description => "remove old registered agents"
#);
my @d;
my $eco = Ecosystem.new;
say "Testing top 1000 modules on the Raku Ecosystem River:";
for $eco.river.sort(-*.value.elems).map(*.key).head(1000) -> $d {
push @d, $d;
#say $d;
}
"list.txt".IO.spurt(@d.join("\n"));
my $me = Sparky::JobApi.new(:mine);
$me.put-file("list.txt","list.txt");
my @eff-list = @d;
my $j = 0;
my %seen;
my $scnt = 0;
my %handled-by-agent;
while (True) {
my @_list = [];
for @eff-list -> $l {
next if %seen{$l}; # module is already send to some agent
if "{self.base-dir}/versions/2025.10/{$l}.OK".IO ~~ :f ||
"{self.base-dir}/versions/2025.10/{$l}.FAIL".IO ~~ :f {
# module is already completed
next;
}
push @_list, $l;
}
@eff-list = @_list;
#@eff-list.=pick(@eff-list);
my $cnt = 0;
for @d -> $l {
if "{self.base-dir}/versions/2025.10/{$l}.OK".IO ~~ :f ||
"{self.base-dir}/versions/2025.10/{$l}.FAIL".IO ~~ :f {
$cnt++;
}
}
if $cnt == @d.elems {
last;
} else {
say "$cnt tests out of {@d.elems} finished"
}
my $chunk = 0;
my @agents;
say "look for available agents ...";
@agents = [];
if "{self.base-dir}/agents".IO ~~ :d {
for dir("{self.base-dir}/agents") -> $ag {
my $age = Int(now - $ag.created.DateTime);
if $age < 900 { # only use agents with 15 minutes ago at least heartbeat
say "agent {$ag.basename} heartbeat OK - [$age] seconds";
push @agents, $ag.basename;
%handled-by-agent{$ag.basename} = [] unless %handled-by-agent{$ag.basename};
} else {
say "remove agent {$ag.basename} from rotation, BAD heartbit - $age seconds";
if %handled-by-agent{$ag.basename} {
my $c = 0;
for %handled-by-agent{$ag.basename}<> -> $m {
next if "{self.base-dir}/versions/2025.10/{$m}.OK".IO ~~ :f;
next if "{self.base-dir}/versions/2025.10/{$m}.FAIL".IO ~~ :f;
%seen{$m}:delete;
say "send $m back to orch queue so that other can pick it up";
$c++;
}
%handled-by-agent{$ag.basename} = [];
say "{$cnt} modules returned back to orch queue";
}
say "remove agent {$ag.basename} from registry";
$ag.unlink;
}
};
}
say "{@agents.elems} online agents found";
if @agents.elems > 0 && @eff-list.elems > 0 {
if @eff-list.elems < @agents.elems {
$chunk = 1;
@agents = @agents[0 .. @eff-list.elems -1];
} else {
$chunk = Int(@eff-list.elems/@agents.elems);
$chunk = 5 if $chunk > 5;
}
my $a = 0;
say "agents cnt: {@agents.elems}";
say "chunk: $chunk";
for 1 .. @agents.elems -> $i {
my @slice = @eff-list[$a .. $a + $chunk - 1];
@slice = @slice.sort;
say "push job to agent {@agents[$i-1]}";
my $agents-queue = Sparky::JobApi.new(
:project<browny.queue>,
:job-id(@agents[$i-1]),
);
$agents-queue.put-stash(
%(
version => "2025.10",
agent => @agents[$i-1],
modules => @slice,
run-id => time,
)
);
say "slice: {@slice.raku}";
$a = $a + $chunk;
say "...";
for @slice -> $s {
%seen{$s} = True;
$scnt++;
push %handled-by-agent{@agents[$i-1]}, $s;
}
}
}
say "///";
say "[{$scnt}] tests out of [{@d.elems}] sent for execution";
say "///";
say "<<< sleep for 30 seconds";
sleep(30);
$j++;
last if $j > 10000;
}
say "done";
say "summary";
my $summary = "";
for @d -> $m {
my $status = "?";
$status = "OK" if "{self.base-dir}/versions/2025.10/{$m}.OK".IO ~~ :f;
$status = "FAIL" if "{self.base-dir}/versions/2025.10/{$m}.FAIL".IO ~~ :f;
say "$m ... \t $status";
$summary ~= "$m ... \t $status\n";
}
"summary.txt".IO.spurt($summary);
for @d -> $m {
if "{self.base-dir}/versions/2025.10/{$m}.log".IO ~~ :f {
$me.put-file("{self.base-dir}/versions/2025.10/{$m}.log","$m.log");
}
}
$me.put-file("summary.txt","summary.txt");
}
}
Pipeline.new.run;