Skip to content

Commit

Permalink
feat: add explict type for tasks
Browse files Browse the repository at this point in the history
  • Loading branch information
alexec committed Jan 15, 2025
1 parent 4f8e959 commit febda7f
Show file tree
Hide file tree
Showing 11 changed files with 135 additions and 11 deletions.
17 changes: 17 additions & 0 deletions docs/reference/workflow-defs-task-properties-type.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# type Schema

```txt
https://github.com/kitproj/kit/internal/types/workflow#/$defs/Task/properties/type
```

Type is the type of the task: "service" or "job". If omitted, if there are ports, it's a service, otherwise it's a job.
This is only needed when you have service that does not listen on ports.
Services are running in the background.

| Abstract | Extensible | Status | Identifiable | Custom Properties | Additional Properties | Access Restrictions | Defined In |
| :------------------ | :--------- | :------------- | :---------------------- | :---------------- | :-------------------- | :------------------ | :------------------------------------------------------------------------------ |
| Can be instantiated | No | Unknown status | Unknown identifiability | Forbidden | Allowed | none | [workflow.schema.json\*](../../out/workflow.schema.json "open original schema") |

## type Type

`string` ([type](workflow-defs-task-properties-type.md))
21 changes: 21 additions & 0 deletions docs/reference/workflow-defs-task.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ A task is a container or a command to run.

