> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tilebox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Clusters

<Accordion title="What is a Cluster?">
  Clusters are a logical grouping for [task runners](/workflows/concepts/task-runners).
  Using clusters, you can scope certain tasks to a specific group of task runners.
  Tasks, which are always submitted to a specific cluster, are only executed on task runners assigned to the same cluster.
</Accordion>

## Use Cases

Use clusters to organize [task runners](/workflows/concepts/clusters) into logical groups, which can help with:

* Targeting specific task runners for a particular job
* Reserving a group of task runners for specific purposes, such as running certain types of batch jobs
* Setting up different clusters for different environments (like development and production)

Even when using different clusters, task runners within the same cluster may still have different capabilities, such as different registered tasks.
If multiple task runners have the same set of registered tasks, you can assign them to different clusters to target specific task runners for a particular job.

### Adding Task Runners to a Cluster

You can add task runners to a cluster by specifying the [cluster's slug](#cluster-slug) when [registering a task runner](/workflows/concepts/task-runners).
Each task runner must always be assigned to a cluster.

## Default Cluster

Each team has a default cluster that is automatically created for them.
This cluster is used when no cluster is specified when [registering a task runner](/workflows/concepts/task-runners) or [submitting a job](/workflows/concepts/jobs).
This is useful when you are just getting started and don't need to create any custom clusters yet.

## Managing Clusters

Before registering a task runner or submitting a job, you must create a cluster. You can also list, fetch, and delete clusters as needed. The following sections explain how to do this.

To manage clusters, first instantiate a cluster client using the `clusters` method in the workflows client.

<CodeGroup title="Instantiating a Clusters Client">
  ```python Python theme={"system"}
  from tilebox.workflows import Client

  client = Client()
  clusters = client.clusters()
  ```

  ```go Go theme={"system"}
  import "github.com/tilebox/tilebox-go/workflows/v1"

  client := workflows.NewClient()
  clusterClient := client.Clusters
  ```
</CodeGroup>

### Creating a Cluster

To create a cluster, use the `create` method on the cluster client and provide a name for the cluster.

<CodeGroup title="Creating a Cluster">
  ```python Python theme={"system"}
  cluster = clusters.create("testing")
  print(cluster)
  ```

  ```go Go theme={"system"}
  cluster := client.Clusters.Create("testing")
  fmt.Println(cluster)
  ```
</CodeGroup>

<CodeGroup title="Output">
  ```plaintext Python theme={"system"}
  Cluster(slug='testing-CvufcSxcC9SKfe', display_name='testing')
  ```

  ```go Go theme={"system"}
  &{testing-CvufcSxcC9SKfe testing}
  ```
</CodeGroup>

### Cluster Slug

Each cluster has a unique identifier, combining the cluster's name and an automatically generated identifier.
Use this slug to reference the cluster for other operations, like submitting a job or subtasks.

### Listing Clusters

To list all available clusters, use the `all` method:

<CodeGroup title="Listing Clusters">
  ```python Python theme={"system"}
  all_clusters = clusters.all()
  print(all_clusters)
  ```

  ```go Go theme={"system"}
  clusters, err := client.Clusters.List(ctx)
  if err != nil {
      slog.Error("failed to list clusters", slog.Any("error", err))
      return
  }

  for _, cluster := range clusters {
      fmt.Println(cluster)
  }
  ```
</CodeGroup>

<CodeGroup title="Output">
  ```plaintext Python theme={"system"}
  [Cluster(slug='testing-CvufcSxcC9SKfe', display_name='testing'),
  Cluster(slug='production-EifhUozDpwAJDL', display_name='Production')]
  ```

  ```go Go theme={"system"}
  &{testing-CvufcSxcC9SKfe testing}
  &{production-EifhUozDpwAJDL Production}
  ```
</CodeGroup>

### Fetching a Specific Cluster

To fetch a specific cluster, use the `find` method and pass the cluster's slug:

<CodeGroup title="Fetching a Cluster">
  ```python Python theme={"system"}
  cluster = clusters.find("testing-CvufcSxcC9SKfe")
  print(cluster)
  ```

  ```go Go theme={"system"}
  cluster, err := client.Clusters.Get(ctx, "testing-CvufcSxcC9SKfe")
  if err != nil {
  	slog.Error("failed to get cluster", slog.Any("error", err))
  	return
  }
  fmt.Println(cluster)
  ```
</CodeGroup>

<CodeGroup title="Output">
  ```plaintext Python theme={"system"}
  Cluster(slug='testing-CvufcSxcC9SKfe', display_name='testing')
  ```

  ```go Go theme={"system"}
  &{testing-CvufcSxcC9SKfe testing}
  ```
</CodeGroup>

### Deleting a Cluster

To delete a cluster, use the `delete` method and pass the cluster's slug:

<CodeGroup title="Deleting a Cluster">
  ```python Python theme={"system"}
  clusters.delete("testing-CvufcSxcC9SKfe")
  ```

  ```go Go theme={"system"}
  err := client.Clusters.Delete(ctx, "testing-CvufcSxcC9SKfe")
  ```
</CodeGroup>

## Jobs Across Different Clusters

When [submitting a job](/workflows/concepts/jobs), you need to specify which cluster the job's root task should be executed on.
This allows you to direct the job to a specific set of task runners.
By default, all sub-tasks within a job are also submitted to the same cluster, but this can be overridden to submit sub-tasks to different clusters if needed.
See the example below for a job that spans across multiple clusters.

<CodeGroup title="Multi-Cluster Workflow Example">
  ```python Python theme={"system"}
  from tilebox.workflows import Task, ExecutionContext, Client

  class MultiCluster(Task):
      def execute(self, context: ExecutionContext) -> None:
          # this submits a task to the same cluster as the one currently executing this task
          same_cluster = context.submit_subtask(DummyTask())
          
          other_cluster = context.submit_subtask(
              DummyTask(),
              # this task runs only on a task runner in the "other-cluster" cluster
              cluster="other-cluster-As3dcSb3D9SAdK",
              # dependencies can be specified across clusters
              depends_on=[same_cluster],
          )

  class DummyTask(Task):
      def execute(self, context: ExecutionContext) -> None:
          pass

  # submit a job to the "testing" cluster
  client = Client()
  job_client = client.jobs()
  job = job_client.submit(
      "my-job",
      MultiCluster(),
      cluster="testing-CvufcSxcC9SKfe",
  )
  ```

  ```go Go theme={"system"}
  package main

  import (
  	"context"

  	"github.com/tilebox/tilebox-go/workflows/v1"
      "github.com/tilebox/tilebox-go/workflows/v1/subtask"
  )

  type MultiCluster struct{}

  func (t *MultiCluster) Execute(ctx context.Context) error {
  	// this submits a task to the same cluster as the one currently executing this task
  	sameCluster, err := workflows.SubmitSubtask(ctx, &DummyTask{})
  	if err != nil {
  		return err
  	}

  	otherCluster, err := workflows.SubmitSubtask(
  		ctx,
  		&DummyTask{},
  		// this task runs only on a task runner in the "other-cluster" cluster
  		subtask.WithClusterSlug("other-cluster-As3dcSb3D9SAdK"),
  		// dependencies can be specified across clusters
  		subtask.WithDependencies(sameCluster),
  	)
  	if err != nil {
  		return err
  	}

  	_ = otherCluster
  	return nil
  }

  type DummyTask struct{}

  func main() {
      ctx := context.Background()
  	client := workflows.NewClient()

  	// submit a job to the "testing" cluster
  	_, _ = client.Jobs.Submit(
  		ctx,
  		"my-job",
  		[]workflows.Task{
  			&MultiCluster{},
  		},
          job.WithClusterSlug("testing-CvufcSxcC9SKfe"),
  	)
  }
  ```
</CodeGroup>

This workflow requires at least two task runners to complete. One must be in the "testing" cluster, and the other must be in the "other-cluster" cluster.
If no task runners are available in the "other-cluster," the task submitted to that cluster will remain queued until a task runner is available.
It won't execute on a task runner in the "testing" cluster, even if the task runner has the `DummyTask` registered.
