Skip to main content

Filter Remote Resources and Open Console Views

Start with the run/action distinction​

When you are investigating a remote execution, begin with flyte.remote.Run: it represents the top-level task run. The run contains a nested flyte.remote.Action, and a run's actions form a linearly nested execution tree. That distinction matters when a run is present but the useful failure or work item is one of its child actions.

Initialize Flyte before listing or retrieving remote resources. Both Run.listall() and Action.listall() call ensure_client() before making a RunService request. For example, the SDK's remote setup and synchronous listing can be used as follows:

import flyte
import flyte.remote as remote

flyte.init_passthrough("endpoint")

with remote.auth_metadata(("key1", "value1")):
print(remote.Run.listall(limit=2))

flyte.init_from_config(), flyte.init(), and other supported initialization paths provide the client and the project/domain defaults used by the remote APIs. Without an endpoint or API key, client initialization raises MissingEndpointOrApiKeyError.

Find runs with Run.listall()​

Use Run.listall() when you need to search across runs in the configured project and domain. It is syncified: normal synchronous use returns an iterator, while the asynchronous form is available through the generated .aio() interface.

import flyte.models
import flyte.remote as remote

training_runs = remote.Run.listall(
in_phase=(flyte.models.ActionPhase.SUCCEEDED,),
task_name="image_finetune_training.finetune_image_model",
sort_by=("created_at", "desc"),
limit=1,
)

training_run = next(training_runs)
outputs = training_run.outputs()

This is the pattern used by examples/ml/image_classification/batch_inference.py: select the newest successful run for a task, take its outputs, and use them in a later run.

Run filters and scope​

Run.listall() accepts the following arguments:

ArgumentBehavior
in_phaseA tuple of ActionPhase values or strings. One phase becomes an equality filter; multiple phases become a VALUE_IN filter. String values are converted using ACTION_PHASE_{value.upper()}.
task_nameAdds an equality filter on task_name.
task_versionAdds an equality filter on task_version.
created_by_subjectAdds an equality filter on created_by. This is the creator's subject, not a username.
sort_byA (field, direction) tuple, with direction "asc" or "desc". The shared sorting helper defaults to ("created_at", "asc").
limitMaximum total number of runs yielded; the default is 100.
project, domainOverride the globally configured project or domain for this listing.
created_atA TimeFilter applied to run creation time.
updated_atA TimeFilter applied to last-update time.

For example, phase, task, version, and creator filters are combined by the SDK before the request is sent:

runs = remote.Run.listall(
in_phase=("running", "failed"),
task_name="my_task",
task_version="v1.0",
created_by_subject="user:alice",
sort_by=("updated_at", "desc"),
limit=20,
project="customer-us-east",
domain="production",
)

Prefer flyte.models.ActionPhase values when possible. A string is looked up as a protobuf enum name; an invalid phase string therefore surfaces as a protobuf enum conversion error rather than becoming an arbitrary server-side value.

If project or domain is omitted, Run.listall() reads the corresponding value from get_init_config(). The explicit values win, as in the focused filter tests: project="customer-us-east" changes the request's project identifier, while omission uses the initialized default.

The method calls run_service.list_runs with protobuf filters and paginates using the response token. Each request asks for min(100, limit) items. The method still enforces the caller's total limit after yielding results, so a limit larger than 100 can span multiple pages. The server's lack of a continuation token ends iteration.

The CLI's flyte get run command forwards the same filters. Its --only-mine option obtains remote.User.get().subject() and passes that value as created_by_subject; its date options become TimeFilter instances.

Narrow a run to its actions​

Once you have a run name, call Action.listall(for_run_name=...). Actions support phase, creation-time, update-time, and sorting filters, but not run-list filters such as task name, task version, or creator:

running_actions = list(
remote.Action.listall(
for_run_name=run_name,
in_phase=(flyte.models.ActionPhase.RUNNING,),
sort_by=("created_at", "asc"),
)
)

Action.listall() defaults to ("created_at", "asc") when sort_by is omitted. It requests 100 actions per page and continues until the service returns no token. Unlike Run.listall(), it has no limit parameter, so a large action tree is not capped by the SDK call.

For one action, use its run name and action name:

action = remote.Action.get(run_name=run_name, name=action_name)

The CLI follows the same split: flyte get action calls Action.get(run_name=..., name=...) when an action name is supplied, and otherwise calls Action.listall(for_run_name=...). The configured project and domain are used to build the action identifier.

An action may not correspond to a task metadata record. Action.task_name returns the task name when the action metadata contains a task ID, and otherwise returns None. The root action is commonly named a0; the SDK's live-abort example deliberately ignores it while looking for a child action:

import flyte.models
import flyte.remote as remote

actions = list(
remote.Action.listall(
for_run_name=r.name,
in_phase=[flyte.models.ActionPhase.RUNNING],
)
)

for a in actions:
if a.name != "a0":
a.abort("External abort!!")
break

Bound searches by time​

