summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--internal/api/server.go15
-rw-r--r--internal/api/server_test.go28
2 files changed, 12 insertions, 31 deletions
diff --git a/internal/api/server.go b/internal/api/server.go
index 34e1872..11c9c15 100644
--- a/internal/api/server.go
+++ b/internal/api/server.go
@@ -451,21 +451,6 @@ func (s *Server) handleRunTask(w http.ResponseWriter, r *http.Request) {
return
}
- // Enforce retry limit for non-initial runs (PENDING is the initial state).
- if t.State != task.StatePending {
- execs, err := s.store.ListExecutions(id)
- if err != nil {
- writeJSON(w, http.StatusInternalServerError, map[string]string{"error": "failed to count executions"})
- return
- }
- if t.Retry.MaxAttempts > 0 && len(execs) >= t.Retry.MaxAttempts {
- writeJSON(w, http.StatusConflict, map[string]string{
- "error": fmt.Sprintf("retry limit reached (%d/%d attempts used)", len(execs), t.Retry.MaxAttempts),
- })
- return
- }
- }
-
if err := s.store.UpdateTaskState(id, task.StateQueued); err != nil {
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
diff --git a/internal/api/server_test.go b/internal/api/server_test.go
index cd415ae..8484e02 100644
--- a/internal/api/server_test.go
+++ b/internal/api/server_test.go
@@ -604,14 +604,14 @@ func TestResumeTimedOut_Success_Returns202(t *testing.T) {
}
}
-func TestRunTask_RetryLimitReached_Returns409(t *testing.T) {
+// TestRunTask_ManualRunIgnoresRetryLimit verifies that a manual POST /run always
+// succeeds regardless of MaxAttempts — retry limits only gate automatic retries.
+func TestRunTask_ManualRunIgnoresRetryLimit(t *testing.T) {
srv, store := testServer(t)
- // Task with MaxAttempts: 1 — only 1 attempt allowed. Create directly as FAILED
- // so state is consistent without going through transition sequence.
tk := &task.Task{
- ID: "retry-limit-1",
+ ID: "retry-limit-manual",
Name: "Retry Limit Task",
- Agent: task.AgentConfig{Instructions: "do something"},
+ Agent: task.AgentConfig{Instructions: "do something"},
Priority: task.PriorityNormal,
Retry: task.RetryConfig{MaxAttempts: 1, Backoff: "linear"},
Tags: []string{},
@@ -621,10 +621,10 @@ func TestRunTask_RetryLimitReached_Returns409(t *testing.T) {
if err := store.CreateTask(tk); err != nil {
t.Fatal(err)
}
- // Record one execution — the first attempt already used.
+ // Record one execution — MaxAttempts already exhausted.
exec := &storage.Execution{
- ID: "exec-retry-1",
- TaskID: "retry-limit-1",
+ ID: "exec-retry-manual",
+ TaskID: "retry-limit-manual",
StartTime: time.Now(),
Status: "FAILED",
}
@@ -632,17 +632,13 @@ func TestRunTask_RetryLimitReached_Returns409(t *testing.T) {
t.Fatal(err)
}
- req := httptest.NewRequest("POST", "/api/tasks/retry-limit-1/run", nil)
+ req := httptest.NewRequest("POST", "/api/tasks/retry-limit-manual/run", nil)
w := httptest.NewRecorder()
srv.Handler().ServeHTTP(w, req)
- if w.Code != http.StatusConflict {
- t.Errorf("status: want 409, got %d; body: %s", w.Code, w.Body.String())
- }
- var body map[string]string
- json.NewDecoder(w.Body).Decode(&body)
- if !strings.Contains(body["error"], "retry limit") {
- t.Errorf("error body should mention retry limit, got %q", body["error"])
+ // Manual run must succeed (202) even though MaxAttempts is exhausted.
+ if w.Code != http.StatusAccepted {
+ t.Errorf("status: want 202, got %d; body: %s", w.Code, w.Body.String())
}
}