mirror of
https://github.com/hatchet-dev/hatchet.git
synced 2026-05-25 04:48:44 -05:00
feat: step reruns from the dashboard (#143)
This commit is contained in:
@@ -116,3 +116,5 @@ CreateAPITokenResponse:
|
||||
$ref: "./api_tokens.yaml#/CreateAPITokenResponse"
|
||||
ListAPITokensResponse:
|
||||
$ref: "./api_tokens.yaml#/ListAPITokensResponse"
|
||||
RerunStepRunRequest:
|
||||
$ref: "./workflow_run.yaml#/RerunStepRunRequest"
|
||||
|
||||
@@ -211,3 +211,10 @@ StepRun:
|
||||
- jobRunId
|
||||
- stepId
|
||||
- status
|
||||
|
||||
RerunStepRunRequest:
|
||||
properties:
|
||||
input:
|
||||
type: object
|
||||
required:
|
||||
- input
|
||||
|
||||
@@ -74,6 +74,10 @@ paths:
|
||||
$ref: "./paths/workflow/workflow.yaml#/workflowRuns"
|
||||
/api/v1/tenants/{tenant}/workflow-runs/{workflow-run}:
|
||||
$ref: "./paths/workflow/workflow.yaml#/workflowRun"
|
||||
/api/v1/tenants/{tenant}/step-runs/{step-run}:
|
||||
$ref: "./paths/step-run/step-run.yaml#/stepRunScoped"
|
||||
/api/v1/tenants/{tenant}/step-runs/{step-run}/rerun:
|
||||
$ref: "./paths/step-run/step-run.yaml#/rerunStepRun"
|
||||
/api/v1/tenants/{tenant}/worker:
|
||||
$ref: "./paths/worker/worker.yaml#/withTenant"
|
||||
/api/v1/workers/{worker}:
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
stepRunScoped:
|
||||
get:
|
||||
x-resources: ["tenant", "step-run"]
|
||||
description: Get a step run by id
|
||||
operationId: step-run:get
|
||||
parameters:
|
||||
- description: The tenant id
|
||||
in: path
|
||||
name: tenant
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
minLength: 36
|
||||
maxLength: 36
|
||||
- description: The step run id
|
||||
in: path
|
||||
name: step-run
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
minLength: 36
|
||||
maxLength: 36
|
||||
responses:
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "../../components/schemas/_index.yaml#/StepRun"
|
||||
description: Successfully retrieved the step run
|
||||
"400":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "../../components/schemas/_index.yaml#/APIErrors"
|
||||
description: A malformed or bad request
|
||||
"403":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "../../components/schemas/_index.yaml#/APIErrors"
|
||||
description: Forbidden
|
||||
"404":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "../../components/schemas/_index.yaml#/APIErrors"
|
||||
description: The step run was not found
|
||||
summary: Get step run
|
||||
tags:
|
||||
- Step Run
|
||||
|
||||
rerunStepRun:
|
||||
post:
|
||||
x-resources: ["tenant", "step-run"]
|
||||
description: Reruns a step run
|
||||
operationId: step-run:update:rerun
|
||||
parameters:
|
||||
- description: The tenant id
|
||||
in: path
|
||||
name: tenant
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
minLength: 36
|
||||
maxLength: 36
|
||||
- description: The step run id
|
||||
in: path
|
||||
name: step-run
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
minLength: 36
|
||||
maxLength: 36
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "../../components/schemas/_index.yaml#/RerunStepRunRequest"
|
||||
description: The input to the rerun
|
||||
required: true
|
||||
responses:
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "../../components/schemas/_index.yaml#/StepRun"
|
||||
description: Successfully replayed the events
|
||||
"400":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "../../components/schemas/_index.yaml#/APIErrors"
|
||||
description: A malformed or bad request
|
||||
"403":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "../../components/schemas/_index.yaml#/APIErrors"
|
||||
description: Forbidden
|
||||
summary: Rerun step run
|
||||
tags:
|
||||
- Step Run
|
||||
@@ -0,0 +1,25 @@
|
||||
package stepruns
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
|
||||
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
|
||||
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
|
||||
"github.com/hatchet-dev/hatchet/internal/repository/prisma/db"
|
||||
)
|
||||
|
||||
func (t *StepRunService) StepRunGet(ctx echo.Context, request gen.StepRunGetRequestObject) (gen.StepRunGetResponseObject, error) {
|
||||
stepRun := ctx.Get("step-run").(*db.StepRunModel)
|
||||
|
||||
res, err := transformers.ToStepRun(stepRun)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not transform step run: %w", err)
|
||||
}
|
||||
|
||||
return gen.StepRunGet200JSONResponse(
|
||||
*res,
|
||||
), nil
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package stepruns
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
|
||||
"github.com/hatchet-dev/hatchet/api/v1/server/oas/apierrors"
|
||||
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
|
||||
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
|
||||
"github.com/hatchet-dev/hatchet/internal/datautils"
|
||||
"github.com/hatchet-dev/hatchet/internal/repository"
|
||||
"github.com/hatchet-dev/hatchet/internal/repository/prisma/db"
|
||||
"github.com/hatchet-dev/hatchet/internal/services/shared/tasktypes"
|
||||
"github.com/hatchet-dev/hatchet/internal/taskqueue"
|
||||
)
|
||||
|
||||
func (t *StepRunService) StepRunUpdateRerun(ctx echo.Context, request gen.StepRunUpdateRerunRequestObject) (gen.StepRunUpdateRerunResponseObject, error) {
|
||||
tenant := ctx.Get("tenant").(*db.TenantModel)
|
||||
stepRun := ctx.Get("step-run").(*db.StepRunModel)
|
||||
|
||||
// preflight check to make sure there's at least one worker to serve this request
|
||||
action := stepRun.Step().ActionID
|
||||
|
||||
tenSecAgo := time.Now().Add(-10 * time.Second)
|
||||
|
||||
workers, err := t.config.Repository.Worker().ListWorkers(tenant.ID, &repository.ListWorkersOpts{
|
||||
Action: &action,
|
||||
LastHeartbeatAfter: &tenSecAgo,
|
||||
})
|
||||
|
||||
if err != nil || len(workers) == 0 {
|
||||
return gen.StepRunUpdateRerun400JSONResponse(
|
||||
apierrors.NewAPIErrors("There are no workers available to execute this step run."),
|
||||
), nil
|
||||
}
|
||||
|
||||
// make sure input can be marshalled and unmarshalled to input type
|
||||
inputBytes, err := json.Marshal(request.Body.Input)
|
||||
|
||||
if err != nil {
|
||||
return gen.StepRunUpdateRerun400JSONResponse(
|
||||
apierrors.NewAPIErrors("Invalid input"),
|
||||
), nil
|
||||
}
|
||||
|
||||
data := &datautils.StepRunData{}
|
||||
|
||||
if err := json.Unmarshal(inputBytes, data); err != nil || data == nil {
|
||||
return gen.StepRunUpdateRerun400JSONResponse(
|
||||
apierrors.NewAPIErrors("Invalid input"),
|
||||
), nil
|
||||
}
|
||||
|
||||
// update step run
|
||||
_, err = t.config.Repository.StepRun().UpdateStepRun(tenant.ID, stepRun.ID, &repository.UpdateStepRunOpts{
|
||||
Input: inputBytes,
|
||||
Status: repository.StepRunStatusPtr(db.StepRunStatusPending),
|
||||
IsRerun: true,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not update step run: %w", err)
|
||||
}
|
||||
|
||||
// requeue the step run in the task queue
|
||||
jobRun, err := t.config.Repository.JobRun().GetJobRunById(tenant.ID, stepRun.JobRunID)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get job run: %w", err)
|
||||
}
|
||||
|
||||
// send a task to the taskqueue
|
||||
err = t.config.TaskQueue.AddTask(
|
||||
ctx.Request().Context(),
|
||||
taskqueue.JOB_PROCESSING_QUEUE,
|
||||
tasktypes.StepRunQueuedToTask(jobRun.Job(), stepRun),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not add step queued task to task queue: %w", err)
|
||||
}
|
||||
|
||||
stepRun, err = t.config.Repository.StepRun().GetStepRunById(tenant.ID, stepRun.ID)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get step run: %w", err)
|
||||
}
|
||||
|
||||
res, err := transformers.ToStepRun(stepRun)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not transform step run: %w", err)
|
||||
}
|
||||
|
||||
return gen.StepRunUpdateRerun200JSONResponse(
|
||||
*res,
|
||||
), nil
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package stepruns
|
||||
|
||||
import (
|
||||
"github.com/hatchet-dev/hatchet/internal/config/server"
|
||||
)
|
||||
|
||||
type StepRunService struct {
|
||||
config *server.ServerConfig
|
||||
}
|
||||
|
||||
func NewStepRunService(config *server.ServerConfig) *StepRunService {
|
||||
return &StepRunService{
|
||||
config: config,
|
||||
}
|
||||
}
|
||||
@@ -281,6 +281,11 @@ type ReplayEventRequest struct {
|
||||
EventIds []openapi_types.UUID `json:"eventIds"`
|
||||
}
|
||||
|
||||
// RerunStepRunRequest defines model for RerunStepRunRequest.
|
||||
type RerunStepRunRequest struct {
|
||||
Input map[string]interface{} `json:"input"`
|
||||
}
|
||||
|
||||
// Step defines model for Step.
|
||||
type Step struct {
|
||||
Action string `json:"action"`
|
||||
@@ -645,6 +650,9 @@ type TenantInviteCreateJSONRequestBody = CreateTenantInviteRequest
|
||||
// TenantInviteUpdateJSONRequestBody defines body for TenantInviteUpdate for application/json ContentType.
|
||||
type TenantInviteUpdateJSONRequestBody = UpdateTenantInviteRequest
|
||||
|
||||
// StepRunUpdateRerunJSONRequestBody defines body for StepRunUpdateRerun for application/json ContentType.
|
||||
type StepRunUpdateRerunJSONRequestBody = RerunStepRunRequest
|
||||
|
||||
// TenantInviteAcceptJSONRequestBody defines body for TenantInviteAccept for application/json ContentType.
|
||||
type TenantInviteAcceptJSONRequestBody = AcceptInviteRequest
|
||||
|
||||
@@ -701,6 +709,12 @@ type ServerInterface interface {
|
||||
// List tenant members
|
||||
// (GET /api/v1/tenants/{tenant}/members)
|
||||
TenantMemberList(ctx echo.Context, tenant openapi_types.UUID) error
|
||||
// Get step run
|
||||
// (GET /api/v1/tenants/{tenant}/step-runs/{step-run})
|
||||
StepRunGet(ctx echo.Context, tenant openapi_types.UUID, stepRun openapi_types.UUID) error
|
||||
// Rerun step run
|
||||
// (POST /api/v1/tenants/{tenant}/step-runs/{step-run}/rerun)
|
||||
StepRunUpdateRerun(ctx echo.Context, tenant openapi_types.UUID, stepRun openapi_types.UUID) error
|
||||
// Get workers
|
||||
// (GET /api/v1/tenants/{tenant}/worker)
|
||||
WorkerList(ctx echo.Context, tenant openapi_types.UUID) error
|
||||
@@ -1091,6 +1105,62 @@ func (w *ServerInterfaceWrapper) TenantMemberList(ctx echo.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// StepRunGet converts echo context to params.
|
||||
func (w *ServerInterfaceWrapper) StepRunGet(ctx echo.Context) error {
|
||||
var err error
|
||||
// ------------- Path parameter "tenant" -------------
|
||||
var tenant openapi_types.UUID
|
||||
|
||||
err = runtime.BindStyledParameterWithLocation("simple", false, "tenant", runtime.ParamLocationPath, ctx.Param("tenant"), &tenant)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter tenant: %s", err))
|
||||
}
|
||||
|
||||
// ------------- Path parameter "step-run" -------------
|
||||
var stepRun openapi_types.UUID
|
||||
|
||||
err = runtime.BindStyledParameterWithLocation("simple", false, "step-run", runtime.ParamLocationPath, ctx.Param("step-run"), &stepRun)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter step-run: %s", err))
|
||||
}
|
||||
|
||||
ctx.Set(BearerAuthScopes, []string{})
|
||||
|
||||
ctx.Set(CookieAuthScopes, []string{})
|
||||
|
||||
// Invoke the callback with all the unmarshaled arguments
|
||||
err = w.Handler.StepRunGet(ctx, tenant, stepRun)
|
||||
return err
|
||||
}
|
||||
|
||||
// StepRunUpdateRerun converts echo context to params.
|
||||
func (w *ServerInterfaceWrapper) StepRunUpdateRerun(ctx echo.Context) error {
|
||||
var err error
|
||||
// ------------- Path parameter "tenant" -------------
|
||||
var tenant openapi_types.UUID
|
||||
|
||||
err = runtime.BindStyledParameterWithLocation("simple", false, "tenant", runtime.ParamLocationPath, ctx.Param("tenant"), &tenant)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter tenant: %s", err))
|
||||
}
|
||||
|
||||
// ------------- Path parameter "step-run" -------------
|
||||
var stepRun openapi_types.UUID
|
||||
|
||||
err = runtime.BindStyledParameterWithLocation("simple", false, "step-run", runtime.ParamLocationPath, ctx.Param("step-run"), &stepRun)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter step-run: %s", err))
|
||||
}
|
||||
|
||||
ctx.Set(BearerAuthScopes, []string{})
|
||||
|
||||
ctx.Set(CookieAuthScopes, []string{})
|
||||
|
||||
// Invoke the callback with all the unmarshaled arguments
|
||||
err = w.Handler.StepRunUpdateRerun(ctx, tenant, stepRun)
|
||||
return err
|
||||
}
|
||||
|
||||
// WorkerList converts echo context to params.
|
||||
func (w *ServerInterfaceWrapper) WorkerList(ctx echo.Context) error {
|
||||
var err error
|
||||
@@ -1455,6 +1525,8 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
|
||||
router.DELETE(baseURL+"/api/v1/tenants/:tenant/invites/:tenant-invite", wrapper.TenantInviteDelete)
|
||||
router.PATCH(baseURL+"/api/v1/tenants/:tenant/invites/:tenant-invite", wrapper.TenantInviteUpdate)
|
||||
router.GET(baseURL+"/api/v1/tenants/:tenant/members", wrapper.TenantMemberList)
|
||||
router.GET(baseURL+"/api/v1/tenants/:tenant/step-runs/:step-run", wrapper.StepRunGet)
|
||||
router.POST(baseURL+"/api/v1/tenants/:tenant/step-runs/:step-run/rerun", wrapper.StepRunUpdateRerun)
|
||||
router.GET(baseURL+"/api/v1/tenants/:tenant/worker", wrapper.WorkerList)
|
||||
router.GET(baseURL+"/api/v1/tenants/:tenant/workflow-runs/:workflow-run", wrapper.WorkflowRunGet)
|
||||
router.GET(baseURL+"/api/v1/tenants/:tenant/workflows", wrapper.WorkflowList)
|
||||
@@ -1944,6 +2016,88 @@ func (response TenantMemberList403JSONResponse) VisitTenantMemberListResponse(w
|
||||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
type StepRunGetRequestObject struct {
|
||||
Tenant openapi_types.UUID `json:"tenant"`
|
||||
StepRun openapi_types.UUID `json:"step-run"`
|
||||
}
|
||||
|
||||
type StepRunGetResponseObject interface {
|
||||
VisitStepRunGetResponse(w http.ResponseWriter) error
|
||||
}
|
||||
|
||||
type StepRunGet200JSONResponse StepRun
|
||||
|
||||
func (response StepRunGet200JSONResponse) VisitStepRunGetResponse(w http.ResponseWriter) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(200)
|
||||
|
||||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
type StepRunGet400JSONResponse APIErrors
|
||||
|
||||
func (response StepRunGet400JSONResponse) VisitStepRunGetResponse(w http.ResponseWriter) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(400)
|
||||
|
||||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
type StepRunGet403JSONResponse APIErrors
|
||||
|
||||
func (response StepRunGet403JSONResponse) VisitStepRunGetResponse(w http.ResponseWriter) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(403)
|
||||
|
||||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
type StepRunGet404JSONResponse APIErrors
|
||||
|
||||
func (response StepRunGet404JSONResponse) VisitStepRunGetResponse(w http.ResponseWriter) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(404)
|
||||
|
||||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
type StepRunUpdateRerunRequestObject struct {
|
||||
Tenant openapi_types.UUID `json:"tenant"`
|
||||
StepRun openapi_types.UUID `json:"step-run"`
|
||||
Body *StepRunUpdateRerunJSONRequestBody
|
||||
}
|
||||
|
||||
type StepRunUpdateRerunResponseObject interface {
|
||||
VisitStepRunUpdateRerunResponse(w http.ResponseWriter) error
|
||||
}
|
||||
|
||||
type StepRunUpdateRerun200JSONResponse StepRun
|
||||
|
||||
func (response StepRunUpdateRerun200JSONResponse) VisitStepRunUpdateRerunResponse(w http.ResponseWriter) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(200)
|
||||
|
||||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
type StepRunUpdateRerun400JSONResponse APIErrors
|
||||
|
||||
func (response StepRunUpdateRerun400JSONResponse) VisitStepRunUpdateRerunResponse(w http.ResponseWriter) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(400)
|
||||
|
||||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
type StepRunUpdateRerun403JSONResponse APIErrors
|
||||
|
||||
func (response StepRunUpdateRerun403JSONResponse) VisitStepRunUpdateRerunResponse(w http.ResponseWriter) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(403)
|
||||
|
||||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
type WorkerListRequestObject struct {
|
||||
Tenant openapi_types.UUID `json:"tenant"`
|
||||
}
|
||||
@@ -2627,6 +2781,10 @@ type StrictServerInterface interface {
|
||||
|
||||
TenantMemberList(ctx echo.Context, request TenantMemberListRequestObject) (TenantMemberListResponseObject, error)
|
||||
|
||||
StepRunGet(ctx echo.Context, request StepRunGetRequestObject) (StepRunGetResponseObject, error)
|
||||
|
||||
StepRunUpdateRerun(ctx echo.Context, request StepRunUpdateRerunRequestObject) (StepRunUpdateRerunResponseObject, error)
|
||||
|
||||
WorkerList(ctx echo.Context, request WorkerListRequestObject) (WorkerListResponseObject, error)
|
||||
|
||||
WorkflowRunGet(ctx echo.Context, request WorkflowRunGetRequestObject) (WorkflowRunGetResponseObject, error)
|
||||
@@ -3054,6 +3212,64 @@ func (sh *strictHandler) TenantMemberList(ctx echo.Context, tenant openapi_types
|
||||
return nil
|
||||
}
|
||||
|
||||
// StepRunGet operation middleware
|
||||
func (sh *strictHandler) StepRunGet(ctx echo.Context, tenant openapi_types.UUID, stepRun openapi_types.UUID) error {
|
||||
var request StepRunGetRequestObject
|
||||
|
||||
request.Tenant = tenant
|
||||
request.StepRun = stepRun
|
||||
|
||||
handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
|
||||
return sh.ssi.StepRunGet(ctx, request.(StepRunGetRequestObject))
|
||||
}
|
||||
for _, middleware := range sh.middlewares {
|
||||
handler = middleware(handler, "StepRunGet")
|
||||
}
|
||||
|
||||
response, err := handler(ctx, request)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
} else if validResponse, ok := response.(StepRunGetResponseObject); ok {
|
||||
return validResponse.VisitStepRunGetResponse(ctx.Response())
|
||||
} else if response != nil {
|
||||
return fmt.Errorf("Unexpected response type: %T", response)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// StepRunUpdateRerun operation middleware
|
||||
func (sh *strictHandler) StepRunUpdateRerun(ctx echo.Context, tenant openapi_types.UUID, stepRun openapi_types.UUID) error {
|
||||
var request StepRunUpdateRerunRequestObject
|
||||
|
||||
request.Tenant = tenant
|
||||
request.StepRun = stepRun
|
||||
|
||||
var body StepRunUpdateRerunJSONRequestBody
|
||||
if err := ctx.Bind(&body); err != nil {
|
||||
return err
|
||||
}
|
||||
request.Body = &body
|
||||
|
||||
handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
|
||||
return sh.ssi.StepRunUpdateRerun(ctx, request.(StepRunUpdateRerunRequestObject))
|
||||
}
|
||||
for _, middleware := range sh.middlewares {
|
||||
handler = middleware(handler, "StepRunUpdateRerun")
|
||||
}
|
||||
|
||||
response, err := handler(ctx, request)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
} else if validResponse, ok := response.(StepRunUpdateRerunResponseObject); ok {
|
||||
return validResponse.VisitStepRunUpdateRerunResponse(ctx.Response())
|
||||
} else if response != nil {
|
||||
return fmt.Errorf("Unexpected response type: %T", response)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WorkerList operation middleware
|
||||
func (sh *strictHandler) WorkerList(ctx echo.Context, tenant openapi_types.UUID) error {
|
||||
var request WorkerListRequestObject
|
||||
@@ -3515,85 +3731,87 @@ func (sh *strictHandler) WorkflowVersionGetDefinition(ctx echo.Context, workflow
|
||||
// Base64 encoded, gzipped, json marshaled Swagger object
|
||||
var swaggerSpec = []string{
|
||||
|
||||
"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",
|
||||
"qAAA",
|
||||
"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",
|
||||
}
|
||||
|
||||
// GetSwagger returns the content of the embedded swagger specification file
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
apitokens "github.com/hatchet-dev/hatchet/api/v1/server/handlers/api-tokens"
|
||||
"github.com/hatchet-dev/hatchet/api/v1/server/handlers/events"
|
||||
"github.com/hatchet-dev/hatchet/api/v1/server/handlers/metadata"
|
||||
stepruns "github.com/hatchet-dev/hatchet/api/v1/server/handlers/step-runs"
|
||||
"github.com/hatchet-dev/hatchet/api/v1/server/handlers/tenants"
|
||||
"github.com/hatchet-dev/hatchet/api/v1/server/handlers/users"
|
||||
"github.com/hatchet-dev/hatchet/api/v1/server/handlers/workers"
|
||||
@@ -31,6 +32,7 @@ type apiService struct {
|
||||
*workers.WorkerService
|
||||
*metadata.MetadataService
|
||||
*apitokens.APITokenService
|
||||
*stepruns.StepRunService
|
||||
}
|
||||
|
||||
func newAPIService(config *server.ServerConfig) *apiService {
|
||||
@@ -42,6 +44,7 @@ func newAPIService(config *server.ServerConfig) *apiService {
|
||||
WorkerService: workers.NewWorkerService(config),
|
||||
MetadataService: metadata.NewMetadataService(config),
|
||||
APITokenService: apitokens.NewAPITokenService(config),
|
||||
StepRunService: stepruns.NewStepRunService(config),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,6 +130,16 @@ func (t *APIServer) Run(ctx context.Context) error {
|
||||
return workflowRun, workflowRun.TenantID, nil
|
||||
})
|
||||
|
||||
populatorMW.RegisterGetter("step-run", func(config *server.ServerConfig, parentId, id string) (result interface{}, uniqueParentId string, err error) {
|
||||
stepRun, err := config.Repository.StepRun().GetStepRunById(parentId, id)
|
||||
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
return stepRun, stepRun.TenantID, nil
|
||||
})
|
||||
|
||||
populatorMW.RegisterGetter("event", func(config *server.ServerConfig, parentId, id string) (result interface{}, uniqueParentId string, err error) {
|
||||
event, err := config.Repository.Event().GetEventById(id)
|
||||
|
||||
|
||||
@@ -83,6 +83,9 @@ func run(ch <-chan interface{}, events chan<- string) error {
|
||||
}, nil
|
||||
}).SetName("step-two"),
|
||||
worker.Fn(func(ctx worker.HatchetContext) (result *stepOutput, err error) {
|
||||
input := &userCreateEvent{}
|
||||
ctx.WorkflowInput(input)
|
||||
|
||||
step1Out := &stepOutput{}
|
||||
ctx.StepOutput("step-one", step1Out)
|
||||
|
||||
@@ -92,7 +95,7 @@ func run(ch <-chan interface{}, events chan<- string) error {
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
return &stepOutput{
|
||||
Message: "Step 3: has parents 1 and 2:" + step1Out.Message + ", " + step2Out.Message,
|
||||
Message: "Username was: " + input.Username + ", Step 3: has parents 1 and 2" + step1Out.Message + ", " + step2Out.Message,
|
||||
}, nil
|
||||
}).SetName("step-three").AddParents("step-one", "step-two"),
|
||||
worker.Fn(func(ctx worker.HatchetContext) (result *stepOutput, err error) {
|
||||
|
||||
@@ -14,7 +14,7 @@ export function CodeEditor({
|
||||
wrapLines = true,
|
||||
}: {
|
||||
code: string;
|
||||
setCode?: (code: string) => void;
|
||||
setCode?: (code: string | undefined) => void;
|
||||
language: string;
|
||||
className?: string;
|
||||
height?: string;
|
||||
@@ -112,6 +112,7 @@ export function CodeEditor({
|
||||
beforeMount={setEditorTheme}
|
||||
language={language}
|
||||
value={code}
|
||||
onChange={setCode}
|
||||
width={width || '100%'}
|
||||
height={height || '400px'}
|
||||
theme="pastels-on-dark"
|
||||
|
||||
@@ -28,6 +28,8 @@ import {
|
||||
ListAPITokensResponse,
|
||||
RejectInviteRequest,
|
||||
ReplayEventRequest,
|
||||
RerunStepRunRequest,
|
||||
StepRun,
|
||||
Tenant,
|
||||
TenantInvite,
|
||||
TenantInviteList,
|
||||
@@ -648,6 +650,42 @@ export class Api<SecurityDataType = unknown> extends HttpClient<SecurityDataType
|
||||
format: "json",
|
||||
...params,
|
||||
});
|
||||
/**
|
||||
* @description Get a step run by id
|
||||
*
|
||||
* @tags Step Run
|
||||
* @name StepRunGet
|
||||
* @summary Get step run
|
||||
* @request GET:/api/v1/tenants/{tenant}/step-runs/{step-run}
|
||||
* @secure
|
||||
*/
|
||||
stepRunGet = (tenant: string, stepRun: string, params: RequestParams = {}) =>
|
||||
this.request<StepRun, APIErrors>({
|
||||
path: `/api/v1/tenants/${tenant}/step-runs/${stepRun}`,
|
||||
method: "GET",
|
||||
secure: true,
|
||||
format: "json",
|
||||
...params,
|
||||
});
|
||||
/**
|
||||
* @description Reruns a step run
|
||||
*
|
||||
* @tags Step Run
|
||||
* @name StepRunUpdateRerun
|
||||
* @summary Rerun step run
|
||||
* @request POST:/api/v1/tenants/{tenant}/step-runs/{step-run}/rerun
|
||||
* @secure
|
||||
*/
|
||||
stepRunUpdateRerun = (tenant: string, stepRun: string, data: RerunStepRunRequest, params: RequestParams = {}) =>
|
||||
this.request<StepRun, APIErrors>({
|
||||
path: `/api/v1/tenants/${tenant}/step-runs/${stepRun}/rerun`,
|
||||
method: "POST",
|
||||
body: data,
|
||||
secure: true,
|
||||
type: ContentType.Json,
|
||||
format: "json",
|
||||
...params,
|
||||
});
|
||||
/**
|
||||
* @description Get all workers for a tenant
|
||||
*
|
||||
|
||||
@@ -570,3 +570,7 @@ export interface ListAPITokensResponse {
|
||||
pagination?: PaginationResponse;
|
||||
rows?: APIToken[];
|
||||
}
|
||||
|
||||
export interface RerunStepRunRequest {
|
||||
input: object;
|
||||
}
|
||||
|
||||
@@ -72,6 +72,12 @@ export const queries = createQueryKeyStore({
|
||||
queryFn: async () => (await api.workflowRunGet(tenant, workflowRun)).data,
|
||||
}),
|
||||
},
|
||||
stepRuns: {
|
||||
get: (tenant: string, stepRun: string) => ({
|
||||
queryKey: ['step-run:get', tenant, stepRun],
|
||||
queryFn: async () => (await api.stepRunGet(tenant, stepRun)).data,
|
||||
}),
|
||||
},
|
||||
events: {
|
||||
list: (tenant: string, query: ListEventQuery) => ({
|
||||
queryKey: ['event:list', tenant, query],
|
||||
|
||||
@@ -6,19 +6,30 @@ import { getFieldErrors } from './utils';
|
||||
|
||||
export function useApiError(props: {
|
||||
setFieldErrors?: Dispatch<SetStateAction<Record<string, string>>>;
|
||||
// if setErrors is passed, it will be used to pass the errors. otherwise,
|
||||
// it will use the global toast.
|
||||
setErrors?: (errors: string[]) => void;
|
||||
}): {
|
||||
handleApiError: (error: AxiosError) => void;
|
||||
} {
|
||||
const { toast } = useToast();
|
||||
|
||||
const handler = props.setErrors
|
||||
? props.setErrors
|
||||
: (errors: string[]) => {
|
||||
for (const error of errors) {
|
||||
toast({
|
||||
title: 'Error',
|
||||
description: error,
|
||||
duration: 5000,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleError = (error: AxiosError) => {
|
||||
if (error.response?.status) {
|
||||
if (error.response?.status >= 500) {
|
||||
toast({
|
||||
title: 'Error',
|
||||
description: 'An internal error occurred.',
|
||||
duration: 5000,
|
||||
});
|
||||
handler(['An internal error occurred.']);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -35,30 +46,27 @@ export function useApiError(props: {
|
||||
props.setFieldErrors(fieldErrors);
|
||||
}
|
||||
|
||||
if (props.setErrors) {
|
||||
const errors = Object.values(fieldErrors);
|
||||
props.setErrors(errors);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!apiErrors || !apiErrors.errors || apiErrors.errors.length === 0) {
|
||||
toast({
|
||||
title: 'Error',
|
||||
description: 'An internal error occurred.',
|
||||
duration: 5000,
|
||||
});
|
||||
handler(['An internal error occurred.']);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (const error of apiErrors.errors) {
|
||||
if (error.description) {
|
||||
toast({
|
||||
title: 'Error',
|
||||
description: error.description,
|
||||
duration: 5000,
|
||||
});
|
||||
}
|
||||
}
|
||||
handler(
|
||||
apiErrors.errors.map(
|
||||
(error) => error.description || 'An internal error occurred.',
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
+27
-7
@@ -1,11 +1,23 @@
|
||||
import { StepRun } from '@/lib/api';
|
||||
import { CodeEditor } from '@/components/ui/code-editor';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { Loading } from '@/components/ui/loading';
|
||||
|
||||
export function StepInputOutputSection({ stepRun }: { stepRun: StepRun }) {
|
||||
export function StepInputOutputSection({
|
||||
stepRun,
|
||||
onInputChanged,
|
||||
}: {
|
||||
stepRun: StepRun;
|
||||
onInputChanged?: (input: string) => void;
|
||||
}) {
|
||||
const input = stepRun.input || '{}';
|
||||
const output = stepRun.output || '{}';
|
||||
|
||||
const isLoading =
|
||||
stepRun?.status != 'SUCCEEDED' &&
|
||||
stepRun?.status != 'FAILED' &&
|
||||
stepRun?.status != 'CANCELLED';
|
||||
|
||||
return (
|
||||
<Tabs defaultValue="input" className="w-full">
|
||||
<TabsList className="grid w-full grid-cols-2">
|
||||
@@ -18,15 +30,23 @@ export function StepInputOutputSection({ stepRun }: { stepRun: StepRun }) {
|
||||
className="my-4"
|
||||
height="400px"
|
||||
code={JSON.stringify(JSON.parse(input), null, 2)}
|
||||
setCode={(code: string | undefined) => {
|
||||
if (onInputChanged && code) {
|
||||
onInputChanged(code);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</TabsContent>
|
||||
<TabsContent value="output">
|
||||
<CodeEditor
|
||||
language="json"
|
||||
className="my-4"
|
||||
height="400px"
|
||||
code={JSON.stringify(JSON.parse(output), null, 2)}
|
||||
/>
|
||||
{isLoading && <Loading />}
|
||||
{!isLoading && (
|
||||
<CodeEditor
|
||||
language="json"
|
||||
className="my-4"
|
||||
height="400px"
|
||||
code={JSON.stringify(JSON.parse(output), null, 2)}
|
||||
/>
|
||||
)}
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
);
|
||||
|
||||
@@ -5,10 +5,17 @@ import {
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '@/components/ui/dialog';
|
||||
import { StepRun, StepRunStatus } from '@/lib/api';
|
||||
import api, { StepRun, StepRunStatus, queries } from '@/lib/api';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { RunStatus } from '../../components/run-statuses';
|
||||
import { getTiming } from './step-run-node';
|
||||
import { StepInputOutputSection } from './step-run-input-output';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import invariant from 'tiny-invariant';
|
||||
import { useApiError } from '@/lib/hooks';
|
||||
import { useMutation, useQuery } from '@tanstack/react-query';
|
||||
import { ArrowPathIcon } from '@heroicons/react/24/outline';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
export function StepRunPlayground({
|
||||
stepRun,
|
||||
@@ -17,6 +24,77 @@ export function StepRunPlayground({
|
||||
stepRun: StepRun | null;
|
||||
setStepRun: (stepRun: StepRun | null) => void;
|
||||
}) {
|
||||
const [errors, setErrors] = useState<string[]>([]);
|
||||
|
||||
const { handleApiError } = useApiError({
|
||||
setErrors,
|
||||
});
|
||||
|
||||
const originalInput = JSON.stringify(
|
||||
JSON.parse(stepRun?.input || '{}'),
|
||||
null,
|
||||
2,
|
||||
);
|
||||
|
||||
const [stepInput, setStepInput] = useState(originalInput);
|
||||
|
||||
useEffect(() => {
|
||||
setStepInput(originalInput);
|
||||
}, [originalInput]);
|
||||
|
||||
invariant(stepRun?.tenantId, 'stepRun is required');
|
||||
|
||||
const getStepRunQuery = useQuery({
|
||||
...queries.stepRuns.get(stepRun?.tenantId, stepRun?.metadata.id),
|
||||
refetchInterval: (query) => {
|
||||
const data = query.state.data;
|
||||
|
||||
if (
|
||||
data?.status != 'SUCCEEDED' &&
|
||||
data?.status != 'FAILED' &&
|
||||
data?.status != 'CANCELLED'
|
||||
) {
|
||||
return 1000;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const rerunStepMutation = useMutation({
|
||||
mutationKey: [
|
||||
'step-run:update:rerun',
|
||||
stepRun?.tenantId,
|
||||
stepRun?.metadata.id,
|
||||
],
|
||||
mutationFn: async (input: object) => {
|
||||
invariant(stepRun?.tenantId, 'has tenantId');
|
||||
|
||||
const res = await api.stepRunUpdateRerun(
|
||||
stepRun?.tenantId,
|
||||
stepRun?.metadata.id,
|
||||
{
|
||||
input: input,
|
||||
},
|
||||
);
|
||||
|
||||
return res.data;
|
||||
},
|
||||
onMutate: () => {
|
||||
setErrors([]);
|
||||
},
|
||||
onSuccess: (stepRun: StepRun) => {
|
||||
setStepRun(stepRun);
|
||||
|
||||
getStepRunQuery.refetch();
|
||||
},
|
||||
onError: handleApiError,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (getStepRunQuery.data) {
|
||||
setStepRun(getStepRunQuery.data);
|
||||
}
|
||||
}, [getStepRunQuery.data, setStepRun]);
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={!!stepRun}
|
||||
@@ -42,21 +120,40 @@ export function StepRunPlayground({
|
||||
</DialogHeader>
|
||||
<div className="flex flex-row justify-between items-center">
|
||||
<div className="font-bold">Input</div>
|
||||
{/* <Button
|
||||
<Button
|
||||
className="w-fit"
|
||||
disabled={stepInput === originalInput || isLoading}
|
||||
disabled={rerunStepMutation.isPending}
|
||||
onClick={() => {
|
||||
setIsLoading(true);
|
||||
setStatus(StepRunStatus.RUNNING);
|
||||
const inputObj = JSON.parse(stepInput);
|
||||
rerunStepMutation.mutate(inputObj);
|
||||
}}
|
||||
>
|
||||
<ArrowPathIcon
|
||||
className={cn(isLoading ? 'rotate-180' : '', 'h-4 w-4 mr-2')}
|
||||
className={cn(
|
||||
rerunStepMutation.isPending ? 'rotate-180' : '',
|
||||
'h-4 w-4 mr-2',
|
||||
)}
|
||||
/>
|
||||
Rerun Step
|
||||
</Button> */}
|
||||
</Button>
|
||||
</div>
|
||||
{stepRun && <StepInputOutputSection stepRun={stepRun} />}
|
||||
{stepRun && (
|
||||
<StepInputOutputSection
|
||||
stepRun={stepRun}
|
||||
onInputChanged={(input: string) => {
|
||||
setStepInput(input);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{errors.length > 0 && (
|
||||
<div className="mt-4">
|
||||
{errors.map((error, index) => (
|
||||
<div key={index} className="text-red-500 text-sm">
|
||||
{error}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
|
||||
@@ -14,17 +14,39 @@ SET
|
||||
"requeueAfter" = COALESCE(sqlc.narg('requeueAfter')::timestamp, "requeueAfter"),
|
||||
"scheduleTimeoutAt" = COALESCE(sqlc.narg('scheduleTimeoutAt')::timestamp, "scheduleTimeoutAt"),
|
||||
"startedAt" = COALESCE(sqlc.narg('startedAt')::timestamp, "startedAt"),
|
||||
"finishedAt" = COALESCE(sqlc.narg('finishedAt')::timestamp, "finishedAt"),
|
||||
"finishedAt" = CASE
|
||||
-- if this is a rerun, we clear the finishedAt
|
||||
WHEN sqlc.narg('rerun')::boolean THEN NULL
|
||||
ELSE COALESCE(sqlc.narg('finishedAt')::timestamp, "finishedAt")
|
||||
END,
|
||||
"status" = CASE
|
||||
-- if this is a rerun, we permit status updates
|
||||
WHEN sqlc.narg('rerun')::boolean THEN COALESCE(sqlc.narg('status'), "status")
|
||||
-- Final states are final, cannot be updated
|
||||
WHEN "status" IN ('SUCCEEDED', 'FAILED', 'CANCELLED') THEN "status"
|
||||
ELSE COALESCE(sqlc.narg('status'), "status")
|
||||
END,
|
||||
"input" = COALESCE(sqlc.narg('input')::jsonb, "input"),
|
||||
"output" = COALESCE(sqlc.narg('output')::jsonb, "output"),
|
||||
"error" = COALESCE(sqlc.narg('error')::text, "error"),
|
||||
"cancelledAt" = COALESCE(sqlc.narg('cancelledAt')::timestamp, "cancelledAt"),
|
||||
"cancelledReason" = COALESCE(sqlc.narg('cancelledReason')::text, "cancelledReason")
|
||||
"output" = CASE
|
||||
-- if this is a rerun, we clear the output
|
||||
WHEN sqlc.narg('rerun')::boolean THEN NULL
|
||||
ELSE COALESCE(sqlc.narg('output')::jsonb, "output")
|
||||
END,
|
||||
"error" = CASE
|
||||
-- if this is a rerun, we clear the error
|
||||
WHEN sqlc.narg('rerun')::boolean THEN NULL
|
||||
ELSE COALESCE(sqlc.narg('error')::text, "error")
|
||||
END,
|
||||
"cancelledAt" = CASE
|
||||
-- if this is a rerun, we clear the cancelledAt
|
||||
WHEN sqlc.narg('rerun')::boolean THEN NULL
|
||||
ELSE COALESCE(sqlc.narg('cancelledAt')::timestamp, "cancelledAt")
|
||||
END,
|
||||
"cancelledReason" = CASE
|
||||
-- if this is a rerun, we clear the cancelledReason
|
||||
WHEN sqlc.narg('rerun')::boolean THEN NULL
|
||||
ELSE COALESCE(sqlc.narg('cancelledReason')::text, "cancelledReason")
|
||||
END
|
||||
WHERE
|
||||
"id" = @id::uuid AND
|
||||
"tenantId" = @tenantId::uuid
|
||||
|
||||
@@ -149,20 +149,42 @@ SET
|
||||
"requeueAfter" = COALESCE($1::timestamp, "requeueAfter"),
|
||||
"scheduleTimeoutAt" = COALESCE($2::timestamp, "scheduleTimeoutAt"),
|
||||
"startedAt" = COALESCE($3::timestamp, "startedAt"),
|
||||
"finishedAt" = COALESCE($4::timestamp, "finishedAt"),
|
||||
"finishedAt" = CASE
|
||||
-- if this is a rerun, we clear the finishedAt
|
||||
WHEN $4::boolean THEN NULL
|
||||
ELSE COALESCE($5::timestamp, "finishedAt")
|
||||
END,
|
||||
"status" = CASE
|
||||
-- if this is a rerun, we permit status updates
|
||||
WHEN $4::boolean THEN COALESCE($6, "status")
|
||||
-- Final states are final, cannot be updated
|
||||
WHEN "status" IN ('SUCCEEDED', 'FAILED', 'CANCELLED') THEN "status"
|
||||
ELSE COALESCE($5, "status")
|
||||
ELSE COALESCE($6, "status")
|
||||
END,
|
||||
"input" = COALESCE($6::jsonb, "input"),
|
||||
"output" = COALESCE($7::jsonb, "output"),
|
||||
"error" = COALESCE($8::text, "error"),
|
||||
"cancelledAt" = COALESCE($9::timestamp, "cancelledAt"),
|
||||
"cancelledReason" = COALESCE($10::text, "cancelledReason")
|
||||
"input" = COALESCE($7::jsonb, "input"),
|
||||
"output" = CASE
|
||||
-- if this is a rerun, we clear the output
|
||||
WHEN $4::boolean THEN NULL
|
||||
ELSE COALESCE($8::jsonb, "output")
|
||||
END,
|
||||
"error" = CASE
|
||||
-- if this is a rerun, we clear the error
|
||||
WHEN $4::boolean THEN NULL
|
||||
ELSE COALESCE($9::text, "error")
|
||||
END,
|
||||
"cancelledAt" = CASE
|
||||
-- if this is a rerun, we clear the cancelledAt
|
||||
WHEN $4::boolean THEN NULL
|
||||
ELSE COALESCE($10::timestamp, "cancelledAt")
|
||||
END,
|
||||
"cancelledReason" = CASE
|
||||
-- if this is a rerun, we clear the cancelledReason
|
||||
WHEN $4::boolean THEN NULL
|
||||
ELSE COALESCE($11::text, "cancelledReason")
|
||||
END
|
||||
WHERE
|
||||
"id" = $11::uuid AND
|
||||
"tenantId" = $12::uuid
|
||||
"id" = $12::uuid AND
|
||||
"tenantId" = $13::uuid
|
||||
RETURNING "StepRun".id, "StepRun"."createdAt", "StepRun"."updatedAt", "StepRun"."deletedAt", "StepRun"."tenantId", "StepRun"."jobRunId", "StepRun"."stepId", "StepRun"."order", "StepRun"."workerId", "StepRun"."tickerId", "StepRun".status, "StepRun".input, "StepRun".output, "StepRun"."requeueAfter", "StepRun"."scheduleTimeoutAt", "StepRun".error, "StepRun"."startedAt", "StepRun"."finishedAt", "StepRun"."timeoutAt", "StepRun"."cancelledAt", "StepRun"."cancelledReason", "StepRun"."cancelledError"
|
||||
`
|
||||
|
||||
@@ -170,6 +192,7 @@ type UpdateStepRunParams struct {
|
||||
RequeueAfter pgtype.Timestamp `json:"requeueAfter"`
|
||||
ScheduleTimeoutAt pgtype.Timestamp `json:"scheduleTimeoutAt"`
|
||||
StartedAt pgtype.Timestamp `json:"startedAt"`
|
||||
Rerun pgtype.Bool `json:"rerun"`
|
||||
FinishedAt pgtype.Timestamp `json:"finishedAt"`
|
||||
Status NullStepRunStatus `json:"status"`
|
||||
Input []byte `json:"input"`
|
||||
@@ -186,6 +209,7 @@ func (q *Queries) UpdateStepRun(ctx context.Context, db DBTX, arg UpdateStepRunP
|
||||
arg.RequeueAfter,
|
||||
arg.ScheduleTimeoutAt,
|
||||
arg.StartedAt,
|
||||
arg.Rerun,
|
||||
arg.FinishedAt,
|
||||
arg.Status,
|
||||
arg.Input,
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
"github.com/rs/zerolog"
|
||||
|
||||
@@ -295,6 +296,10 @@ func getUpdateParams(
|
||||
updateParams = dbsqlc.UpdateStepRunParams{
|
||||
ID: pgStepRunId,
|
||||
Tenantid: pgTenantId,
|
||||
Rerun: pgtype.Bool{
|
||||
Valid: true,
|
||||
Bool: opts.IsRerun,
|
||||
},
|
||||
}
|
||||
|
||||
if opts.Output != nil {
|
||||
|
||||
@@ -27,6 +27,8 @@ type ListStepRunsOpts struct {
|
||||
}
|
||||
|
||||
type UpdateStepRunOpts struct {
|
||||
IsRerun bool
|
||||
|
||||
RequeueAfter *time.Time
|
||||
|
||||
ScheduleTimeoutAt *time.Time
|
||||
|
||||
@@ -473,50 +473,54 @@ func (ec *JobsControllerImpl) queueStepRun(ctx context.Context, tenantId, stepId
|
||||
updateStepOpts.ScheduleTimeoutAt = &scheduleTimeoutAt
|
||||
}
|
||||
|
||||
lookupDataModel, ok := stepRun.JobRun().LookupData()
|
||||
// If the step run input is not set, then we should set it. This will be set upstream if we've rerun
|
||||
// the step run manually with new inputs. It will not be set when the step is automatically queued.
|
||||
if in, ok := stepRun.Input(); !ok || string(json.RawMessage(in)) == "{}" {
|
||||
lookupDataModel, ok := stepRun.JobRun().LookupData()
|
||||
|
||||
if ok && lookupDataModel != nil {
|
||||
data, ok := lookupDataModel.Data()
|
||||
if ok && lookupDataModel != nil {
|
||||
data, ok := lookupDataModel.Data()
|
||||
|
||||
if !ok {
|
||||
return fmt.Errorf("job run has no lookup data")
|
||||
}
|
||||
if !ok {
|
||||
return fmt.Errorf("job run has no lookup data")
|
||||
}
|
||||
|
||||
lookupData := &datautils.JobRunLookupData{}
|
||||
lookupData := &datautils.JobRunLookupData{}
|
||||
|
||||
err := datautils.FromJSONType(&data, lookupData)
|
||||
err := datautils.FromJSONType(&data, lookupData)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not get job run lookup data: %w", err)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not get job run lookup data: %w", err)
|
||||
}
|
||||
|
||||
// input data is the triggering event data and any parent step data
|
||||
inputData := datautils.StepRunData{
|
||||
Input: lookupData.Input,
|
||||
TriggeredBy: lookupData.TriggeredBy,
|
||||
Parents: map[string]datautils.StepData{},
|
||||
}
|
||||
// input data is the triggering event data and any parent step data
|
||||
inputData := datautils.StepRunData{
|
||||
Input: lookupData.Input,
|
||||
TriggeredBy: lookupData.TriggeredBy,
|
||||
Parents: map[string]datautils.StepData{},
|
||||
}
|
||||
|
||||
// add all parents to the input data
|
||||
for _, parent := range stepRun.Parents() {
|
||||
readableId, ok := parent.Step().ReadableID()
|
||||
// add all parents to the input data
|
||||
for _, parent := range stepRun.Parents() {
|
||||
readableId, ok := parent.Step().ReadableID()
|
||||
|
||||
if ok && readableId != "" {
|
||||
parentData, exists := lookupData.Steps[readableId]
|
||||
if ok && readableId != "" {
|
||||
parentData, exists := lookupData.Steps[readableId]
|
||||
|
||||
if exists {
|
||||
inputData.Parents[readableId] = parentData
|
||||
if exists {
|
||||
inputData.Parents[readableId] = parentData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inputDataBytes, err := json.Marshal(inputData)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not convert input data to json: %w", err)
|
||||
}
|
||||
|
||||
updateStepOpts.Input = inputDataBytes
|
||||
}
|
||||
|
||||
inputDataBytes, err := json.Marshal(inputData)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not convert input data to json: %w", err)
|
||||
}
|
||||
|
||||
updateStepOpts.Input = inputDataBytes
|
||||
}
|
||||
|
||||
// begin transaction and make sure step run is in a pending status
|
||||
@@ -542,7 +546,6 @@ func (ec *JobsControllerImpl) scheduleStepRun(ctx context.Context, tenantId, ste
|
||||
ctx, span := telemetry.NewSpan(ctx, "schedule-step-run")
|
||||
defer span.End()
|
||||
|
||||
// indicate that the step run is pending assignment
|
||||
stepRun, err := ec.repo.StepRun().GetStepRunById(tenantId, stepRunId)
|
||||
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user