Construct flyte.remote.TimeFilter with optional datetime bounds. after is inclusive and before is exclusive:

from datetime import datetime, timezone

created_at = remote.TimeFilter(
after=datetime(2024, 1, 1, tzinfo=timezone.utc),
before=datetime(2024, 2, 1, tzinfo=timezone.utc),
)

runs = remote.Run.listall(
in_phase=("succeeded",),
created_at=created_at,
updated_at=remote.TimeFilter(
after=datetime(2024, 1, 15, tzinfo=timezone.utc)
),
)

time_filtering() converts these bounds into list-service protobuf filters: after becomes GREATER_THAN_OR_EQUAL, and before becomes LESS_THAN. Each bound is normalized with astimezone(timezone.utc).isoformat(), and both bounds are added when present. An empty TimeFilter() produces no filters. Use timezone-aware datetimes—preferably UTC—because the helper calls astimezone() and the CLI explicitly attaches UTC to naive date values before constructing its filters.

Time filters compose with phase and other run filters, and the same created_at/updated_at behavior is used by Action.listall().

Inspect and control the selected resource​

A returned Run exposes name, a string phase, and raw_phase, which is the underlying protobuf enum. A returned Action exposes name, run_name, task_name, phase as an ActionPhase enum, raw_phase, action_id, and start_time as a UTC-aware datetime.

Fetch remote data lazily when you need more than the list response:

details = run.details()
inputs = run.inputs()
outputs = run.outputs()

For live investigation, run.wait() delegates to its nested action and copies the updated action protobuf back into the Run. run.watch() similarly yields action-detail updates while synchronizing the run state. On an action, watch() can stop when the action is running, when logs are ready, or when it reaches a terminal state; wait() provides the corresponding progress display and stopping behavior.

Use get_logs() to iterate log lines or show_logs() to display them. Both action methods may wait until logs are ready and default to the latest attempt. Run.get_logs() and Run.show_logs() delegate to the nested action.

run.abort(reason=...) calls the run abort RPC; action.abort(reason=...) calls the action abort RPC. Both treat a NOT_FOUND ConnectRPC error as harmless and propagate other RPC errors. done() reports terminal-state status. Do not treat sync() as a refresh operation: Run.sync() and Action.sync() currently return the existing object as placeholders.

Open console views while investigating​

Run.url gives you a browser link for the containing run:

flyte.init_from_config()
r = flyte.run(main, 10, 30.0)
print(r.url)

The property delegates to the initialized client's Console.run_url() with the run's project, domain, and name. Action has no direct url property. Use the containing run URL for an action investigation, or use the client's console to build a task/resource link. Task.url similarly uses client.console.task_url(...).

The Console constructor takes the configured endpoint and insecure flag. Direct construction is useful when you need a resource link explicitly:

from flyte.remote._client.controlplane import Console

console = Console("https://example.com")
run_url = console.run_url(
project="myproject",
domain="development",
run_name="run123",
)
task_url = console.task_url(
project="myproject",
domain="development",
task_name="mytask",
)

The generated path has this shape:

{scheme}://{domain}/v2/domain/{domain}/project/{project}/{resource}/{resource_name}

Thus the examples produce URLs such as https://example.com/v2/domain/development/project/myproject/runs/run123 and https://example.com/v2/domain/development/project/myproject/tasks/mytask. Console also provides app_url() and trigger_url(); trigger resources use {task_name}/{trigger_name} as the resource name.

ClientSet creates the configured Console and exposes it as client.console, which is the console used by Run.url and Task.url. Endpoint normalization chooses HTTPS by default and HTTP when insecure=True. DNS-style endpoints such as dns:///example.com are reduced to example.com. The local-development special case maps localhost:8090 to the web console at localhost:8080, preserving the selected HTTP/HTTPS scheme:

console = Console("dns:///localhost:8090", insecure=True)
assert console._http_domain == "http://localhost:8080"

The URL builder interpolates resource names directly into the path and does not URL-quote them. The source also marks console URL configuration as a future TODO, so the endpoint-derived path is the behavior to rely on today rather than a separately configurable console base URL.

Investigation checklist for common surprises​

  • Initialize the client before calling Run.listall(), Action.listall(), Run.get(), or Action.get().
  • Remember that run listing defaults to the initialized project/domain, while project= and domain= override them.
  • Use ActionPhase values or valid phase strings; run phases are exposed as strings, while action phases are enum values.
  • Expect run pagination and a default run limit of 100. Action listing pages at 100 but has no caller-side limit.
  • Use timezone-aware UTC bounds for TimeFilter; after includes its instant and before excludes its instant.
  • A manually constructed Run must contain an action field in its protobuf or initialization raises RuntimeError("Run does not have an action").
  • For child-action investigation, filter Action.listall() by phase and account for the root action a0; actions can also lack a task name.
  • insecure=True changes generated browser links to http://; it is not only an RPC transport setting.
  • Treat a missing resource during abort as a no-op only for NOT_FOUND; other errors are raised.