Skip to content

Commit 3cf7500

Browse files
committed
feat: enforce 120 seconds compilation timeout
1 parent dcca66a commit 3cf7500

File tree

1 file changed

+21
-6
lines changed

1 file changed

+21
-6
lines changed

main.go

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package main
55

66
import (
7+
"context"
78
"encoding/base64"
89
"encoding/json"
910
"fmt"
@@ -21,6 +22,11 @@ import (
2122
"github.com/prometheus/client_golang/prometheus/promhttp"
2223
)
2324

25+
const (
26+
// CompilationTimeout is the maximum time allowed for a compilation request
27+
CompilationTimeout = 120 * time.Second
28+
)
29+
2430
type CompileRequest struct {
2531
Sources map[string]string `json:"sources"`
2632
TopModule string `json:"topModule"`
@@ -163,6 +169,10 @@ func handleCompile(w http.ResponseWriter, r *http.Request) {
163169
return
164170
}
165171

172+
// Create context with timeout
173+
ctx, cancel := context.WithTimeout(r.Context(), CompilationTimeout)
174+
defer cancel()
175+
166176
// Start metrics tracking
167177
startTime := time.Now()
168178
compilationInProgress.Inc()
@@ -243,7 +253,7 @@ func handleCompile(w http.ResponseWriter, r *http.Request) {
243253
}
244254
yosysArgs = append(yosysArgs, sourceFiles...)
245255

246-
if !runCommand(w, flusher, workDir, "yosys", yosysArgs) {
256+
if !runCommand(ctx, w, flusher, workDir, "yosys", yosysArgs) {
247257
return
248258
}
249259

@@ -268,13 +278,13 @@ func handleCompile(w http.ResponseWriter, r *http.Request) {
268278
"--json", "output.json",
269279
}
270280

271-
if !runCommand(w, flusher, workDir, "nextpnr-ice40", nextpnrArgs) {
281+
if !runCommand(ctx, w, flusher, workDir, "nextpnr-ice40", nextpnrArgs) {
272282
return
273283
}
274284

275285
// Run icepack
276286
icepackArgs := []string{"output.asc", "output.bin"}
277-
if !runCommand(w, flusher, workDir, "icepack", icepackArgs) {
287+
if !runCommand(ctx, w, flusher, workDir, "icepack", icepackArgs) {
278288
return
279289
}
280290

@@ -294,7 +304,7 @@ func handleCompile(w http.ResponseWriter, r *http.Request) {
294304
})
295305
}
296306

297-
func runCommand(w http.ResponseWriter, flusher http.Flusher, workDir, command string, args []string) bool {
307+
func runCommand(ctx context.Context, w http.ResponseWriter, flusher http.Flusher, workDir, command string, args []string) bool {
298308
startTime := time.Now()
299309
defer func() {
300310
commandExecutionDuration.WithLabelValues(command).Observe(time.Since(startTime).Seconds())
@@ -306,7 +316,7 @@ func runCommand(w http.ResponseWriter, flusher http.Flusher, workDir, command st
306316
Args: args,
307317
})
308318

309-
cmd := exec.Command(command, args...)
319+
cmd := exec.CommandContext(ctx, command, args...)
310320
cmd.Dir = workDir
311321

312322
stdout, err := cmd.StdoutPipe()
@@ -333,7 +343,12 @@ func runCommand(w http.ResponseWriter, flusher http.Flusher, workDir, command st
333343
go streamOutput(w, flusher, stderr, "stderr")
334344

335345
if err := cmd.Wait(); err != nil {
336-
sendSSE(w, flusher, StreamMessage{Type: "error", Message: fmt.Sprintf("%s failed: %v", command, err)})
346+
// Check if the error is due to context timeout
347+
if ctx.Err() == context.DeadlineExceeded {
348+
sendSSE(w, flusher, StreamMessage{Type: "error", Message: fmt.Sprintf("Compilation timeout: operation exceeded %v", CompilationTimeout)})
349+
} else {
350+
sendSSE(w, flusher, StreamMessage{Type: "error", Message: fmt.Sprintf("%s failed: %v", command, err)})
351+
}
337352
return false
338353
}
339354

0 commit comments

Comments
 (0)