-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.js
More file actions
130 lines (116 loc) · 4.1 KB
/
index.js
File metadata and controls
130 lines (116 loc) · 4.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
const { promisify } = require("util");
const mongoose = require("mongoose");
const AWS = require("aws-sdk");
const fs = require("fs");
const path = require("path");
const tar = require("tar");
const through2 = require("through2");
const amqp = require("amqplib");
const execa = require("execa");
const run = require("./run");
const { Match } = require("mm-schemas")(mongoose);
const RABBITMQ_URI = process.env.RABBITMQ_URI || "amqp://localhost";
const DOCKER_CREDENTIALS_PATH = "/gcr/mechmania2017-key.json";
const RUNNER_QUEUE = `runnerQueue`;
const GAME_PATH = "/game/game.exe";
const MAP_PATH = "/game/Map.json";
const BOT_STARTUP_TIMEOUT = "8"; // 8s
mongoose.connect(process.env.MONGO_URL);
mongoose.Promise = global.Promise;
const s3 = new AWS.S3({
params: { Bucket: "mechmania" }
});
const upload = promisify(s3.upload.bind(s3));
async function main() {
// Login to docker
// docker login -u _json_key --password-stdin https://gcr.io
const dockerLoginProc = execa("docker", [
"login",
"-u",
"_json_key",
"--password-stdin",
"https://gcr.io"
]);
fs.createReadStream(DOCKER_CREDENTIALS_PATH).pipe(dockerLoginProc.stdin);
const { stdout, stderr } = dockerLoginProc;
stdout.pipe(process.stdout);
stderr.pipe(process.stderr);
await dockerLoginProc;
const conn = await amqp.connect(RABBITMQ_URI);
const ch = await conn.createChannel();
ch.assertQueue(RUNNER_QUEUE, { durable: true });
ch.prefetch(2); // Each instance can run upto 2 games in parallel
process.on("SIGTERM", async () => {
console.log("Got SIGTERM");
await ch.close();
conn.close();
});
console.log(`Listening to ${RUNNER_QUEUE}`);
ch.consume(
RUNNER_QUEUE,
async message => {
console.log(`Got message - ${message.content.toString()}`);
const [p1, p2] = JSON.parse(message.content.toString()).sort();
const images = [p1, p2].map(id => `gcr.io/mechmania2017/${id}`);
const matchName = `logs/${p1}:${p2}`;
// Pull docker images
try {
console.log(`${p1} v ${p2} - Fetching docker images`);
await Promise.all(images.map(img => run("docker", ["pull", img])));
} catch (e) {
// Sleep 5s and requeue the message
console.warn("Got an error on docker pull. Sleeping 5s and requeueing");
await new Promise(r => setTimeout(r, 5000));
ch.nack(message);
}
console.log(`${p1} v ${p2} - Running game`);
try {
const { stdout, stderr } = await execa(GAME_PATH, [
...images.map(img => `docker run --rm -i ${img}`),
MAP_PATH,
BOT_STARTUP_TIMEOUT
]);
// TODO: Save the stderr somewhere too so we have debug infor for each run?
console.log(`${p1} v ${p2} - Uploading logfile to s3`);
const data = await upload({
Key: matchName,
Body: stdout
});
console.log(`${p1} v ${p2} - Uploaded to s3 (${data.Location})`);
console.log(`${p1} v ${p2} - Parsing logfile for stats`);
const logLines = stdout.split("\n");
const numLogLines = logLines.length; // -1 becuause the last line is just '\n'
const lastRecord = logLines.slice(-1)[0];
console.log(`${p1} v ${p2} - Last log line is ${lastRecord}`);
const { Winner: winner } = JSON.parse(lastRecord);
console.log(`${p1} v ${p2} - Winner is ${winner}`);
console.log(`${p1} v ${p2} - Creating mongo record`);
await Match.update(
{
key: matchName
},
{
key: matchName,
length: numLogLines,
winner
},
{ upsert: true }
).exec();
} catch (e) {
console.log(`${p1} v ${p2} - The game engine exited`);
console.error(e);
console.log(`${p1} v ${p2} - Considering the game a tie`);
console.log(`${p1} v ${p2} - Creating mongo record`);
const match = new Match({
key: matchName,
winner: 3
});
console.log(`${p1} v ${p2} - Saving mongo record`);
await match.save();
}
ch.ack(message);
},
{ noAck: false }
);
}
main().catch(console.trace);