Skip to content

Commit 19f87d1

Browse files
committed
Add progression
1 parent cdd6bba commit 19f87d1

File tree

1 file changed

+174
-23
lines changed

1 file changed

+174
-23
lines changed

docs/side_quests/workflows_of_workflows.md

Lines changed: 174 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ modules/
4848
└── reverse_text.nf # Reverses text content
4949
```
5050

51-
We going to compose these modules into two separate workflows that we will then compose into a main workflow.
51+
We're going to compose these modules into two separate workflows that we will then compose into a main workflow.
5252

5353
---
5454

@@ -72,6 +72,50 @@ include { VALIDATE_NAME } from '../modules/validate_name'
7272
include { SAY_HELLO } from '../modules/say_hello'
7373
include { TIMESTAMP_GREETING } from '../modules/timestamp_greeting'
7474
75+
workflow {
76+
77+
names_ch = Channel.from('Alice', 'Bob', 'Charlie')
78+
79+
// Chain processes: validate -> create greeting -> add timestamp
80+
validated_ch = VALIDATE_NAME(names_ch)
81+
greetings_ch = SAY_HELLO(validated_ch)
82+
timestamped_ch = TIMESTAMP_GREETING(greetings_ch)
83+
}
84+
```
85+
86+
This is a complete workflow, with a structure similar to the ones you saw in the 'Hello Nextflow' tutorial, that we can test independently. Let's try that now:
87+
88+
```bash title="Run the greeting workflow"
89+
nextflow run workflows/greeting.nf
90+
```
91+
92+
```console title="Expected output"
93+
N E X T F L O W ~ version 24.10.0
94+
Launching `workflows/greeting.nf` [peaceful_montalcini] DSL2 - revision: 90f61b7093
95+
executor > local (9)
96+
[51/4f980f] process > VALIDATE_NAME (validating Bob) [100%] 3 of 3 ✔
97+
[2b/dd8dc2] process > SAY_HELLO (greeting Bob) [100%] 3 of 3 ✔
98+
[8e/882565] process > TIMESTAMP_GREETING (adding timestamp to greeting) [100%] 3 of 3 ✔
99+
```
100+
101+
This works as expected, but to make it composable there's a few things we need to change.
102+
103+
### 1.3. Make the workflow composable
104+
105+
Composable workflows have some differences from the ones you saw in the 'Hello Nextflow' tutorial:
106+
107+
- The workflow block needs to be named
108+
- Inputs are declared using the `take:` keyword
109+
- Workflow content is placed inside the `main:` block
110+
- Outputs are declared using the `emit:` keyword
111+
112+
Let's update the greeting workflow to match this structure. Change the code to the following:
113+
114+
```groovy title="workflows/greeting.nf" linenums="1"
115+
include { VALIDATE_NAME } from '../modules/validate_name'
116+
include { SAY_HELLO } from '../modules/say_hello'
117+
include { TIMESTAMP_GREETING } from '../modules/timestamp_greeting'
118+
75119
workflow GREETING_WORKFLOW {
76120
take:
77121
names_ch // Input channel with names
@@ -88,9 +132,56 @@ workflow GREETING_WORKFLOW {
88132
}
89133
```
90134

91-
This is already a complete workflow that we can test independently. You might notice that it's very similar to the `hello` workflow from the 'Hello Nextflow' tutorial, but with some additional syntax to allow it to receive input ('take:') and produce output ('emit:'). These are the connections we will use to compose a higher level workflow.
135+
You can see that the workflow is now named and has a `take:` and `emit:` block, and these are the connections we will use to compose a higher level workflow.
136+
The workflow content is also placed inside the `main:` block. Note also that we have removed the `names_ch` input channel declaration, as it's now passed as an argument to the workflow.
137+
138+
Let's test the workflow again to see if it works as expected:
139+
140+
```bash title="Run the greeting workflow"
141+
nextflow run workflows/greeting.nf
142+
```
143+
144+
What you'll actually see in response is:
145+
146+
```console title="Expected output"
147+
N E X T F L O W ~ version 24.10.0
148+
Launching `workflows/greeting.nf` [high_brahmagupta] DSL2 - revision: 8f5857af25
149+
WARN: No entry workflow specified
150+
```
151+
152+
This tells you about another new concept, an 'entry workflow'. The entry workflow is the workflow that gets called when you run a Nextflow script. By default, Nextflow will use an un-named workflow as the entry workflow, when present, and that's what you've been doing so far, with workflow blocks starting like this:
153+
154+
```groovy title="hello.nf" linenums="1"
155+
workflow {
156+
```
157+
158+
But our greeting workflow doesn't have an un-named workflow, rather we have a named workflow:
159+
160+
```groovy title="workflows/greeting.nf" linenums="1"
161+
workflow GREETING_WORKFLOW {
162+
```
163+
164+
... so Nextflow will throw an error. We can actually tell Nextflow to use our named workflow as the entry workflow by adding this line to Nextflow's command line:
165+
166+
```bash title="Run the greeting workflow"
167+
nextflow run workflows/greeting.nf -entry GREETING_WORKFLOW
168+
```
169+
170+
This will also throw an error, because the workflow is expecting an input channel:
171+
172+
```console title="Expected output"
173+
N E X T F L O W ~ version 24.10.0
174+
Launching `workflows/greeting.nf` [compassionate_fermi] DSL2 - revision: 8f5857af25
175+
ERROR ~ Workflow `GREETING_WORKFLOW` declares 1 input channels but 0 were given
176+
177+
-- Check '.nextflow.log' file for details
178+
```
179+
180+
... but if you wanted to call a named workflow that didn't require inputs, you could call it this way.
181+
182+
But we didn't add that syntax so we could call the workflow directly, we did it so we could compose it with other workflows. Let's start by creating a main workflow that imports and uses the `greeting` workflow.
92183

