Skip to content

Commit 4b0d8b4

Browse files
authored
Add saveArtifact support to interactive session. Closes #1902 (#1903)
1 parent bd96716 commit 4b0d8b4

File tree

6 files changed

+57
-15
lines changed

6 files changed

+57
-15
lines changed

src/common/compute/interactive/message.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
}
1010
}(this, function() {
1111
const Constants = makeEnum('STDOUT', 'STDERR', 'RUN', 'ADD_ARTIFACT', 'KILL',
12-
'ADD_FILE', 'REMOVE_FILE', 'ADD_USER_DATA', 'COMPLETE', 'ERROR', 'SET_ENV');
12+
'ADD_FILE', 'REMOVE_FILE', 'ADD_USER_DATA', 'COMPLETE', 'ERROR', 'SET_ENV',
13+
'SAVE_ARTIFACT');
1314

1415
function makeEnum() {
1516
const names = Array.prototype.slice.call(arguments);

src/common/compute/interactive/session-with-queue.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ define([
2222

2323
async runTask(task) {
2424
const queuedTask = this.queueTask(task);
25-
await queuedTask.promise;
25+
return await queuedTask.promise;
2626
}
2727

2828
queueTask(task) {
@@ -46,9 +46,9 @@ define([
4646

4747
async runNextTask() {
4848
const queuedTask = this.tasks[0];
49-
await super.runTask(queuedTask.unwrap());
49+
const result = await super.runTask(queuedTask.unwrap());
5050
this.tasks.shift();
51-
queuedTask.resolve();
51+
queuedTask.resolve(result);
5252
this.checkTaskQueue();
5353
}
5454

src/common/compute/interactive/session.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,10 @@ define([
9494
this.ensureIdle('run task');
9595

9696
this.currentTask = task;
97-
await task.run();
97+
const result = await task.run();
9898
this.currentTask = null;
9999
this.checkReady();
100+
return result;
100101
}
101102

102103
async whenConnected() {
@@ -128,12 +129,24 @@ define([
128129
}
129130

130131
async addArtifact(name, dataInfo, type, auth) {
132+
auth = auth || {};
131133
this.ensureIdle('add artifact');
132134
const msg = new Message(Message.ADD_ARTIFACT, [name, dataInfo, type, auth]);
133135
const task = new Task(this.channel, msg);
134136
await this.runTask(task);
135137
}
136138

139+
async saveArtifact(/*path, name, storageId, config*/) {
140+
this.ensureIdle('save artifact');
141+
const msg = new Message(Message.SAVE_ARTIFACT, [...arguments]);
142+
const task = new Task(this.channel, msg);
143+
const [exitCode, dataInfo] = await this.runTask(task);
144+
if (exitCode) {
145+
throw new CommandFailedError('saveArtifact', {exitCode});
146+
}
147+
return dataInfo;
148+
}
149+
137150
async addFile(filepath, content) {
138151
this.ensureIdle('add file');
139152
const msg = new Message(Message.ADD_FILE, [filepath, content]);

src/common/compute/interactive/task.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ define([
2828
this.emitMessage(msg);
2929
if (msg.type === Message.COMPLETE) {
3030
this.channel.unlisten(handler);
31-
deferred.resolve();
31+
deferred.resolve(msg.data);
3232
}
3333
};
3434
this.channel.listen(handler);
@@ -37,7 +37,11 @@ define([
3737
}
3838

3939
emitMessage(msg) {
40-
this.emit(msg.type, msg.data);
40+
if (msg.type === Message.COMPLETE) {
41+
this.emit(msg.type, ...msg.data);
42+
} else {
43+
this.emit(msg.type, msg.data);
44+
}
4145
}
4246

4347
static async getMessageData(wsMsg) {

src/routers/InteractiveCompute/job-files/start.js

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class InteractiveClient {
2929
if (msg.type === Message.RUN) {
3030
const [cmd, ...opts] = InteractiveClient.parseCommand(msg.data);
3131
this.subprocess = spawn(cmd, opts);
32-
this.subprocess.on('exit', code => this.sendMessage(Message.COMPLETE, code));
32+
this.subprocess.on('exit', code => this.sendMessage(Message.COMPLETE, [code]));
3333
this.subprocess.stdout.on('data', data => this.sendMessage(Message.STDOUT, data));
3434
this.subprocess.stderr.on('data', data => this.sendMessage(Message.STDERR, data));
3535
} else if (msg.type === Message.KILL) {
@@ -46,15 +46,31 @@ class InteractiveClient {
4646
Utils,
4747
) => {
4848
const {Storage} = Utils;
49-
50-
async function saveArtifact() {
51-
const client = await Storage.getClient(dataInfo.backend, null, config);
49+
const fetchArtifact = async () => {
50+
const client = await Storage.getClient(dataInfo.backend, undefined, config);
5251
const dataPath = path.join(...dirs.concat('data'));
5352
const stream = await client.getFileStream(dataInfo);
5453
await pipeline(stream, fs.createWriteStream(dataPath));
5554
const filePath = path.join(...dirs.concat('__init__.py'));
5655
await fsp.writeFile(filePath, initFile(name, type));
57-
}
56+
};
57+
58+
this.runTask(fetchArtifact);
59+
});
60+
} else if (msg.type === Message.SAVE_ARTIFACT) {
61+
const [filepath, name, backend, config={}] = msg.data;
62+
requirejs([
63+
'./utils.build',
64+
], (
65+
Utils,
66+
) => {
67+
const {Storage} = Utils;
68+
const saveArtifact = async () => {
69+
const client = await Storage.getClient(backend, null, config);
70+
const stream = await fs.createReadStream(filepath);
71+
const dataInfo = await client.putFileStream(name, stream);
72+
return dataInfo;
73+
};
5874

5975
this.runTask(saveArtifact);
6076
});
@@ -76,7 +92,7 @@ class InteractiveClient {
7692
await fsp.unlink(filepath);
7793
});
7894
} else {
79-
this.sendMessage(Message.COMPLETE, 2);
95+
this.sendMessage(Message.COMPLETE, [2]);
8096
}
8197
}
8298

@@ -99,13 +115,14 @@ class InteractiveClient {
99115

100116
async runTask(fn) {
101117
let exitCode = 0;
118+
let result;
102119
try {
103-
await fn();
120+
result = await fn();
104121
} catch (err) {
105122
exitCode = 1;
106123
console.log('Task failed with error:', err);
107124
}
108-
this.sendMessage(Message.COMPLETE, exitCode);
125+
this.sendMessage(Message.COMPLETE, [exitCode, result]);
109126
}
110127

111128
static parseCommand(cmd) {

test/integration/InteractiveCompute.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,13 @@ describe('InteractiveCompute', function() {
6161
sleep(100).then(() => session.kill(task));
6262
});
6363

64+
it('should save artifacts', async function() {
65+
await session.exec('node -e \'fs.writeFileSync("test.txt", "hi")\'');
66+
const dataInfo = await session.saveArtifact('test.txt', 'test', 'gme');
67+
assert.equal(dataInfo.backend, 'gme');
68+
assert(dataInfo.data);
69+
});
70+
6471
function sleep(duration) {
6572
return new Promise(resolve => setTimeout(resolve, duration));
6673
}

0 commit comments

Comments
 (0)