15028: Add upgrade notes about going from CWL v1.0 to v1.1
[arvados.git] / doc / user / cwl / cwl-style.html.textile.liquid
index 0debd16a15cfae5a5bad1aa7279494837cdc19de..4f5e372a6e77c4515cbda248bfdea3b7611cc8b1 100644 (file)
@@ -1,22 +1,25 @@
 ---
 layout: default
 navsection: userguide
-title: Best Practices for writing CWL
+title: Writing Portable High-Performance Workflows
 ...
+{% comment %}
+Copyright (C) The Arvados Authors. All rights reserved.
 
-* To run on Arvados, a workflow should provide a @DockerRequirement@ in the @hints@ section.
+SPDX-License-Identifier: CC-BY-SA-3.0
+{% endcomment %}
 
-* Build a reusable library of components.  Share tool wrappers and subworkflows between projects.  Make use of and contribute to "community maintained workflows and tools":https://github.com/common-workflow-language/workflows and tool registries such as "Dockstore":http://dockstore.org .
+h2. Portability
 
-* When combining a parameter value with a string, such as adding a filename extension, write @$(inputs.file.basename).ext@ instead of @$(inputs.file.basename + 'ext')@.  The first form is evaluated as a simple text substitution, the second form (using the @+@ operator) is evaluated as an arbitrary Javascript expression and requires that you declare @InlineJavascriptRequirement@.
+To run on Arvados, a workflow must provide a @DockerRequirement@ in either the @hints@ or @requirements@ section.
 
-* Avoid declaring @InlineJavascriptRequirement@ or @ShellCommandRequirement@ unless you specifically need them.  Don't include them "just in case" because they change the default behavior and may imply extra overhead.
+Build a reusable library of components.  Share tool wrappers and subworkflows between projects.  Make use of and contribute to "community maintained workflows and tools":https://github.com/common-workflow-language/workflows and tool registries such as "Dockstore":http://dockstore.org .
 
-* Don't write CWL scripts that access the Arvados SDK.  This is non-portable; a script that access Arvados directly won't work with @cwltool@ or crunch v2.
+Avoid declaring @InlineJavascriptRequirement@ or @ShellCommandRequirement@ unless you specifically need them.  Don't include them "just in case" because they change the default behavior and may imply extra overhead.
 
-CommandLineTools wrapping custom scripts should represent the script as an input parameter with the script file as a default value.  Use @secondaryFiles@ for scripts that consist of multiple files.  For example:
+CommandLineTools wrapping custom scripts should represent the script as an input parameter with the script file as a default value.  Use @secondaryFiles@ for scripts that consist of multiple files.  For example:
 
-<pre>
+{% codeblock as yaml %}
 cwlVersion: v1.0
 class: CommandLineTool
 baseCommand: python
@@ -40,15 +43,57 @@ outputs:
     type: File
     outputBinding:
       glob: "*.fastq"
-</pre>
+{% endcodeblock %}
 
-You can get the designated temporary directory using @$(runtime.tmpdir)@ in your CWL file, or from the @$TMPDIR@ environment variable in your script.
+You can get the designated temporary directory using @$(runtime.tmpdir)@ in your CWL file, or from the @$TMPDIR@ environment variable in your script.
 
-Similarly, you can get the designated output directory using $(runtime.outdir), or from the @HOME@ environment variable in your script.
+Similarly, you can get the designated output directory using $(runtime.outdir), or from the @HOME@ environment variable in your script.
 
-* Use @ExpressionTool@ to efficiently rearrange input files between steps of a Workflow.  For example, the following expression accepts a directory containing files paired by @_R1_@ and @_R2_@ and produces an array of Directories containing each pair.
+Avoid specifying resource requirements in CommandLineTool.  Prefer to specify them in the workflow.  You can provide a default resource requirement in the top level @hints@ section, and individual steps can override it with their own resource requirement.
 
