/* * CompileQueue.java * * Copyright (C) 2015 Pixelgaffer * * This work is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation; either version 2 of the License, or any later * version. * * This work is distributed in the hope that it will be useful, but without * any warranty; without even the implied warranty of merchantability or * fitness for a particular purpose. See version 2 and version 3 of the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.pixelgaffer.turnierserver.worker.compile; import java.io.File; import java.io.FileOutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.StringWriter; import java.nio.file.Files; import java.util.Deque; import java.util.LinkedList; import org.pixelgaffer.turnierserver.Airbrake; import org.pixelgaffer.turnierserver.compile.CompileResult; import org.pixelgaffer.turnierserver.compile.Compiler; import org.pixelgaffer.turnierserver.networking.DatastoreFtpClient; import org.pixelgaffer.turnierserver.networking.bwprotocol.WorkerCommandAnswer; import org.pixelgaffer.turnierserver.networking.messages.WorkerCommand; import org.pixelgaffer.turnierserver.worker.LibraryCache; import org.pixelgaffer.turnierserver.worker.WorkerMain; /** * Diese Queue sorgt dafür, dass nur ein Compile-Job zur selben Zeit ausgeführt * wird, damit der Server nicht zu langsam wird und die KIs in den Sandboxen * einigermaßen gleiche Geschwindigkeitsverhältnisse haben. */ public class CompileQueue implements Runnable { private static CompileQueue instance = new CompileQueue(); public static void addJob (WorkerCommand job) { if (job.getAction() != WorkerCommand.COMPILE) throw new IllegalArgumentException(); synchronized (instance.queue) { instance.queue.addLast(job); instance.queue.notifyAll(); } } private final Deque<WorkerCommand> queue = new LinkedList<>(); private CompileQueue () { new Thread(this, "CompileQueue").start(); } @Override public void run () { while (true) { WorkerCommand job = null; synchronized (queue) { // wenn die queue leer ist, warten bis wieder was drinnen ist while (queue.isEmpty()) { try { queue.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // den nächsten job holen job = queue.pollFirst(); } // wenn der job nicht null ist, den job ausführen if (job != null) { WorkerMain.getLogger().info("Starte Kompiliervorgang: " + job); try { Compiler c = Compiler.getCompiler(job.getAiId(), job.getVersion(), job.getGame(), job.getLang()); c.setUuid(job.getUuid()); CompileResult result = c.compileAndUpload(WorkerMain.getBackendClient(), LibraryCache.getCache()); DatastoreFtpClient.storeAiCompileOutput(job.getAiId(), job.getVersion(), result.getOutput()); WorkerMain.getBackendClient().sendAnswer( new WorkerCommandAnswer(job.getAction(), result.isSuccessfull() ? WorkerCommandAnswer.SUCCESS : WorkerCommandAnswer.CRASH, job.getUuid(), null)); result.getOutput().delete(); } catch (Exception e) { WorkerMain.getLogger().critical("Fehler beim Kompilieren der KI " + job.getAiId()); Airbrake.log(e).printStackTrace(); try { File tmp = Files.createTempFile("exception", ".txt").toFile(); PrintWriter out = new PrintWriter(new OutputStreamWriter(new FileOutputStream(tmp))); out.println("Während des Kompilierungsvorgangs ist ein interner Fehler aufgetreten."); e.printStackTrace(out); out.close(); DatastoreFtpClient.storeAiCompileOutput(job.getAiId(), job.getVersion(), tmp); StringWriter sw = new StringWriter(); e.printStackTrace(new PrintWriter(sw)); WorkerMain.getBackendClient().sendAnswer(new WorkerCommandAnswer(job.getAction(), WorkerCommandAnswer.MESSAGE, job.getUuid(), sw.toString())); WorkerMain.getBackendClient().sendAnswer(new WorkerCommandAnswer(job.getAction(), WorkerCommandAnswer.CRASH, job.getUuid(), null)); tmp.delete(); } catch (Exception e1) { Airbrake.log(e1).printStackTrace(); } } WorkerMain.getLogger().info("Kompilierauftrag fertig: " + job); } } } }