Skip to main content

Working with Remote Tasks

When you need to interact with tasks already registered on a Flyte backend—whether to inspect their interfaces, override their resource requirements, or trigger them from a script—flyte-sdk provides the remote.Task and remote._task.TaskDetails classes. These entities allow you to treat remote tasks as local Python objects while maintaining a connection to the Flyte API.

Fetching Remote Tasks​

The primary entry point for retrieving a task is Task.get(). Because fetching full task definitions (including interfaces and metadata) can be expensive, flyte-sdk returns a LazyEntity that only communicates with the backend when you explicitly request data or attempt to call the task.

Retrieving a Specific Version​

If you know the exact version of the task you need, pass the name and version to Task.get(). You must then call .fetch() to resolve the LazyEntity into a TaskDetails object.

from flyte.remote import Task

# Retrieve a specific version of a task
lazy_task = Task.get(
name="my_workflow.tasks.process_data",
project="flytesnacks",
domain="development",
version="v1"
)

# Explicitly fetch the full details
task_details = lazy_task.fetch()
print(f"Fetched task: {task_details.name} version {task_details.version}")

Automatic Versioning​

In scenarios like CLI tools or dynamic scripts where hardcoding a version is impractical, you can use auto_version.

  • latest: Fetches the most recently created version of the task.
  • current: Derives the version from the current execution context. This is only valid when called from within another running Flyte task.
# Fetch the latest version available on the backend
task = Task.get(name="my_task", auto_version="latest").fetch()

Internally, TaskDetails.get implements this by calling Task.listall with a descending sort on created_at and a limit of 1 to identify the latest version before performing a GetTaskDetails request.

Discovering Tasks​

To find available tasks without knowing their names beforehand, use Task.listall(). This method returns an iterator of Task objects (which are lighter than TaskDetails).

# List the first 10 tasks in a project
tasks = Task.listall(project="flytesnacks", domain="development", limit=10)
for t in tasks:
print(f"Found task: {t.name} ({t.version})")

Inspecting Task Interfaces​

Once you have a TaskDetails object, you can inspect its signature to understand what inputs it requires. The interface property returns a NativeInterface which maps Flyte types back to Python types.

task_details = Task.get(name="math.add", version="v1").fetch()

# Inspect required vs optional arguments
print(f"Required: {task_details.required_args}")
print(f"Defaults: {task_details.default_input_args}")

# Access the full interface object
interface = task_details.interface
for name, var in interface.inputs.items():
print(f"Input {name} is of type {var.type}")

The TaskDetails class also exposes metadata such as cache policies, secrets, and resources (requests and limits) directly from the underlying protobuf definition.

Executing Remote Tasks​

You can execute a remote task by calling the LazyEntity or TaskDetails object directly.

Note: Positional arguments are not supported for remote task calls; you must use keyword arguments.

# Calling a remote task like a function
task = Task.get(name="math.multiply", auto_version="latest")
result = task(a=5, b=10)

When you call a task:

  1. If it is a LazyEntity, it calls fetch() internally.
  2. It validates that all required_args are provided in kwargs.
  3. If the code is running inside a Flyte task context, it uses the internal controller (controller.submit_task_ref) to submit the execution to the Flyte backend.

Overriding Task Configuration​

You may need to modify a task's execution parameters—such as increasing memory or setting environment variables—without changing the registered task definition. The override() method allows you to create a modified version of the task for a specific execution.

from flyte import Resources

task = Task.get(name="heavy_job", version="v1")

# Override resources and retries for this specific usage
custom_task = task.override(
resources=Resources(cpu="2", mem="4Gi"),
retries=3,
env_vars={"STAGE": "production"}
)

# Execute the task with overrides
custom_task(data_path="s3://bucket/data")

The override() method modifies the internal task_template within the TaskDetails.pb2 object. It supports overriding:

  • short_name: A display name for the task.
  • resources: CPU, memory, and GPU requirements.
  • retries: The number of times to retry on failure.
  • timeout: Maximum execution time.
  • env_vars: Environment variables passed to the container.
  • secrets: Security context requirements.

Implementation Details​

Lazy Loading with LazyEntity​

The LazyEntity class in remote/_task.py acts as a proxy. It holds a getter coroutine that is only executed when fetch() is called or when the entity is invoked via __call__. This ensures that scripts listing hundreds of tasks do not trigger hundreds of heavy API calls to fetch full task details unless specifically requested.

Configuration Requirements​

Interacting with remote tasks requires the flyte-sdk to be configured with a project and domain. If these are not provided in the Task.get() call, the SDK retrieves them from the global configuration via get_common_config(). If the client is not initialized, Task.listall() will trigger an ensure_client() check to verify connectivity to the Flyte service.