-<pre>
+{% codeblock as yaml %}
+cwlVersion: v1.0
+class: Workflow
+inputs:
+  inp: File
+hints:
+  ResourceRequirement:
+    ramMin: 1000
+    coresMin: 1
+    tmpdirMin: 45000
+steps:
+  step1:
+    in: {inp: inp}
+    out: [out]
+    run: tool1.cwl
+  step2:
+    in: {inp: step1/inp}
+    out: [out]
+    run: tool2.cwl
+    hints:
+      ResourceRequirement:
+        ramMin: 2000
+        coresMin: 2
+        tmpdirMin: 90000
+{% endcodeblock %}
+
+h3. Upgrading to CWL v1.1
+
+CWL v1.1 introduces several features to the standard that were previously available as Arvados extensions.  CWL v1.1 syntax is backwards compatible with v1.0, so you can just change @cwlVersion: v1.0@ to @cwlVersion: v1.1@ and update your script to using the standard features.  On Arvados, there is only one behavior change between CWL v1.0 and v1.1 to be aware of: for performance reasons, Directory listings are no longer loaded by default.  To control loading Directory listings, use "loadListing":https://www.commonwl.org/v1.1/CommandLineTool.html#CommandInputParameter or "LoadListingRequirement":https://www.commonwl.org/v1.1/CommandLineTool.html#LoadListingRequirement (the extension @cwltool:LoadListingRequirement@ is deprecated.)
+
+If a step requires network access, use "NetworkAccess":https://www.commonwl.org/v1.1/CommandLineTool.html#NetworkAccess instead of the Arvados-specific "arv:APIRequirement":cwl-extensions.html#APIRequirement .
+
+To prevent misbehaving steps from running forever and wasting resources, you can fail the step if it exceeds a certain running time with "ToolTimeLimit":https://www.commonwl.org/v1.1/CommandLineTool.html#ToolTimeLimit instead of the deprecated @cwltool:TimeLimit@ .
+
+To control if an individual step can be reused, use "WorkReuse":https://www.commonwl.org/v1.1/CommandLineTool.html#WorkReuse instead of the deprecated @arv:ReuseRequirement@.
+
+h2(#performance). Performance
+
+When combining a parameter value with a string, such as adding a filename extension, write @$(inputs.file.basename).ext@ instead of @$(inputs.file.basename + 'ext')@.  The first form is evaluated as a simple text substitution, the second form (using the @+@ operator) is evaluated as an arbitrary Javascript expression and requires that you declare @InlineJavascriptRequirement@.
+
+Use @ExpressionTool@ to efficiently rearrange input files between steps of a Workflow.  For example, the following expression accepts a directory containing files paired by @_R1_@ and @_R2_@ and produces an array of Directories containing each pair.
+
+{% codeblock as yaml %}
 class: ExpressionTool
 cwlVersion: v1.0
 inputs:
@@ -78,41 +123,15 @@ expression: |
     }
     return {"out": dirs};
   }
-</pre>
-
-* Avoid specifying resource requirements in CommandLineTool.  Prefer to specify them in the workflow.  You can provide a default resource requirement in the top level @hints@ section, and individual steps can override it with their own resource requirement.
+{% endcodeblock %}
 
-<pre>
-cwlVersion: v1.0
-class: Workflow
-inputs:
-  inp: File
-hints:
-  ResourceRequirement:
-    ramMin: 1000
-    coresMin: 1
-    tmpdirMin: 45000
-steps:
-  step1:
-    in: {inp: inp}
-    out: [out]
-    run: tool1.cwl
-  step2:
-    in: {inp: step1/inp}
-    out: [out]
-    run: tool2.cwl
-    hints:
-      ResourceRequirement:
-        ramMin: 2000
-        coresMin: 2
-        tmpdirMin: 90000
-</pre>
+Available compute nodes types vary over time and across different cloud providers, so try to limit the RAM requirement to what the program actually needs.  However, if you need to target a specific compute node type, see this discussion on "calculating RAM request and choosing instance type for containers.":{{site.baseurl}}/api/execution.html#RAM
 
-Instead of scattering separate steps, prefer to scatter over a subworkflow.
+Instead of scattering separate steps, prefer to scatter over a subworkflow.
 
 With the following pattern, @step1@ has to wait for all samples to complete before @step2@ can start computing on any samples.  This means a single long-running sample can prevent the rest of the workflow from moving on:
 
-<pre>
+{% codeblock as yaml %}
 cwlVersion: v1.0
 class: Workflow
 inputs:
@@ -133,12 +152,12 @@ steps:
     scatter: inp
     out: [out]
     run: tool3.cwl
-</pre>
+{% endcodeblock %}
 
 Instead, scatter over a subworkflow.  In this pattern, a sample can proceed to @step2@ as soon as @step1@ is done, independently of any other samples.
 Example: (note, the subworkflow can also be put in a separate file)
 
-<pre>
+{% codeblock as yaml %}
 cwlVersion: v1.0
 class: Workflow
 steps:
@@ -167,4 +186,6 @@ steps:
           in: {inp: step2/inp}
           out: [out]
           run: tool3.cwl
-</pre>
+{% endcodeblock %}
+
+If you have a sequence of short-running steps (less than 1-2 minutes each), use the Arvados extension "arv:RunInSingleContainer":cwl-extensions.html#RunInSingleContainer to avoid scheduling and data transfer overhead by running all the steps together at once.  To use this feature, @cwltool@ must be installed in the container image.