This commit was merged in pull request #32.
This commit is contained in:
@@ -15,6 +15,7 @@ import (
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -181,6 +182,9 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
resp := response{RequestID: requestID, Image: req.Image, Tag: req.Tag, Matched: len(services)}
|
||||
pending := map[int]int64{} // index into resp.Results -> job ID
|
||||
// An agent's own service goes last: jobs that reach an agent while it
|
||||
// replaces itself are lost, and messages to one agent arrive in order.
|
||||
slices.SortStableFunc(services, func(a, b model.Service) int { return selfRank(a) - selfRank(b) })
|
||||
for _, svc := range services {
|
||||
res, job := h.handle(work, svc, req.Tag, started, log)
|
||||
resp.Results = append(resp.Results, res)
|
||||
@@ -252,6 +256,14 @@ func (h *Handler) handle(ctx context.Context, svc model.Service, tag string, sta
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// selfRank sorts an agent's own service after all others.
|
||||
func selfRank(svc model.Service) int {
|
||||
if svc.Self {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (h *Handler) setJob(res *result, job model.Job) {
|
||||
res.JobID = job.ID
|
||||
res.JobURL = h.cfg.PublicURL + "/jobs/" + strconv.FormatInt(job.ID, 10)
|
||||
|
||||
@@ -470,14 +470,14 @@ func TestBusyIsNotAFailure(t *testing.T) {
|
||||
|
||||
func TestRefusedIsNotAFailure(t *testing.T) {
|
||||
e := newEnv(t, compose(1, model.ModeAuto, slusk+":1.4.2"))
|
||||
e.jobs.errFor[1] = &model.NotUpdatableError{Reason: model.ReasonSelf}
|
||||
e.jobs.errFor[1] = &model.NotUpdatableError{Reason: model.ReasonContainer}
|
||||
|
||||
rec := e.post(`{"image":"` + slusk + `","tag":"2"}`)
|
||||
|
||||
assert.Equal(t, 200, rec.Code)
|
||||
r := decode(t, rec).Results[0]
|
||||
assert.Equal(t, statusRefused, r.Status)
|
||||
assert.Equal(t, model.ReasonSelf, r.Error)
|
||||
assert.Equal(t, model.ReasonContainer, r.Error)
|
||||
assert.Zero(t, r.JobID)
|
||||
assert.NotEmpty(t, e.store.avail)
|
||||
}
|
||||
@@ -500,6 +500,21 @@ func TestMixedAutoAndManual(t *testing.T) {
|
||||
assert.Len(t, e.store.avail, 3)
|
||||
}
|
||||
|
||||
func TestAgentsOwnServiceIsStartedLast(t *testing.T) {
|
||||
own := compose(1, model.ModeAuto, slusk+":1")
|
||||
own.Self = true
|
||||
e := newEnv(t, own, compose(2, model.ModeAuto, slusk+":1"))
|
||||
e.jobs.jobFor[1] = model.Job{Status: model.JobSucceeded}
|
||||
e.jobs.jobFor[2] = model.Job{Status: model.JobSucceeded}
|
||||
|
||||
e.post(`{"image":"` + slusk + `","tag":"2"}`)
|
||||
|
||||
calls := e.jobs.startCalls()
|
||||
require.Len(t, calls, 2)
|
||||
assert.Equal(t, int64(2), calls[0].svc.ID)
|
||||
assert.Equal(t, int64(1), calls[1].svc.ID)
|
||||
}
|
||||
|
||||
func TestClientCancelStopsWaitingButNotStarting(t *testing.T) {
|
||||
e := newEnv(t, compose(1, model.ModeAuto, slusk+":1.4.2"))
|
||||
e.h.cfg.Timeout = time.Minute
|
||||
|
||||
Reference in New Issue
Block a user