Skip to content

Commit 0942341

Browse files
committed
Apps now relay stdout/stderr and status to the app service.
Add query_task_details to retrieve this data. Stdout/stderr are retrieved via REST URLs.
1 parent 6bbd9bb commit 0942341

File tree

9 files changed

+417
-13
lines changed

9 files changed

+417
-13
lines changed

AppService.spec

+9
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,15 @@ module AppService
6767

6868
funcdef query_task_summary() returns (mapping<task_status status, int count> status);
6969

70+
typedef structure {
71+
string stdout_url;
72+
string stderr_url;
73+
int pid;
74+
string hostname;
75+
int exitcode;
76+
} TaskDetails;
77+
funcdef query_task_details(task_id) returns (TaskDetails details);
78+
7079
funcdef enumerate_tasks(int offset, int count)
7180
returns (list<Task>);
7281
};

Makefile

-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ compile-typespec: Makefile
6161
touch lib/biokbase/$(SERVICE_NAME_PY)/__init__.py
6262
mkdir -p lib/javascript/$(SERVICE_NAME)
6363
compile_typespec \
64-
--psgi $(SERVICE_PSGI_FILE) \
6564
--impl Bio::KBase::$(SERVICE_NAME)::%sImpl \
6665
--service Bio::KBase::$(SERVICE_NAME)::Service \
6766
--client Bio::KBase::$(SERVICE_NAME)::Client \

deploy.cfg

+26
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,19 @@
44
awe-server = http://redwood.mcs.anl.gov:7080
55
shock-server = http://redwood.mcs.anl.gov:7078
66
app-directory = app_specs
7+
8+
;
9+
; Directory into which task status (stdout/err etc) are written
10+
;
11+
12+
; task-status-dir =
13+
14+
;
15+
; AWE client group to submit jobs iwth
16+
;
17+
; awe-clientgroup =
18+
19+
720
; service-url =
821
; service-host =
922
; service-port =
@@ -13,6 +26,19 @@ app-directory = app_specs
1326
awe-server = http://redwood.mcs.anl.gov:7080
1427
shock-server = http://redwood.mcs.anl.gov:7078
1528
app-directory = app_specs
29+
30+
;
31+
; Directory into which task status (stdout/err etc) are written
32+
;
33+
34+
; task-status-dir =
35+
36+
;
37+
; AWE client group to submit jobs iwth
38+
;
39+
; awe-clientgroup =
40+
41+
1642
; service-url =
1743
; service-host =
1844
; service-port =

lib/AppService.psgi

+3-5
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,8 @@ use Plack::Builder;
88

99
my @dispatch;
1010

11-
{
12-
my $obj = Bio::KBase::AppService::AppServiceImpl->new;
13-
push(@dispatch, 'AppService' => $obj);
14-
}
15-
11+
my $obj = Bio::KBase::AppService::AppServiceImpl->new;
12+
push(@dispatch, 'AppService' => $obj);
1613

1714
my $server = Bio::KBase::AppService::Service->new(instance_dispatch => { @dispatch },
1815
allow_get => 0,
@@ -23,6 +20,7 @@ my $rpc_handler = sub { $server->handle_input(@_) };
2320
$handler = builder {
2421
mount "/ping" => sub { $server->ping(@_); };
2522
mount "/auth_ping" => sub { $server->auth_ping(@_); };
23+
mount "/task_info" => sub { $obj->_task_info(@_); };
2624
mount "/" => $rpc_handler;
2725
};
2826

lib/Bio/KBase/AppService/AppScript.pm

+104
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,14 @@ use strict;
66
use JSON::XS;
77
use File::Slurp;
88
use IO::File;
9+
use IO::Pipe;
10+
use IO::Select;
911
use Capture::Tiny 'capture';
1012
use Bio::P3::Workspace::WorkspaceClientExt;
1113
use Bio::KBase::AuthToken;
1214
use Time::HiRes 'gettimeofday';
15+
use LWP::UserAgent;
16+
use REST::Client;
1317

1418
use base 'Class::Accessor';
1519

@@ -27,7 +31,107 @@ sub new
2731
return bless $self, $class;
2832
}
2933

34+
#
35+
# Run the script.
36+
#
37+
# We wish the script to always succeed (from the point of view of the execution environment)
38+
# so we will run the script itself as a forked child, and monitor its execution. We create
39+
# pipes from stdout and stderr and push their output to the app service URL provided as the first argument to
40+
# the script.
41+
#
3042
sub run
43+
{
44+
my($self, $args) = @_;
45+
46+
#
47+
# Hack to finding task id.
48+
#
49+
my $task_id = 'TBD';
50+
if ($ENV{PWD} =~ /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})_\d+_\d+$/i)
51+
{
52+
$task_id = $1;
53+
}
54+
else
55+
{
56+
$task_id = "UNK-$$";
57+
}
58+
59+
my $appserv_url = shift @$args;
60+
61+
my $ua = LWP::UserAgent->new();
62+
my $rest = REST::Client->new();
63+
$rest->setHost("$appserv_url/$task_id");
64+
$self->{rest} = $rest;
65+
66+
my $sel = IO::Select->new();
67+
68+
my $stdout_pipe = IO::Pipe->new();
69+
my $stderr_pipe = IO::Pipe->new();
70+
71+
my $pid = fork();
72+
73+
if ($pid == 0)
74+
{
75+
$stdout_pipe->writer();
76+
$stderr_pipe->writer();
77+
78+
open(STDOUT, ">&", $stdout_pipe);
79+
open(STDERR, ">&", $stderr_pipe);
80+
81+
$self->subproc_run($args);
82+
exit(0);
83+
}
84+
85+
my $host = `hostname -f`;
86+
$host = `hostname` if !$host;
87+
chomp $host;
88+
89+
$self->write_block("pid", $pid);
90+
$self->write_block("hostname", $host);
91+
92+
$stdout_pipe->reader();
93+
$stderr_pipe->reader();
94+
95+
$sel->add($stdout_pipe);
96+
$sel->add($stderr_pipe);
97+
98+
while ($sel->count() > 0)
99+
{
100+
my @ready = $sel->can_read();
101+
for my $r (@ready)
102+
{
103+
my $which = ($r == $stdout_pipe) ? 'stdout' : 'stderr';
104+
my $block;
105+
my $n = $r->read($block, 1_000_000);
106+
if (!defined($n))
107+
{
108+
die "error reading $which $r: $!";
109+
}
110+
elsif ($n == 0)
111+
{
112+
print STDERR "EOF on $r\n";
113+
$self->write_block("$which/eof");
114+
$sel->remove($r);
115+
}
116+
else
117+
{
118+
$self->write_block("$which/data", $block);
119+
}
120+
}
121+
}
122+
123+
my $x = waitpid($pid, 0);
124+
$self->write_block("exitcode",$?);
125+
}
126+
127+
sub write_block
128+
{
129+
my($self, $path, $data) = @_;
130+
print "Write to $path: $data\n";
131+
$self->{rest}->POST($path, $data);
132+
}
133+
134+
sub subproc_run
31135
{
32136
my($self, $args) = @_;
33137

0 commit comments

Comments
 (0)