# Tasks

The fundamental unit of work in Hatchet is a **task**. At its most basic level, a task is just a function. You can invoke a task on its own (a "standalone" task), compose tasks into a [DAG workflow](/v1/patterns/directed-acyclic-graphs), or use [durable task composition](/v1/child-spawning) to spawn child tasks at runtime.

Every task you invoke is **durable** - Hatchet persists it, its state, and its results even after it finishes running.

## Defining a task

A task needs a name and a function. The function accepts an [input](#input-and-output) and a [context](#the-context-object).

#### Python

```python
class SimpleInput(BaseModel):
    message: str


class SimpleOutput(BaseModel):
    transformed_message: str


# Declare the task to run
@hatchet.task(name="first-task", input_validator=SimpleInput)
def first_task(input: SimpleInput, ctx: Context) -> SimpleOutput:
    print("first-task task called")

    return SimpleOutput(transformed_message=input.message.lower())
```

#### Typescript

```typescript
import { hatchet } from '../hatchet-client';

// (optional) Define the input type for the workflow
export type SimpleInput = {
  Message: string;
};

export const simple = hatchet.task({
  name: 'simple',
  retries: 3,
  fn: async (input: SimpleInput) => {
    return {
      TransformedMessage: input.Message.toLowerCase(),
    };
  },
});
```

#### Go

```go
type SimpleInput struct {
	Message string `json:"message"`
}

type SimpleOutput struct {
	Result string `json:"result"`
}

task := client.NewStandaloneTask("process-message", func(ctx hatchet.Context, input SimpleInput) (SimpleOutput, error) {
	return SimpleOutput{
		Result: "Processed: " + input.Message,
	}, nil
})
```

#### Ruby

```ruby
FIRST_TASK = HATCHET.task(name: "first-task") do |input, ctx|
  puts "first-task called"
  { "transformed_message" => input["message"].downcase }
end
```

## Input and output

Every task receives an **input** - a JSON-serializable object passed when the task is triggered. The value that is returned from the task becomes the task's **output**, which callers receive when they await the result of the task.

Hatchet's SDKs support type-checked and runtime-validated input and output types for tasks, so that you can integrate your Hatchet tasks into your codebase in a type-safe and predictable way that provides you all of the guarantees you get from, for example, replacing the Hatchet task run with a local function call.

You can refer to the [examples above](#defining-a-task) to see how to provide validators for task inputs and outputs.

## The context object

In addition to input and output payloads, every task receives a **context**. The context provides Hatchet-related information that might be useful to the execution of the task at runtime. For instance, you might access the workflow run ID, the task run ID, or the retry count from the context and have your task's application logic do something with those values.

The context also provides helper methods for interacting with a number of Hatchet's features, such as [managing cancellations](/v1/cancellation), [refreshing timeouts](/v1/timeouts#refreshing-timeouts), [pushing stream events](/v1/streaming#pushing-stream-events) and more.

#### Python

See the [Python SDK reference](/reference/python/context) for more details

#### Typescript

See the [TypeScript SDK reference](/reference/typescript/Context) for more
details

#### Go

See the [Go SDK
reference](https://pkg.go.dev/github.com/hatchet-dev/hatchet/sdks/go#Context)
for more details

#### Ruby

Ruby SDK reference coming soon! For now, see the [Python SDK
reference](/reference/python/context) to get a sense of what's available.

## Configuration

Tasks can be configured to handle common problems in distributed systems. For example, you might want to automatically retry a task when an external API returns a transient error, or limit how many instances of a task run at the same time to avoid overwhelming a downstream service.

Concept, What it does

[Retries](/v1/retry-policies), Retry the task on failure, with optional backoff.
[Timeouts](/v1/timeouts), Limit how long a task may wait to be scheduled or to run.
[Concurrency](/v1/concurrency), Distribute load fairly between your customers.
[Rate limits](/v1/rate-limits), Throttle task execution over a time window.
[Priority](/v1/priority), Influence scheduling order relative to other queued tasks.
[Worker affinity](/v1/advanced-assignment/worker-affinity), Prefer or require specific workers for this task.

## How tasks execute on workers

Tasks don't run on their own. [Workers](/v1/workers) execute them. A worker is a long-running process that registers one or more tasks with Hatchet. When you trigger a task, Hatchet places it in a queue and assigns it to an available worker that has registered that task. When a task completes, the Hatchet SDK running on the worker sends the result back to Hatchet, which marks the task as a success or failure, displays the results, and so on.
