Skill Tracer
Skills › Scientific Agent Skills › latchbio-integration › resource-configuration.md

resource-configuration.md

279 lines · skills/latchbio-integration/references/resource-configuration.md at 5f2bc03

Open on GitHub
1# Task Resource Configuration
2
3This reference targets `latch==2.77.1`. Resource shapes are operational
4configuration and can change independently of examples. Inspect the installed
5SDK before making cost or capacity guarantees. Task bodies below are illustrative
6resource-configuration skeletons, not complete scientific implementations.
7

Task Resource Configuration

This reference targets latch==2.77.1. Resource shapes are operational configuration and can change independently of examples. Inspect the installed SDK before making cost or capacity guarantees. Task bodies below are illustrative resource-configuration skeletons, not complete scientific implementations.

Raw lines 1 to 7
8## Selection Strategy
9
101. Start with the smallest named decorator that can run the task.
112. Measure CPU, peak RSS, temporary storage, wall time, and GPU utilization.
123. Move to a larger named decorator only when evidence justifies it.
134. Use `custom_task` for CPU-only shapes not represented by a named decorator.
145. Use a named GPU decorator; `custom_task` does not accept `gpu` or
15 `gpu_type` arguments.
166. Re-measure with representative scientific data before release.

Selection Strategy

  1. Start with the smallest named decorator that can run the task.
  2. Measure CPU, peak RSS, temporary storage, wall time, and GPU utilization.
  3. Move to a larger named decorator only when evidence justifies it.
  4. Use custom_task for CPU-only shapes not represented by a named decorator.
  5. Use a named GPU decorator; custom_task does not accept gpu or gpu_type arguments.
  6. Re-measure with representative scientific data before release.
Raw lines 8 to 17
18## Named CPU Decorators
20```python
21from latch.resources.tasks import large_task, medium_task, small_task
24@small_task
25def parse_manifest():
26 ...
29@medium_task
30def align_reads():
31 ...
34@large_task
35def assemble_genome():
36 ...
37```
39SDK 2.77.1 configures these scheduler requests:
41| Decorator | CPU | RAM | Ephemeral storage |
42|---|---:|---:|---:|
43| `small_task` | 2 | 4 GiB | 100 GiB |
44| `medium_task` | 30 | 100 GiB | 1500 GiB |
45| `large_task` | 90 | 170 GiB | 4500 GiB |
47The public guide may display nominal instance capacities rather than the
48schedulable requests encoded in the package. The installed package determines
49what registration serializes.

Named CPU Decorators

from latch.resources.tasks import large_task, medium_task, small_task


@small_task
def parse_manifest():
    ...


@medium_task
def align_reads():
    ...


@large_task
def assemble_genome():
    ...

SDK 2.77.1 configures these scheduler requests:

DecoratorCPURAMEphemeral storage
small_task24 GiB100 GiB
medium_task30100 GiB1500 GiB
large_task90170 GiB4500 GiB

The public guide may display nominal instance capacities rather than the schedulable requests encoded in the package. The installed package determines what registration serializes.

Raw lines 18 to 50
51## Named GPU Decorators
53Generic GPU shapes:
55```python
56from latch.resources.tasks import large_gpu_task, small_gpu_task
57```
59| Decorator | CPU | RAM | GPU |
60|---|---:|---:|---|
61| `small_gpu_task` | 7 | 30 GiB | 1× T4-class |
62| `large_gpu_task` | 63 | 245 GiB | 1× A10G-class |
64V100 shapes:
66```python
67from latch.resources.tasks import (
68 v100_x1_task,
69 v100_x4_task,
70 v100_x8_task,
72```
74L40S shapes:
76```python
77from latch.resources.tasks import (
78 g6e_xlarge_task,
79 g6e_2xlarge_task,
80 g6e_4xlarge_task,
81 g6e_8xlarge_task,
82 g6e_12xlarge_task,
83 g6e_16xlarge_task,
84 g6e_24xlarge_task,
85 g6e_48xlarge_task,
87```
89Current L40S scheduler requests and limits:
91| Decorator | Request CPU | Request RAM | Limit CPU | Limit RAM | GPUs |
92|---|---:|---:|---:|---:|---:|
93| `g6e_xlarge_task` | 2 | 28 GiB | 4 | 32 GiB | 1 |
94| `g6e_2xlarge_task` | 6 | 57 GiB | 8 | 64 GiB | 1 |
95| `g6e_4xlarge_task` | 14 | 115 GiB | 16 | 128 GiB | 1 |
96| `g6e_8xlarge_task` | 30 | 230 GiB | 32 | 256 GiB | 1 |
97| `g6e_12xlarge_task` | 46 | 345 GiB | 48 | 384 GiB | 4 |
98| `g6e_16xlarge_task` | 62 | 460 GiB | 64 | 512 GiB | 1 |
99| `g6e_24xlarge_task` | 94 | 691 GiB | 96 | 768 GiB | 4 |
100| `g6e_48xlarge_task` | 190 | 1382 GiB | 192 | 1536 GiB | 8 |
102GPU availability, quotas, and platform mapping can change. Confirm in the
103current docs or with Latch support before promising a specific model to users.

