F1bonacc1 / process-compose

Process Compose is a simple and flexible scheduler and orchestrator to manage non-containerized applications.
https://f1bonacc1.github.io/process-compose/
Apache License 2.0
1.34k stars 52 forks source link

[Fixes #197] Gracefully shutdown HTTP server #201

Closed dcarley closed 4 months ago

dcarley commented 4 months ago

To prevent a race condition seen in https://github.com/F1bonacc1/process-compose/issues/197:

  1. On the client: a. User runs process-compose down b. Client makes request to /project/stop
  2. On the server: a. ProjectRunner.ShutDownProject() stops all processes b. cmd.runProject() stops blocking c. Exits before PcApi.ShutDownProject has written the response
  3. On the client: a. Gets EOF reading the response because the server has gone away

I can't think of a way to reproduce this in a test, except for something convoluted like creating a custom client that introduces a delay in reading the response.

It can be "manually" simulated by adding a small delay here though:

diff --git a/src/api/pc_api.go b/src/api/pc_api.go
index d123257..d069399 100644
--- a/src/api/pc_api.go
+++ b/src/api/pc_api.go
@@ -3,6 +3,7 @@ package api
 import (
    "net/http"
    "strconv"
+   "time"

    "github.com/f1bonacc1/process-compose/src/app"
    "github.com/gin-gonic/gin"
@@ -268,6 +269,7 @@ func (api *PcApi) GetProcessPorts(c *gin.Context) {
 // @Router /project/stop [post]
 func (api *PcApi) ShutDownProject(c *gin.Context) {
    api.project.ShutDownProject()
+   time.Sleep(10 * time.Millisecond)
    c.JSON(http.StatusOK, gin.H{"status": "stopped"})
 }

And using this config:

processes:
  one:
    command: sleep infinity
  two:
    command: sleep infinity

Before this change:

bash-5.2$ go run src/main.go up --config services.yaml --tui=false &
[1] 8171
bash-5.2$ go run src/main.go down
24-07-12 15:38:40.332 FTL failed to stop project error="Post \"http://localhost:8080/project/stop\": EOF"
exit status 1
[1]+  Done                    go run src/main.go up --config services.yaml --tui=false

After this change:

bash-5.2$ go run src/main.go up --config services.yaml --tui=false &
[1] 8432
bash-5.2$ go run src/main.go down