| Property | Type | Required | Nullable | Defined by |
| :---------------------------------- | :-------- | :------- | :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [type](#type) | `string` | Optional | cannot be null | [Untitled schema](workflow-defs-task-properties-type.md "https://github.com/kitproj/kit/internal/types/workflow#/$defs/Task/properties/type") |
| [log](#log) | `string` | Optional | cannot be null | [Untitled schema](workflow-defs-task-properties-log.md "https://github.com/kitproj/kit/internal/types/workflow#/$defs/Task/properties/log") |
| [image](#image) | `string` | Optional | cannot be null | [Untitled schema](workflow-defs-task-properties-image.md "https://github.com/kitproj/kit/internal/types/workflow#/$defs/Task/properties/image") |
| [imagePullPolicy](#imagepullpolicy) | `string` | Optional | cannot be null | [Untitled schema](workflow-defs-task-properties-imagepullpolicy.md "https://github.com/kitproj/kit/internal/types/workflow#/$defs/Task/properties/imagePullPolicy") |
Expand All @@ -42,6 +43,26 @@ A task is a container or a command to run.
| [targets](#targets) | `array` | Optional | cannot be null | [Untitled schema](workflow-defs-strings.md "https://github.com/kitproj/kit/internal/types/workflow#/$defs/Task/properties/targets") |
| [restartPolicy](#restartpolicy) | `string` | Optional | cannot be null | [Untitled schema](workflow-defs-task-properties-restartpolicy.md "https://github.com/kitproj/kit/internal/types/workflow#/$defs/Task/properties/restartPolicy") |

## type

Type is the type of the task: "service" or "job". If omitted, if there are ports, it's a service, otherwise it's a job.
This is only needed when you have service that does not listen on ports.
Services are running in the background.

`type`

* is optional

* Type: `string` ([type](workflow-defs-task-properties-type.md))

* cannot be null

* defined in: [Untitled schema](workflow-defs-task-properties-type.md "https://github.com/kitproj/kit/internal/types/workflow#/$defs/Task/properties/type")

### type Type

`string` ([type](workflow-defs-task-properties-type.md))

## log

Where to log the output of the task. E.g. if the task is verbose. Defaults to /dev/stdout. Maybe a file, or /dev/null.
Expand Down
21 changes: 21 additions & 0 deletions docs/reference/workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,7 @@ Reference this group by using

| Property | Type | Required | Nullable | Defined by |
| :---------------------------------- | :-------- | :------- | :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [type](#type) | `string` | Optional | cannot be null | [Untitled schema](workflow-defs-task-properties-type.md "https://github.com/kitproj/kit/internal/types/workflow#/$defs/Task/properties/type") |
| [log](#log) | `string` | Optional | cannot be null | [Untitled schema](workflow-defs-task-properties-log.md "https://github.com/kitproj/kit/internal/types/workflow#/$defs/Task/properties/log") |
| [image](#image) | `string` | Optional | cannot be null | [Untitled schema](workflow-defs-task-properties-image.md "https://github.com/kitproj/kit/internal/types/workflow#/$defs/Task/properties/image") |
| [imagePullPolicy](#imagepullpolicy) | `string` | Optional | cannot be null | [Untitled schema](workflow-defs-task-properties-imagepullpolicy.md "https://github.com/kitproj/kit/internal/types/workflow#/$defs/Task/properties/imagePullPolicy") |
Expand All @@ -415,6 +416,26 @@ Reference this group by using
| [targets](#targets) | `array` | Optional | cannot be null | [Untitled schema](workflow-defs-strings.md "https://github.com/kitproj/kit/internal/types/workflow#/$defs/Task/properties/targets") |
| [restartPolicy](#restartpolicy) | `string` | Optional | cannot be null | [Untitled schema](workflow-defs-task-properties-restartpolicy.md "https://github.com/kitproj/kit/internal/types/workflow#/$defs/Task/properties/restartPolicy") |

### type

Type is the type of the task: "service" or "job". If omitted, if there are ports, it's a service, otherwise it's a job.
This is only needed when you have service that does not listen on ports.
Services are running in the background.

`type`

* is optional

* Type: `string` ([type](workflow-defs-task-properties-type.md))

* cannot be null

* defined in: [Untitled schema](workflow-defs-task-properties-type.md "https://github.com/kitproj/kit/internal/types/workflow#/$defs/Task/properties/type")

#### type Type

`string` ([type](workflow-defs-task-properties-type.md))

### log

Where to log the output of the task. E.g. if the task is verbose. Defaults to /dev/stdout. Maybe a file, or /dev/null.
Expand Down
4 changes: 2 additions & 2 deletions internal/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ func RunSubgraph(
anyJobFailed := false
numJobsSucceeded := 0
for _, node := range subgraph.Nodes {
if node.task.IsService() {
if node.task.GetType() == types.TaskTypeService {
anyServices = true
}
if node.phase == "failed" {
Expand Down Expand Up @@ -307,7 +307,7 @@ func RunSubgraph(
go probeLoop(ctx, *probe, readyFunc)
}

if t.IsService() {
if t.GetType() == types.TaskTypeService && t.GetReadinessProbe() != nil {
setNodeStatus(node, "starting", "")
} else {
// non a service, must be a job
Expand Down
31 changes: 31 additions & 0 deletions internal/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,37 @@ sleep 30

})

t.Run("Service without ports is running", func(t *testing.T) {
ctx, cancel, logger, buffer := setup(t)
defer cancel()

wf := &types.Workflow{
Tasks: map[string]types.Task{
"service": {Command: []string{"sleep", "30"}, Type: types.TaskTypeService},
},
}
wg := &sync.WaitGroup{}
wg.Add(1)
go func() {
defer wg.Done()
err := RunSubgraph(
ctx,
cancel,
logger,
wf,
[]string{"service"},
nil,
)
assert.NoError(t, err)
}()

sleep(t)
cancel()

wg.Wait()

assert.Contains(t, buffer.String(), "[service] (running)")
})
}

func sleep(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion internal/task_node.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ type TaskNode struct {
}

func (n TaskNode) blocked() bool {
if n.task.IsService() {
if n.task.GetType() == types.TaskTypeService {
// skipped services are succeeded
return n.phase != "running" && n.phase != "succeeded"
} else {
Expand Down
15 changes: 13 additions & 2 deletions internal/types/task.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ func (t *Task) HasMutex() bool {

// A task is a container or a command to run.
type Task struct {
// Type is the type of the task: "service" or "job". If omitted, if there are ports, it's a service, otherwise it's a job.
// This is only needed when you have service that does not listen on ports.
// Services are running in the background.
Type TaskType `json:"type,omitempty"`
// Where to log the output of the task. E.g. if the task is verbose. Defaults to /dev/stdout. Maybe a file, or /dev/null.
Log string `json:"log,omitempty"`
// Either the container image to run, or a directory containing a Dockerfile. If omitted, the process runs on the host.
Expand Down Expand Up @@ -165,6 +169,13 @@ func (t *Task) Skip() bool {
return oldestTarget.After(youngestSource)
}

func (t *Task) IsService() bool {
return len(t.Ports) > 0 || t.LivenessProbe != nil || t.ReadinessProbe != nil
func (t *Task) GetType() TaskType {
if t.Type != "" {
return t.Type
}
if len(t.Ports) > 0 || t.LivenessProbe != nil || t.ReadinessProbe != nil {
return TaskTypeService
}
return TaskTypeJob

}
14 changes: 9 additions & 5 deletions internal/types/task_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,25 @@ func TestTask_AllTargetsExist(t *testing.T) {
}
}

func TestTask_IsService(t *testing.T) {
func TestTask_GetType(t *testing.T) {
t.Run("Defined", func(t *testing.T) {
task := &Task{Type: TaskTypeService}
assert.Equal(t, TaskTypeService, task.GetType())
})
t.Run("Job", func(t *testing.T) {
task := &Task{}
assert.False(t, task.IsService())
assert.Equal(t, TaskTypeJob, task.GetType())
})
t.Run("Ports", func(t *testing.T) {
task := &Task{Ports: []Port{{}}}
assert.True(t, task.IsService())
assert.Equal(t, TaskTypeService, task.GetType())
})
t.Run("LivenessProbe", func(t *testing.T) {
task := &Task{LivenessProbe: &Probe{}}
assert.True(t, task.IsService())
assert.Equal(t, TaskTypeService, task.GetType())
})
t.Run("ReadinessProbe", func(t *testing.T) {
task := &Task{ReadinessProbe: &Probe{}}
assert.True(t, task.IsService())
assert.Equal(t, TaskTypeService, task.GetType())
})
}
8 changes: 8 additions & 0 deletions internal/types/task_type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package types

type TaskType string

const (
TaskTypeJob TaskType = "job"
TaskTypeService TaskType = "service"
)
5 changes: 5 additions & 0 deletions schema/workflow.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,11 @@
},
"Task": {
"properties": {
"type": {
"type": "string",
"title": "type",
"description": "Type is the type of the task: \"service\" or \"job\". If omitted, if there are ports, it's a service, otherwise it's a job.\nThis is only needed when you have service that does not listen on ports.\nServices are running in the background."
},
"log": {
"type": "string",
"title": "log",
Expand Down
8 changes: 7 additions & 1 deletion tasks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,14 @@ tasks:
set -eux
echo "hello world"
sleep 5
service:
type: service
sh: |
set -eux
echo "hello world"
sleep 10
up:
dependencies: go-demo docker script k8s
dependencies: go-demo script k8s service
terminationGracePeriodSeconds: 3
volumes:
- hostPath:
Expand Down

0 comments on commit febda7f

Please sign in to comment.