Named GPU Decorators

Generic GPU shapes:

from latch.resources.tasks import large_gpu_task, small_gpu_task
DecoratorCPURAMGPU
small_gpu_task730 GiB1× T4-class
large_gpu_task63245 GiB1× A10G-class

V100 shapes:

from latch.resources.tasks import (
    v100_x1_task,
    v100_x4_task,
    v100_x8_task,
)

L40S shapes:

from latch.resources.tasks import (
    g6e_xlarge_task,
    g6e_2xlarge_task,
    g6e_4xlarge_task,
    g6e_8xlarge_task,
    g6e_12xlarge_task,
    g6e_16xlarge_task,
    g6e_24xlarge_task,
    g6e_48xlarge_task,
)

Current L40S scheduler requests and limits:

DecoratorRequest CPURequest RAMLimit CPULimit RAMGPUs
g6e_xlarge_task228 GiB432 GiB1
g6e_2xlarge_task657 GiB864 GiB1
g6e_4xlarge_task14115 GiB16128 GiB1
g6e_8xlarge_task30230 GiB32256 GiB1
g6e_12xlarge_task46345 GiB48384 GiB4
g6e_16xlarge_task62460 GiB64512 GiB1
g6e_24xlarge_task94691 GiB96768 GiB4
g6e_48xlarge_task1901382 GiB1921536 GiB8

GPU availability, quotas, and platform mapping can change. Confirm in the current docs or with Latch support before promising a specific model to users.

Raw lines 51 to 104
105## Custom CPU, Memory, and Storage
107Exact stable signature:
109```text
110custom_task(
111 cpu,
112 memory,
113 *,
114 storage_gib=500,
115 timeout=0,
116 **task_options,
118```
120Example:
122```python
123from datetime import timedelta
125from latch import custom_task
128@custom_task(
129 cpu=12,
130 memory=48,
131 storage_gib=750,
132 timeout=timedelta(hours=6),
133 retries=1,
135def call_variants():
136 ...
137```
139In SDK 2.77.1, `custom_task` accepts up to 126 CPU cores, 975 GiB RAM, and
1404949 GiB ephemeral storage. Not every arbitrary combination fits a schedulable
141node group; the decorator selects the smallest configured group that satisfies
142all three requests.
144`custom_memory_optimized_task` is deprecated. Use `custom_task`.

Custom CPU, Memory, and Storage

Exact stable signature:

custom_task(
    cpu,
    memory,
    *,
    storage_gib=500,
    timeout=0,
    **task_options,
)

Example:

from datetime import timedelta

from latch import custom_task


@custom_task(
    cpu=12,
    memory=48,
    storage_gib=750,
    timeout=timedelta(hours=6),
    retries=1,
)
def call_variants():
    ...

In SDK 2.77.1, custom_task accepts up to 126 CPU cores, 975 GiB RAM, and 4949 GiB ephemeral storage. Not every arbitrary combination fits a schedulable node group; the decorator selects the smallest configured group that satisfies all three requests.

custom_memory_optimized_task is deprecated. Use custom_task.

