StartRun transitions one claimed or starting run into active execution.
(ctx context.Context, runID string, req StartRun, actor ActorContext)
| 1949 | |
| 1950 | // StartRun transitions one claimed or starting run into active execution. |
| 1951 | func (m *Service) StartRun(ctx context.Context, runID string, req StartRun, actor ActorContext) (*Run, error) { |
| 1952 | if err := requireWriteAuthority(actor); err != nil { |
| 1953 | return nil, err |
| 1954 | } |
| 1955 | |
| 1956 | normalizedReq, err := normalizeStartRun(req) |
| 1957 | if err != nil { |
| 1958 | return nil, err |
| 1959 | } |
| 1960 | if err := requireLifecycleIdempotency(actor, normalizedReq.IdempotencyKey, "start_run"); err != nil { |
| 1961 | return nil, err |
| 1962 | } |
| 1963 | |
| 1964 | run, taskRecord, err := m.loadRunWithTask(ctx, runID) |
| 1965 | if err != nil { |
| 1966 | return nil, err |
| 1967 | } |
| 1968 | if err := m.ensureTaskExecutable(ctx, taskRecord); err != nil { |
| 1969 | return nil, err |
| 1970 | } |
| 1971 | if err := m.validateRunChannelUsable(ctx, taskRecord, run, actor, "start"); err != nil { |
| 1972 | return nil, err |
| 1973 | } |
| 1974 | |
| 1975 | switch run.Status.Normalize() { |
| 1976 | case TaskRunStatusClaimed: |
| 1977 | var failedRun *Run |
| 1978 | run, failedRun, err = m.transitionClaimedRunToStarting(ctx, taskRecord, run, actor) |
| 1979 | if err != nil { |
| 1980 | if failedRun != nil { |
| 1981 | return failedRun, err |
| 1982 | } |
| 1983 | return nil, err |
| 1984 | } |
| 1985 | case TaskRunStatusStarting: |
| 1986 | if err := validateRunningSessionBinding(run); err != nil { |
| 1987 | return nil, err |
| 1988 | } |
| 1989 | default: |
| 1990 | return nil, requireRunTransition(run, TaskRunStatusRunning) |
| 1991 | } |
| 1992 | |
| 1993 | lifecycleCtx := taskRunLifecycleContext(ctx) |
| 1994 | run.Status = TaskRunStatusRunning |
| 1995 | run.StartedAt = m.now().UTC() |
| 1996 | if err := m.store.UpdateTaskRun(lifecycleCtx, run); err != nil { |
| 1997 | return nil, err |
| 1998 | } |
| 1999 | |
| 2000 | reconciledTask, err := m.reconcileTaskCascade(lifecycleCtx, run.TaskID) |
| 2001 | if err != nil { |
| 2002 | return nil, err |
| 2003 | } |
| 2004 | if err := m.recordTaskEvent(lifecycleCtx, run.TaskID, run.ID, taskEventRunStarted, actor, runTransitionPayload{ |
| 2005 | Status: run.Status, |
| 2006 | TaskStatus: reconciledTask.Status, |
| 2007 | SessionID: run.SessionID, |
| 2008 | }); err != nil { |
nothing calls this directly
no test coverage detected