Skip to content

Commit c2bc622

Browse files
committed
upload result to s3 for callback mode (POST: /runs)
1 parent 50816db commit c2bc622

File tree

7 files changed

+239
-15
lines changed

7 files changed

+239
-15
lines changed

config.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,14 @@ exports = module.exports = {
2323
PASS: process.env.AMQP_PASS || 'codingblocks',
2424
HOST: process.env.AMQP_HOST || 'localhost',
2525
PORT: process.env.AMQP_PORT || 5672
26+
},
27+
28+
S3: {
29+
endpoint: process.env.S3_ENDPOINT || 'localhost',
30+
port: process.env.S3_PORT || 9000,
31+
ssl: process.env.S3_SSL || false,
32+
accessKey: process.env.S3_ACCESS_KEY || '',
33+
secretKey: process.env.S3_SECRET_KEY || '',
34+
bucket: process.env.S3_BUCKET || 'judge-submissions'
2635
}
2736
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
alter table submissions
2+
add column outputs varchar[];

package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "judge-api",
3-
"version": "1.0.0",
3+
"version": "1.1.0",
44
"description": "Judge API",
55
"main": "dist/server.js",
66
"repository": "https://github.com/coding-blocks/judge-api",
@@ -15,14 +15,17 @@
1515
"base-64": "^0.1.0",
1616
"debug": "^4.0.0",
1717
"express": "^4.16.2",
18+
"minio": "^7.0.3",
1819
"pg": "^7.4.3",
1920
"pg-hstore": "^2.3.2",
20-
"sequelize": "^4.22.6"
21+
"sequelize": "^4.22.6",
22+
"uuid": "^3.3.2"
2123
},
2224
"devDependencies": {
2325
"@types/chai": "^4.0.4",
2426
"@types/debug": "^0.0.30",
2527
"@types/express": "^4.0.39",
28+
"@types/minio": "^7.0.1",
2629
"@types/mocha": "^5.0.0",
2730
"@types/request": "^2.0.8",
2831
"@types/sequelize": "^4.0.79",

src/db/models.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ const Submissions = db.define('submissions', {
4242
},
4343
start_time: Sequelize.DATE,
4444
end_time: Sequelize.DATE,
45-
results: Sequelize.ARRAY(Sequelize.INTEGER)
45+
results: Sequelize.ARRAY(Sequelize.INTEGER),
46+
outputs: Sequelize.ARRAY(Sequelize.STRING)
4647
}, {
4748
paranoid: true, // We do not want to lose any submission data
4849
timestamps: false // Start and end times are already logged
@@ -53,6 +54,7 @@ export type SubmissionAttributes = {
5354
start_time: Date
5455
end_time?: Date
5556
results?: Array<number>
57+
outputs?: Array<string>
5658
}
5759

5860
const ApiKeys = db.define('apikeys', {

src/routes/api/run.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import {Response, Router, Request} from 'express'
22
import axios from 'axios'
33

4-
import {SubmissionAttributes, Submissions} from '../../db/models'
4+
import {SubmissionAttributes, Submissions, db} from '../../db/models'
55
import {RunJob, queueJob, successListener} from '../../rabbitmq/jobqueue'
66
import {isInvalidRunRequest} from '../../validators/SubmissionValidators'
7+
import {upload} from '../../utils/s3'
78
import config = require('../../../config')
89

910
const route: Router = Router()
@@ -58,7 +59,22 @@ const handleSuccessForSubmission = function (result: RunResponse) {
5859
break;
5960
case 'callback':
6061
// send a post request to callback
61-
axios.post(job.callback, result)
62+
(async () => {
63+
// 1. upload the result to s3 and get the url
64+
const {url} = await upload(result)
65+
66+
// 2. save the url in db
67+
await Submissions.update({
68+
outputs: [url]
69+
}, {
70+
where: {
71+
id: result.id
72+
}
73+
})
74+
75+
// make the callback request
76+
await axios.post(job.callback, {id: result.id, outputs: [url]})
77+
})()
6278
break;
6379
}
6480
}
@@ -112,6 +128,13 @@ const getRunPoolElement = function (body: RunRequestBody, res: Response): RunPoo
112128
* }
113129
* @apiSuccessExample {JSON} Success-Response(mode=callback):
114130
* HTTP/1.1 200 OK
131+
*
132+
* @apiSuccessExample {JSON} Body for Callback(mode=callback):
133+
* HTTP/1.1 200 OK
134+
* {
135+
* "id": 10,
136+
* "outputs": ["http://localhost/judge-submissions/file.json"]
137+
* }
115138
*/
116139
route.post('/', (req, res, next) => {
117140
const invalidRequest = isInvalidRunRequest(req)

src/utils/s3.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import Minio = require('minio')
2+
import v4 = require('uuid/v4')
3+
import config = require('../../config')
4+
5+
const client = new Minio.Client({
6+
endPoint: config.S3.endpoint,
7+
port: config.S3.port,
8+
useSSL: config.S3.ssl,
9+
accessKey: config.S3.accessKey,
10+
secretKey: config.S3.secretKey,
11+
})
12+
13+
export type savedFile = {
14+
etag: string,
15+
url: string
16+
}
17+
18+
export const urlForFilename = (bucket: string, filename: string) : string => `http${config.S3.ssl ? 's': ''}://${config.S3.endpoint}/${bucket}/${filename}`
19+
20+
export const upload = function (object:object, filename:string = v4() + '.json' ,bucket:string = config.S3.bucket) : Promise<savedFile> {
21+
return new Promise((resolve, reject) => {
22+
client.putObject(bucket, filename, JSON.stringify(object), function(err, etag) {
23+
if (err) return reject(err)
24+
resolve({etag, url: urlForFilename(bucket, filename) })
25+
})
26+
})
27+
}

0 commit comments

Comments
 (0)