Raw lines 105 to 145
146## Dynamic Resources
148Each `cpu`, `memory`, or `storage_gib` argument may be a function of task
149inputs. The resource function's annotated parameters must exist in the task
150with exactly matching annotations.
152```python
153from latch import custom_task
154from latch.types import LatchFile
157def allocate_cpu(files: list[LatchFile]) -> int:
158 return min(32, max(2, len(files) * 2))
161def allocate_storage(files: list[LatchFile]) -> int:
162 sizes = [file.size() for file in files]
163 if any(size is None for size in sizes):
164 raise ValueError("unable to determine every input size")
165 total_bytes = sum(int(size) for size in sizes)
166 estimated_gib = total_bytes / (1024**3)
167 storage = max(100, int(estimated_gib * 2) + 1)
168 if storage > 4949:
169 raise ValueError("estimated storage exceeds the custom_task limit")
170 return storage
173@custom_task(
174 cpu=allocate_cpu,
175 memory=64,
176 storage_gib=allocate_storage,
178def merge_files(files: list[LatchFile]) -> LatchFile:
179 ...
180```
182Dynamic functions execute at runtime before the task launches.
184Guardrails:
186- Return integers.
187- Bound every computed resource.
188- Include overhead for decompression and intermediate files.
189- Keep computation deterministic and fast.
190- Restrict remote lookups to necessary input metadata (such as `file.size()`).
191 Do not download inputs or retrieve secrets in a resource function.
192- Test the exact annotation matching during staging registration.

Dynamic Resources

Each cpu, memory, or storage_gib argument may be a function of task inputs. The resource function's annotated parameters must exist in the task with exactly matching annotations.

from latch import custom_task
from latch.types import LatchFile


def allocate_cpu(files: list[LatchFile]) -> int:
    return min(32, max(2, len(files) * 2))


def allocate_storage(files: list[LatchFile]) -> int:
    sizes = [file.size() for file in files]
    if any(size is None for size in sizes):
        raise ValueError("unable to determine every input size")
    total_bytes = sum(int(size) for size in sizes)
    estimated_gib = total_bytes / (1024**3)
    storage = max(100, int(estimated_gib * 2) + 1)
    if storage > 4949:
        raise ValueError("estimated storage exceeds the custom_task limit")
    return storage


@custom_task(
    cpu=allocate_cpu,
    memory=64,
    storage_gib=allocate_storage,
)
def merge_files(files: list[LatchFile]) -> LatchFile:
    ...

Dynamic functions execute at runtime before the task launches.

Guardrails:

  • Return integers.
  • Bound every computed resource.
  • Include overhead for decompression and intermediate files.
  • Keep computation deterministic and fast.
  • Restrict remote lookups to necessary input metadata (such as file.size()). Do not download inputs or retrieve secrets in a resource function.
  • Test the exact annotation matching during staging registration.
Raw lines 146 to 193
194## Cache, Retries, and Timeout
196Named decorators and non-dynamic `custom_task` accept Flyte task options:
198```python
199@medium_task(
200 cache=True,
201 cache_version="aligner-2.1-reference-v4",
202 retries=2,
203 timeout=7200,
205def align_reads():
206 ...
207```
209- Cache deterministic outputs only.
210- Include tool, reference, and behavior changes in `cache_version`.
211- Use retries for transient infrastructure or network errors.
212- Do not retry deterministic invalid-input failures.
213- A timeout can be seconds or `datetime.timedelta`.

Cache, Retries, and Timeout

Named decorators and non-dynamic custom_task accept Flyte task options:

@medium_task(
    cache=True,
    cache_version="aligner-2.1-reference-v4",
    retries=2,
    timeout=7200,
)
def align_reads():
    ...
  • Cache deterministic outputs only.
  • Include tool, reference, and behavior changes in cache_version.
  • Use retries for transient infrastructure or network errors.
  • Do not retry deterministic invalid-input failures.
  • A timeout can be seconds or datetime.timedelta.
Raw lines 194 to 214
215## Temporary and Persistent Storage
217Ephemeral task storage is deleted with the task environment. Use it for:
219- Decompressed inputs
220- Tool work directories
221- Sort spills
222- Intermediate indexes
224Return a `LatchFile` or `LatchDir`, or upload through `LPath`, for persistent
225outputs. Never assume `/tmp` or `/root` survives task completion.
227Estimate storage from peak simultaneous intermediates, not final output size:
229```text
230requested storage
231 >= staged inputs
232 + decompressed expansion
233 + peak tool intermediates
234 + final outputs
235 + safety margin
236```

