mirror of
https://github.com/harness/drone.git
synced 2025-05-07 12:11:12 +08:00
144 lines
3.7 KiB
Go
144 lines
3.7 KiB
Go
package canceler
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/harness/gitness/internal/pipeline/scheduler"
|
|
"github.com/harness/gitness/internal/sse"
|
|
"github.com/harness/gitness/internal/store"
|
|
"github.com/harness/gitness/types"
|
|
"github.com/harness/gitness/types/enum"
|
|
|
|
"github.com/rs/zerolog/log"
|
|
)
|
|
|
|
type service struct {
|
|
executionStore store.ExecutionStore
|
|
sseStreamer sse.Streamer
|
|
repoStore store.RepoStore
|
|
scheduler scheduler.Scheduler
|
|
stageStore store.StageStore
|
|
stepStore store.StepStore
|
|
}
|
|
|
|
// Canceler cancels a build.
|
|
type Canceler interface {
|
|
// Cancel cancels the provided execution.
|
|
Cancel(ctx context.Context, repo *types.Repository, execution *types.Execution) error
|
|
}
|
|
|
|
// New returns a cancellation service that encapsulates
|
|
// all cancellation operations.
|
|
func New(
|
|
executionStore store.ExecutionStore,
|
|
sseStreamer sse.Streamer,
|
|
repoStore store.RepoStore,
|
|
scheduler scheduler.Scheduler,
|
|
stageStore store.StageStore,
|
|
stepStore store.StepStore,
|
|
) Canceler {
|
|
return &service{
|
|
executionStore: executionStore,
|
|
sseStreamer: sseStreamer,
|
|
repoStore: repoStore,
|
|
scheduler: scheduler,
|
|
stageStore: stageStore,
|
|
stepStore: stepStore,
|
|
}
|
|
}
|
|
|
|
func (s *service) Cancel(ctx context.Context, repo *types.Repository, execution *types.Execution) error {
|
|
log := log.With().
|
|
Int64("execution.id", execution.ID).
|
|
Str("execution.status", string(execution.Status)).
|
|
Str("execution.Ref", execution.Ref).
|
|
Logger()
|
|
|
|
// do not cancel the build if the build status is
|
|
// complete. only cancel the build if the status is
|
|
// running or pending.
|
|
switch execution.Status {
|
|
case enum.CIStatusPending, enum.CIStatusRunning:
|
|
default:
|
|
return nil
|
|
}
|
|
|
|
// update the build status to killed. if the update fails
|
|
// due to an optimistic lock error it means the build has
|
|
// already started, and should now be ignored.
|
|
now := time.Now().UnixMilli()
|
|
execution.Status = enum.CIStatusKilled
|
|
execution.Finished = now
|
|
if execution.Started == 0 {
|
|
execution.Started = now
|
|
}
|
|
|
|
err := s.executionStore.Update(ctx, execution)
|
|
if err != nil {
|
|
return fmt.Errorf("could not update execution status to canceled: %w", err)
|
|
}
|
|
|
|
stages, err := s.stageStore.ListWithSteps(ctx, execution.ID)
|
|
if err != nil {
|
|
return fmt.Errorf("could not list stages with steps: %w", err)
|
|
}
|
|
|
|
// update the status of all steps to indicate they
|
|
// were killed or skipped.
|
|
for _, stage := range stages {
|
|
if stage.Status.IsDone() {
|
|
continue
|
|
}
|
|
if stage.Started != 0 {
|
|
stage.Status = enum.CIStatusKilled
|
|
} else {
|
|
stage.Status = enum.CIStatusSkipped
|
|
stage.Started = now
|
|
}
|
|
stage.Stopped = now
|
|
err := s.stageStore.Update(ctx, stage)
|
|
if err != nil {
|
|
log.Debug().Err(err).
|
|
Int64("stage.number", stage.Number).
|
|
Msg("canceler: cannot update stage status")
|
|
}
|
|
|
|
// update the status of all steps to indicate they
|
|
// were killed or skipped.
|
|
for _, step := range stage.Steps {
|
|
if step.Status.IsDone() {
|
|
continue
|
|
}
|
|
if step.Started != 0 {
|
|
step.Status = enum.CIStatusKilled
|
|
} else {
|
|
step.Status = enum.CIStatusSkipped
|
|
step.Started = now
|
|
}
|
|
step.Stopped = now
|
|
step.ExitCode = 130
|
|
err := s.stepStore.Update(ctx, step)
|
|
if err != nil {
|
|
log.Debug().Err(err).
|
|
Int64("stage.number", stage.Number).
|
|
Int64("step.number", step.Number).
|
|
Msg("canceler: cannot update step status")
|
|
}
|
|
}
|
|
}
|
|
|
|
execution.Stages = stages
|
|
log.Info().Msg("canceler: successfully cancelled build")
|
|
|
|
// trigger a SSE to notify subscribers that
|
|
// the execution was cancelled.
|
|
err = s.sseStreamer.Publish(ctx, repo.ParentID, enum.SSETypeExecutionCanceled, execution)
|
|
if err != nil {
|
|
log.Debug().Err(err).Msg("canceler: failed to publish server-sent event")
|
|
}
|
|
|
|
return nil
|
|
}
|