feat!(backend/jobs): don't require agent_id on waitjob
ci-agent / build (push) Failing after 5m30s

This commit is contained in:
2026-04-05 04:57:43 +03:00
parent b1e6775f1b
commit 71a8fa154b
6 changed files with 37 additions and 77 deletions
-20
View File
@@ -1106,15 +1106,6 @@ const docTemplate = `{
"name": "id", "name": "id",
"in": "path", "in": "path",
"required": true "required": true
},
{
"description": "Agent reference",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/internal_handlers.WaitJobIn"
}
} }
], ],
"responses": { "responses": {
@@ -2923,17 +2914,6 @@ const docTemplate = `{
"type": "string" "type": "string"
} }
} }
},
"internal_handlers.WaitJobIn": {
"type": "object",
"required": [
"agent_id"
],
"properties": {
"agent_id": {
"type": "string"
}
}
} }
}, },
"securityDefinitions": { "securityDefinitions": {
-20
View File
@@ -1095,15 +1095,6 @@
"name": "id", "name": "id",
"in": "path", "in": "path",
"required": true "required": true
},
{
"description": "Agent reference",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/internal_handlers.WaitJobIn"
}
} }
], ],
"responses": { "responses": {
@@ -2912,17 +2903,6 @@
"type": "string" "type": "string"
} }
} }
},
"internal_handlers.WaitJobIn": {
"type": "object",
"required": [
"agent_id"
],
"properties": {
"agent_id": {
"type": "string"
}
}
} }
}, },
"securityDefinitions": { "securityDefinitions": {
-13
View File
@@ -513,13 +513,6 @@ definitions:
required: required:
- token - token
type: object type: object
internal_handlers.WaitJobIn:
properties:
agent_id:
type: string
required:
- agent_id
type: object
info: info:
contact: {} contact: {}
paths: paths:
@@ -1165,12 +1158,6 @@ paths:
name: id name: id
required: true required: true
type: integer type: integer
- description: Agent reference
in: body
name: body
required: true
schema:
$ref: '#/definitions/internal_handlers.WaitJobIn'
produces: produces:
- application/json - application/json
responses: responses:
+33 -20
View File
@@ -51,11 +51,6 @@ type JobResult struct {
Status int32 `json:"status"` Status int32 `json:"status"`
} }
// WaitJobIn is the request body for waiting on a job.
type WaitJobIn struct {
AgentID string `json:"agent_id" binding:"required"`
}
// AddJob submits a job to an agent and returns a wait_url for the result. // AddJob submits a job to an agent and returns a wait_url for the result.
// @Summary Submit a job to an agent // @Summary Submit a job to an agent
// @Description Sends a command to the specified agent and returns a URL to wait for the result // @Description Sends a command to the specified agent and returns a URL to wait for the result
@@ -118,14 +113,14 @@ func (h *JobsHandlers) runCommand(
} }
// WaitJob waits for a submitted job to complete (long-poll). // WaitJob waits for a submitted job to complete (long-poll).
// If the job is already done, returns immediately. // First checks the database; if already finished, returns immediately.
// Otherwise waits on the agent for the result.
// @Summary Wait for job result // @Summary Wait for job result
// @Description Long-polls for a job result. Returns immediately if the job is already finished. // @Description Long-polls for a job result. Returns immediately if the job is already finished.
// @Tags jobs // @Tags jobs
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Param id path int true "Job ID" // @Param id path int true "Job ID"
// @Param body body WaitJobIn true "Agent reference"
// @Success 200 {object} JobResult // @Success 200 {object} JobResult
// @Failure 400 {object} map[string]string // @Failure 400 {object} map[string]string
// @Failure 404 {object} map[string]string // @Failure 404 {object} map[string]string
@@ -137,32 +132,50 @@ func (h *JobsHandlers) WaitJob(c *gin.Context) {
return return
} }
var in WaitJobIn // Check database first
if err := c.Bind(&in); err != nil { job, err := h.jobRepo.GetJobByID(c.Request.Context(), jid)
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request body"}) if err != nil {
if errors.Is(err, repository.ErrNotFound) {
c.JSON(http.StatusNotFound, gin.H{"error": "job not found"})
return
}
c.Error(err)
return return
} }
agent, ok := h.tracker.GetAgent(in.AgentID) // If job is already completed (has output or non-zero status), return immediately
if job.Status != 0 || job.Stdout != "" || job.Stderr != "" {
c.JSON(http.StatusOK, JobResult{
ID: job.ID,
Command: job.Command,
Stdin: job.Stdin,
Stdout: job.Stdout,
Stderr: job.Stderr,
Status: job.Status,
})
return
}
// Job is still pending — wait on the agent
agent, ok := h.tracker.GetAgent(job.AgentID)
if !ok { if !ok {
c.Status(http.StatusNotFound) c.JSON(http.StatusNotFound, gin.H{"error": "agent not found"})
c.Error(fmt.Errorf("agent not found"))
return return
} }
job, err := agent.WaitJob(jid) ajob, err := agent.WaitJob(jid)
if err != nil { if err != nil {
c.Error(err) c.Error(err)
return return
} }
c.JSON(http.StatusOK, JobResult{ c.JSON(http.StatusOK, JobResult{
ID: job.ID, ID: ajob.ID,
Command: job.Command, Command: ajob.Command,
Stdin: job.Stdin, Stdin: ajob.Stdin,
Stdout: job.Stdout, Stdout: ajob.Stdout,
Stderr: job.Stderr, Stderr: ajob.Stderr,
Status: job.Status, Status: ajob.Status,
}) })
} }
+2 -2
View File
@@ -1,8 +1,8 @@
package models package models
type Job struct { type Job struct {
ID int64 ID int64
AgentID string
JobForInsert JobForInsert
JobForUpdate JobForUpdate
} }
@@ -87,9 +87,9 @@ func (r *JobRepository) GetJobByID(ctx context.Context, jid int64) (models.Job,
var stdinVal *string var stdinVal *string
err := r.DB.QueryRowContext(ctx, err := r.DB.QueryRowContext(ctx,
`SELECT id, command, stdin, stdout, stderr, status FROM jobs WHERE id = ?`, `SELECT id, agent_id, command, stdin, stdout, stderr, status FROM jobs WHERE id = ?`,
jid, jid,
).Scan(&job.ID, &commandJSON, &stdinVal, &job.Stdout, &job.Stderr, &job.Status) ).Scan(&job.ID, &job.AgentID, &commandJSON, &stdinVal, &job.Stdout, &job.Stderr, &job.Status)
if err != nil { if err != nil {
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
return models.Job{}, ErrNotFound return models.Job{}, ErrNotFound