Project: brw-orch

Build now

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;