nextflow-io / nextflow-io/nextflow
Allow opting out of foreign-file staging for paths on worker-accessible mounts
Nobody has claimed this yet.
- Dominant language
- Groovy
- Stars
- 3.5k
- Forks
- 811
- Avg merge
- 2d 11h
- Merged PRs (30d)
- 61
Description
New feature
Allow users to declare that one or more filesystem paths (e.g. a shared network mount such as WEKA, Lustre, or s3-files) are reachable on the worker nodes at the same path as on the head node, so that Nextflow can skip its driver-side staging step (FilePorter) and the per-task download for inputs under those paths. Instead of copying these inputs into the work directory, Nextflow would stage them into the task working directory with a symlink, exactly as it already does when inputs and the work directory share the same URI scheme.
Today the foreign-file decision is made solely by comparing URI schemes (Executor.isForeignFile(Path)); there is no per-process or per-path override. As a result, any file:// input is treated as foreign when the executor's work directory is on s3:///gs:///az://, and Nextflow uploads the file to object storage before the task is dispatched — even in setups where the same path is already mounted and readable on every worker.
Use case
Take a user that runs Nextflow pipelines on AWS Batch with an s3:// work directory. Reference and input data lives on a WEKA filesystem in their on-premises datacenter and is mounted (read-only, via wekafs) on both the head node and the AWS Batch compute environment workers at the same POSIX paths. The data is also accessible at the same POSIX paths via "S3 Files" (efs-utils mounting an S3 bucket as an EFS-style filesystem) for a separate class of inputs.
Because the inputs are addressed as file:///weka/... paths and the work directory is s3://, Nextflow currently:
- Treats every input as foreign and runs
FilePorteron the head node, uploading each input file to the S3 stage directory before the Batch job is submitted. - Then, inside the task container, runs
nxf_s3_downloadto pull the staged copy from S3 back down to local scratch.
Both steps consume time, network and disk that the customer would not need to spend if Nextflow knew the workers already see /weka/... at the same path. The current workaround is to declare these inputs as val (which skips staging entirely) — but val loses file size/mtime tracking, breaks -resume, and removes the inputs from Nextflow's reports and provenance.
This pattern (cloud Batch executor + on-prem shared filesystem also mounted on the workers) is increasingly common as organisations adopt a hybrid model: cloud compute against reference datasets that are too large, too tightly governed, or too expensive to mirror to object storage on every run. Other shapes that would benefit from the same feature:
- HPC clusters with a parallel filesystem (Lustre, GPFS, BeeGFS, WEKA) shared across head and compute, where the user prefers a cloud-style configuration but the data is on-prem.
- AWS Batch / EKS / GKE deployments mounting FSx for Lustre, EFS, Filestore, or S3 Files at the workers via launch templates or pod specs.
- Hybrid pipelines that mix a local executor with a cloud executor and want to share inputs without paying for an upload on every run.
A non-Fusion workaround exists for users who can put the work directory on the shared mount and use a local-style executor — but for customers like our example, EFS-as-work-dir has its own scaling issues, S3 work dir is non-negotiable, and Fusion may not be available (procurement, licensing, or operational constraints).
Suggested implementation
The core change is small: give the foreign-file check an opt-in escape hatch. Two layers need to honour it.
Layer 1 — driver-side staging (FilePorter). Extend Executor.isForeignFile(Path) (modules/nextflow/src/main/groovy/nextflow/executor/Executor.groovy) so that, when a configured list of "shared mount" path prefixes is provided, paths under those prefixes are not considered foreign. Concretely:
boolean isForeignFile(Path path) {
if (path.scheme == getStageDir().scheme) return false
if (sharedMounts.any { path.toAbsolutePath().startsWith(it) }) return false
return true
}
Configuration could be exposed in two complementary places:
- A global config setting:
executor { sharedMounts = ['/weka', '/s3files'] } - An optional per-process directive for finer scoping:
process FOO { sharedMount '/weka' input: path reference ... }
Layer 2 — task-side staging. The cloud copy strategies (e.g. AwsBatchFileCopyStrategy.stageInputFile in plugins/nf-amazon/src/main/nextflow/cloud/aws/batch/AwsBatchFileCopyStrategy.groovy) currently emit nxf_s3_download for every input. They would need to emit ln -s <source> <target> for inputs whose paths are under a declared shared mount, matching the behaviour of SimpleFileCopyStrategy.stageInCommand in symlink mode.
Safety and ergonomics.
- Nextflow has no way to verify that the mount actually exists on the worker; the directive is a user assertion. To fail fast on misconfiguration, the generated task script could include a startup probe (
test -e /weka/path/to/input || { echo "shared mount /weka not available on this worker"; exit 1; }) so that a missing or broken mount produces a clear error rather than a silently confusing one. - Hashing/provenance should continue to work:
pathinputs would still carry file size and mtime in the task hash, so-resumewould correctly detect modified inputs even though no upload occurred. (This is the main thingvalloses today.) - The default for
sharedMountsis empty, so existing behaviour is unchanged.
Related components.
Executor.isForeignFileandExecutor.getStageDir— the foreign-file check itself.TaskInputResolver.groovy(line whereexecutor.isForeignFile(path)is consulted) — the call site that routes paths throughFilePorter.addToForeign.FilePorter— would receive fewer paths but otherwise unchanged.AwsBatchFileCopyStrategy,GoogleBatchFileCopyStrategy,AzBatchFileCopyStrategy— the task-side staging script generators that need to emitln -sfor shared-mount paths.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with Executor.groovy and TaskInputResolver.groovy to trace the foreign-file decision and FilePorter routing. Then compare AwsBatchFileCopyStrategy, GoogleBatchFileCopyStrategy, and AzBatchFileCopyStrategy with SimpleFileCopyStrategy's symlink behavior. Done means shared-mount paths avoid foreign staging and task downloads, use symlinks, and leave the empty-default behavior unchanged.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- aws, azure, gcp, groovy
- Domain
- backend, cloud, infrastructure
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100