93-
### 1.3. Create and test the main workflow
184+
### 1.4. Create and test the main workflow
94185

95186
Now we will create a main workflow that imports and uses the `greeting` workflow.
96187

@@ -109,14 +200,16 @@ workflow {
109200
110201
```
111202

203+
Note that our workflow entry in this file is un-named, and that's because we're going to use it as an entry workflow.
204+
112205
Run this and see the output:
113206

114207
```bash title="Run the workflow"
115208
nextflow run main.nf
116209
```
117210

118211
```console title="Expected output"
119-
N E X T F L O W ~ version 23.10.1
212+
N E X T F L O W ~ version 24.10.0
120213
Launching `main.nf` [goofy_mayer] DSL2 - revision: 543f8742fe
121214
executor > local (9)
122215
[05/3cc752] process > GREETING_WORKFLOW:VALIDATE_NAME (validating Char... [100%] 3 of 3 ✔
@@ -130,14 +223,27 @@ Timestamped: /workspaces/training/side_quests/workflows_of_workflows/work/aa/bd3
130223
Timestamped: /workspaces/training/side_quests/workflows_of_workflows/work/ea/342168d4ba04cc899a89c56cbfd9b0/timestamped_Charlie-output.txt
131224
```
132225

226+
It works! We've wrapped the named greeting workflow in a main workflow with an un-named entry `workflow` block. The main workflow is using the `GREETING_WORKFLOW` workflow almost (not quite) like a process, and passing the `names` channel as an argument.
227+
133228
### Takeaway
134229

135-
You should now have a working greeting workflow that:
230+
In this section, you've learned several important concepts:
231+
232+
- **Named Workflows**: Creating a named workflow (`GREETING_WORKFLOW`) that can be imported and reused
233+
- **Workflow Interfaces**: Defining clear inputs with `take:` and outputs with `emit:` to create a composable workflow
234+
- **Entry Points**: Understanding that Nextflow needs an entry workflow (either unnamed or specified with `-entry`)
235+
- **Workflow Composition**: Importing and using a named workflow within another workflow
236+
- **Workflow Namespaces**: Accessing workflow outputs using the `.out` namespace (`GREETING_WORKFLOW.out.greetings`)
237+
238+
You now have a working greeting workflow that:
136239

137240
- Takes a channel of names as input
138241
- Validates each name
139242
- Creates a greeting for each valid name
140243
- Adds timestamps to the greetings
244+
- Exposes both original and timestamped greetings as outputs
245+
246+
This modular approach allows you to test the greeting workflow independently or use it as a component in larger pipelines.
141247

142248
---
143249

@@ -174,26 +280,28 @@ workflow TRANSFORM_WORKFLOW {
174280
}
175281
```
176282

283+
We won't repeat the explanation of the composable syntax here, but note the named workflow is again declared with a `take:` and `emit:` block, and the workflow content is placed inside the `main:` block.
284+
177285
### 2.3. Update the main workflow
178286

179287
Update `main.nf` to use both workflows:
180288

181289
```groovy title="main.nf" linenums="1"
182-
include { SAY_HELLO_UPPER } from '../modules/say_hello_upper'
183-
include { REVERSE_TEXT } from '../modules/reverse_text'
290+
include { GREETING_WORKFLOW } from './workflows/greeting'
291+
include { TRANSFORM_WORKFLOW } from './workflows/transform'
184292
185-
workflow TRANSFORM_WORKFLOW {
186-
take:
187-
input_ch // Input channel with messages
293+
workflow {
294+
names = Channel.from('Alice', 'Bob', 'Charlie')
188295
189-
main:
190-
// Apply transformations in sequence
191-
upper_ch = SAY_HELLO_UPPER(input_ch)
192-
reversed_ch = REVERSE_TEXT(upper_ch)
296+
// Run the greeting workflow
297+
GREETING_WORKFLOW(names)
193298
194-
emit:
195-
upper = upper_ch // Uppercase greetings
196-
reversed = reversed_ch // Reversed uppercase greetings
299+
// Run the transform workflow
300+
TRANSFORM_WORKFLOW(GREETING_WORKFLOW.out.timestamped)
301+
302+
// View results
303+
TRANSFORM_WORKFLOW.out.upper.view { "Uppercase: $it" }
304+
TRANSFORM_WORKFLOW.out.reversed.view { "Reversed: $it" }
197305
}
198306
```
199307

@@ -204,7 +312,7 @@ nextflow run main.nf
204312
```
205313

206314
```console title="Expected output"
207-
N E X T F L O W ~ version 23.10.1
315+
N E X T F L O W ~ version 24.10.0
208316
Launching `main.nf` [sick_kimura] DSL2 - revision: 8dc45fc6a8
209317
executor > local (13)
210318
executor > local (15)
@@ -223,12 +331,13 @@ Reversed: /workspaces/training/side_quests/workflows_of_workflows/work/f0/74ba4a
223331

224332
If you take a look at one of those reversed files, you'll see that it's the uppercase version of the greeting reversed:
225333

226-
````bash title="Check a final output file"
227-
cat /workspaces/training/side_quests/workflows_of_workflows/work/f0/74ba4a10d9ef5c82f829d1c154d0f6/REVERSED-UPPER-timestamped_Alice-output.txt```
334+
```bash title="Check a final output file"
335+
cat /workspaces/training/side_quests/workflows_of_workflows/work/f0/74ba4a10d9ef5c82f829d1c154d0f6/REVERSED-UPPER-timestamped_Alice-output.txt
336+
```
228337

229338
```console title="Reversed file content"
230339
!ECILA ,OLLEH ]04:50:71 60-30-5202[
231-
````
340+
```
232341

233342
### Takeaway
234343

@@ -255,14 +364,19 @@ In this side quest, we've explored the powerful concept of workflow composition
255364

256365
5. **Practiced Modular Design**: We experienced firsthand how breaking a pipeline into logical components makes the code more maintainable and easier to understand.
257366

367+
6. **Worked with Entry Points**: We learned that Nextflow requires an entry workflow (either unnamed or specified with `-entry`) to know where to start execution.
368+
369+
7. **Structured Workflow Content**: We wrapped workflow logic within the `main:` block.
370+
258371
This modular approach offers several advantages over monolithic pipelines:
259372

260373
- Each workflow can be developed, tested, and debugged independently
261374
- Workflows can be reused across different pipelines
262375
- The overall pipeline structure becomes more readable and maintainable
263376
- Changes to one workflow don't necessarily affect others if the interfaces remain consistent
377+
- Entry points can be configured to run different parts of your pipeline as needed
264378

265-
It's important to note that while calling workflows is a bit like calling processes, it's not the same. You can't, for example, run a workflow n times by calling it with a channel of size n- you would need to pass a channel of size n to the workflow and iterate internally.
379+
It's important to note that while calling workflows is a bit like calling processes, it's not the same. You can't, for example, run a workflow n times by calling it with a channel of size n - you would need to pass a channel of size n to the workflow and iterate internally.
266380

267381
By mastering workflow composition, you're now equipped to build more sophisticated Nextflow pipelines that can handle complex bioinformatics tasks while remaining maintainable and scalable.
268382

@@ -292,13 +406,50 @@ By mastering workflow composition, you're now equipped to build more sophisticat
292406
}
293407
```
294408

295-
3. **Workflow Composition**
409+
3. **Main Block Structure**
410+
411+
```nextflow
412+
workflow EXAMPLE_WORKFLOW {
413+
take:
414+
// Input channels are declared here
415+
input_ch
416+
417+
main:
418+
// Workflow logic goes here
419+
// This is where processes are called and channels are manipulated
420+
result_ch = SOME_PROCESS(input_ch)
421+
422+
emit:
423+
// Output channels are declared here
424+
output_ch = result_ch
425+
}
426+
```
427+
428+
4. **Workflow Composition**
429+
296430
```nextflow
297431
// Using explicit connections
298432
WORKFLOW_A(input_ch)
299433
WORKFLOW_B(WORKFLOW_A.out.some_channel)
300434
```
301435

436+
5. **Entry Points**
437+
438+
```nextflow
439+
// Unnamed workflow (default entry point)
440+
workflow {
441+
// This is automatically the entry point when the script is run
442+
}
443+
444+
// Named workflow (not an entry point by default)
445+
workflow NAMED_WORKFLOW {
446+
// This is not automatically run
447+
}
448+
449+
// Running a named workflow as entry point
450+
// nextflow run script.nf -entry NAMED_WORKFLOW
451+
```
452+
302453
## Resources
303454

304455
- [Nextflow Workflow Documentation](https://www.nextflow.io/docs/latest/workflow.html)

0 commit comments

Comments
 (0)