Temporary and Persistent Storage

Ephemeral task storage is deleted with the task environment. Use it for:

  • Decompressed inputs
  • Tool work directories
  • Sort spills
  • Intermediate indexes

Return a LatchFile or LatchDir, or upload through LPath, for persistent outputs. Never assume /tmp or /root survives task completion.

Estimate storage from peak simultaneous intermediates, not final output size:

requested storage
  >= staged inputs
   + decompressed expansion
   + peak tool intermediates
   + final outputs
   + safety margin
Raw lines 215 to 237
238## Cost and Launch Safety
240- Surface the chosen resource class before registration or launch.
241- Obtain confirmation before starting large or GPU-backed executions.
242- Prefer a representative small launch plan for validation.
243- Parallelism multiplies cost; map width matters as much as per-task size.
244- Cache hits can reduce cost but are not a substitute for reproducible inputs.
245- Compare resource monitoring against scientific throughput, not utilization
246 alone.

Cost and Launch Safety

  • Surface the chosen resource class before registration or launch.
  • Obtain confirmation before starting large or GPU-backed executions.
  • Prefer a representative small launch plan for validation.
  • Parallelism multiplies cost; map width matters as much as per-task size.
  • Cache hits can reduce cost but are not a substitute for reproducible inputs.
  • Compare resource monitoring against scientific throughput, not utilization alone.
Raw lines 238 to 247
248## Troubleshooting

Troubleshooting

Raw lines 248 to 249
250### Out of memory
252- Check peak RSS, not average memory.
253- Identify whether an algorithm scales with records, bases, or samples.
254- Increase memory only after ruling out unbounded accumulation.

Out of memory

  • Check peak RSS, not average memory.
  • Identify whether an algorithm scales with records, bases, or samples.
  • Increase memory only after ruling out unbounded accumulation.
Raw lines 250 to 255
256### Out of storage
258- Inspect hidden tool caches and decompressed inputs.
259- Clean intermediates within the task when safe.
260- Increase `storage_gib` based on peak use.

Out of storage

  • Inspect hidden tool caches and decompressed inputs.
  • Clean intermediates within the task when safe.
  • Increase storage_gib based on peak use.
Raw lines 256 to 261
262### CPU under-utilization
264- Confirm the scientific tool received its thread/process flag.
265- Avoid requesting more cores than the tool can use.
266- Check I/O and memory bandwidth before scaling CPU.

CPU under-utilization

  • Confirm the scientific tool received its thread/process flag.
  • Avoid requesting more cores than the tool can use.
  • Check I/O and memory bandwidth before scaling CPU.
Raw lines 262 to 267
268### GPU under-utilization
270- Verify the tool was built with the expected CUDA support.
271- Check batch size, data loading, and CPU preprocessing.
272- Avoid multi-GPU shapes unless the application implements distributed work.

GPU under-utilization

  • Verify the tool was built with the expected CUDA support.
  • Check batch size, data loading, and CPU preprocessing.
  • Avoid multi-GPU shapes unless the application implements distributed work.
Raw lines 268 to 273
274## Official Sources
276- Resource guide: https://wiki.latch.bio/workflows/sdk/python/defining-cloud-resources
277- Resource monitoring: https://wiki.latch.bio/workflows/sdk/console/resource-monitoring
278- Task source in the 2.77.1 release commit: https://github.com/latchbio/latch/blob/b3768e65c6d496868f6e530f11977d857ad85dc7/src/latch/resources/tasks.py
279- Changelog in the 2.77.1 release commit: https://github.com/latchbio/latch/blob/b3768e65c6d496868f6e530f11977d857ad85dc7/CHANGELOG.md

Official Sources

  • Resource guide: https://wiki.latch.bio/workflows/sdk/python/defining-cloud-resources
  • Resource monitoring: https://wiki.latch.bio/workflows/sdk/console/resource-monitoring
  • Task source in the 2.77.1 release commit: https://github.com/latchbio/latch/blob/b3768e65c6d496868f6e530f11977d857ad85dc7/src/latch/resources/tasks.py
  • Changelog in the 2.77.1 release commit: https://github.com/latchbio/latch/blob/b3768e65c6d496868f6e530f11977d857ad85dc7/CHANGELOG.md
Raw lines 274 to 279