Przejdź do treści

Przepływy pracy złożone z przepływów pracy

Tłumaczenie wspomagane przez AI - dowiedz się więcej i zasugeruj ulepszenia

Podczas tworzenia potoku często zdarza się, że tworzysz podobne sekwencje procesów dla różnych typów danych lub etapów analizy. Możesz kończyć kopiując i wklejając te sekwencje procesów, co prowadzi do zduplikowanego kodu, który jest trudny w utrzymaniu; albo możesz stworzyć jeden masywny przepływ pracy, który jest trudny do zrozumienia i modyfikacji.

Jedną z najpotężniejszych funkcji Nextflow jest jego zdolność do komponowania złożonych potoków z mniejszych, wielokrotnego użytku modułów przepływu pracy. To modularne podejście sprawia, że potoki są łatwiejsze do rozwijania, testowania i utrzymania.

Cele nauki

W tej misji pobocznej zbadamy, jak rozwijać moduły przepływu pracy, które można testować i używać osobno, komponować te moduły w większy potok oraz zarządzać przepływem danych między modułami.

Pod koniec tej misji pobocznej będziesz w stanie:

  • Rozbijać złożone potoki na logiczne, wielokrotnego użytku jednostki
  • Testować każdy moduł przepływu pracy niezależnie
  • Łączyć i dopasowywać przepływy pracy, aby tworzyć nowe potoki
  • Udostępniać wspólne moduły przepływu pracy w różnych potokach
  • Sprawić, by Twój kod był bardziej łatwy w utrzymaniu i zrozumieniu

Te umiejętności pomogą Ci budować złożone potoki, zachowując czystą, łatwą w utrzymaniu strukturę kodu.

Wymagania wstępne

Przed podjęciem tej misji pobocznej powinieneś:

  • Ukończyć tutorial Hello Nextflow lub równoważny kurs dla początkujących.
  • Swobodnie posługiwać się podstawowymi konceptami i mechanizmami Nextflow (procesy, kanały, operatory, moduły)

0. Rozpoczęcie

Otwórz środowisko szkoleniowe

Jeśli jeszcze tego nie zrobiłeś, upewnij się, że otworzysz środowisko szkoleniowe zgodnie z opisem w Konfiguracja środowiska.

Open in GitHub Codespaces

Przejdź do katalogu projektu

Przejdźmy do katalogu, w którym znajdują się pliki do tego tutoriala.

cd side-quests/workflows_of_workflows

Możesz ustawić VSCode, aby skupił się na tym katalogu:

code .

Przejrzyj materiały

Znajdziesz katalog modules zawierający kilka definicji procesów, które rozwijają to, czego nauczyłeś się w 'Hello Nextflow':

Zawartość katalogu
modules/
├── say_hello.nf             # Tworzy powitanie (z Hello Nextflow)
├── say_hello_upper.nf       # Konwertuje na wielkie litery (z Hello Nextflow)
├── timestamp_greeting.nf    # Dodaje znaczniki czasu do powitań
├── validate_name.nf         # Waliduje nazwy wejściowe
└── reverse_text.nf          # Odwraca zawartość tekstu

Przejrzyj zadanie

Twoim wyzwaniem jest złożenie tych modułów w dwa oddzielne przepływy pracy, które następnie skomponujemy w główny przepływ pracy:

  • GREETING_WORKFLOW, który waliduje nazwy, tworzy powitania i dodaje znaczniki czasu
  • TRANSFORM_WORKFLOW, który konwertuje tekst na wielkie litery i odwraca go

Lista gotowości

Myślisz, że jesteś gotowy do rozpoczęcia?

  • Rozumiem cel tego kursu i jego wymagania wstępne
  • Moje środowisko codespace działa
  • Ustawiłem odpowiednio mój katalog roboczy
  • Rozumiem zadanie

Jeśli możesz zaznaczyć wszystkie pola, możesz zaczynać.


1. Utwórz przepływ pracy powitania

Zacznijmy od stworzenia przepływu pracy, który waliduje nazwy i generuje powitania ze znacznikami czasu.

1.1. Utwórz strukturę przepływu pracy

Utwórz katalog i plik przepływu pracy
mkdir -p workflows
touch workflows/greeting.nf

1.2. Dodaj kod pierwszego (pod)przepływu pracy

Dodaj ten kod do workflows/greeting.nf:

workflows/greeting.nf
include { VALIDATE_NAME } from '../modules/validate_name'
include { SAY_HELLO } from '../modules/say_hello'
include { TIMESTAMP_GREETING } from '../modules/timestamp_greeting'

workflow {

    names_ch = channel.of('Alice', 'Bob', 'Charlie')

    // Połącz procesy: waliduj -> utwórz pozdrowienie -> dodaj znacznik czasu
    validated_ch = VALIDATE_NAME(names_ch)
    greetings_ch = SAY_HELLO(validated_ch)
    timestamped_ch = TIMESTAMP_GREETING(greetings_ch)
}

To jest kompletny przepływ pracy o strukturze podobnej do tych, które widziałeś w tutorialu 'Hello Nextflow', który możemy testować niezależnie. Spróbujmy tego teraz:

nextflow run workflows/greeting.nf
Wyjście polecenia
N E X T F L O W  ~  version 24.10.0
Launching `workflows/greeting.nf` [peaceful_montalcini] DSL2 - revision: 90f61b7093
executor >  local (9)
[51/4f980f] process > VALIDATE_NAME (validating Bob)                    [100%] 3 of 3 ✔
[2b/dd8dc2] process > SAY_HELLO (greeting Bob)                          [100%] 3 of 3 ✔
[8e/882565] process > TIMESTAMP_GREETING (adding timestamp to greeting) [100%] 3 of 3 ✔

Działa zgodnie z oczekiwaniami, ale aby uczynić go komponowalnym, musimy zmienić kilka rzeczy.

1.3. Uczyń przepływ pracy komponowalnym

Komponowalne przepływy pracy mają kilka różnic w porównaniu z tymi, które widziałeś w tutorialu 'Hello Nextflow':

  • Blok workflow musi być nazwany
  • Wejścia są deklarowane za pomocą słowa kluczowego take:
  • Zawartość przepływu pracy jest umieszczona wewnątrz bloku main:
  • Wyjścia są deklarowane za pomocą słowa kluczowego emit:

Zaktualizujmy przepływ pracy powitania, aby pasował do tej struktury. Zmień kod na następujący:

workflows/greeting.nf
include { VALIDATE_NAME } from '../modules/validate_name'
include { SAY_HELLO } from '../modules/say_hello'
include { TIMESTAMP_GREETING } from '../modules/timestamp_greeting'

workflow GREETING_WORKFLOW {
    take:
        names_ch        // Kanał wejściowy z imionami

    main:
        // Połącz procesy: waliduj -> utwórz pozdrowienie -> dodaj znacznik czasu
        validated_ch = VALIDATE_NAME(names_ch)
        greetings_ch = SAY_HELLO(validated_ch)
        timestamped_ch = TIMESTAMP_GREETING(greetings_ch)

    emit:
        greetings = greetings_ch      // Oryginalne pozdrowienia
        timestamped = timestamped_ch  // Pozdrowienia ze znacznikiem czasu
}

Widać, że przepływ pracy jest teraz nazwany i ma bloki take: oraz emit:, a to są połączenia, których użyjemy do komponowania przepływu pracy wyższego poziomu. Zawartość przepływu pracy jest również umieszczona wewnątrz bloku main:. Zauważ również, że usunęliśmy deklarację kanału wejściowego names_ch, ponieważ jest on teraz przekazywany jako argument do przepływu pracy.

Przetestujmy przepływ pracy ponownie, aby zobaczyć, czy działa zgodnie z oczekiwaniami:

nextflow run workflows/greeting.nf
Wyjście polecenia
N E X T F L O W  ~  version 24.10.0
Launching `workflows/greeting.nf` [high_brahmagupta] DSL2 - revision: 8f5857af25
No entry workflow specified

To informuje Cię o kolejnym nowym koncepcje, 'przepływie pracy wejściowym'. Przepływ pracy wejściowy to przepływ pracy, który jest wywoływany po uruchomieniu skryptu Nextflow. Domyślnie Nextflow użyje nienazwanego przepływu pracy jako przepływu pracy wejściowego, gdy jest obecny, i to robiłeś do tej pory, z blokami workflow zaczynającymi się w ten sposób:

hello.nf
workflow {

Ale nasz przepływ pracy powitania nie ma nienazwanego przepływu pracy, zamiast tego mamy nazwany przepływ pracy:

workflows/greeting.nf
workflow GREETING_WORKFLOW {

Dlatego Nextflow zgłosił błąd i nie zrobił tego, czego chcieliśmy.

Nie dodaliśmy składni take:/emit:, abyśmy mogli wywołać przepływ pracy bezpośrednio - zrobiliśmy to, abyśmy mogli komponować go z innymi przepływami pracy. Rozwiązaniem jest utworzenie głównego skryptu z nienazwanym przepływem pracy wejściowym, który importuje i wywołuje nasz nazwany przepływ pracy.

1.4. Utwórz i przetestuj główny przepływ pracy

Teraz utworzymy główny przepływ pracy, który importuje i używa przepływu pracy greeting.

Utwórz main.nf:

main.nf
1
2
3
4
5
6
7
8
9
include { GREETING_WORKFLOW } from './workflows/greeting'

workflow {
    names = channel.of('Alice', 'Bob', 'Charlie')
    GREETING_WORKFLOW(names)

    GREETING_WORKFLOW.out.greetings.view { "Original: $it" }
    GREETING_WORKFLOW.out.timestamped.view { "Timestamped: $it" }
}

Zauważ, że nasz wpis workflow w tym pliku jest nienazwany, i to dlatego, że będziemy go używać jako przepływu pracy wejściowego.

Uruchom to i zobacz wyjście:

nextflow run main.nf
Wyjście polecenia
N E X T F L O W  ~  version 24.10.0
Launching `main.nf` [goofy_mayer] DSL2 - revision: 543f8742fe
executor >  local (9)
[05/3cc752] process > GREETING_WORKFLOW:VALIDATE_NAME (validating Char... [100%] 3 of 3 ✔
[b1/b56ecf] process > GREETING_WORKFLOW:SAY_HELLO (greeting Charlie)      [100%] 3 of 3 ✔
[ea/342168] process > GREETING_WORKFLOW:TIMESTAMP_GREETING (adding tim... [100%] 3 of 3 ✔
Original: /workspaces/training/side_quests/workflows_of_workflows/work/bb/c8aff3df0ebc15a4d7d35f736db44c/Alice-output.txt
Original: /workspaces/training/side_quests/workflows_of_workflows/work/fb/fa877776e8a5d90b537b1bcd3b6f5b/Bob-output.txt
Original: /workspaces/training/side_quests/workflows_of_workflows/work/b1/b56ecf938fda8bcbec211847c8f0be/Charlie-output.txt
Timestamped: /workspaces/training/side_quests/workflows_of_workflows/work/06/877bc909f140bbf8223343450cea36/timestamped_Alice-output.txt
Timestamped: /workspaces/training/side_quests/workflows_of_workflows/work/aa/bd31b71cdb745b7c155ca7f8837b8a/timestamped_Bob-output.txt
Timestamped: /workspaces/training/side_quests/workflows_of_workflows/work/ea/342168d4ba04cc899a89c56cbfd9b0/timestamped_Charlie-output.txt

Działa! Opakaliśmy nazwany przepływ pracy powitania w główny przepływ pracy z nienazwanym blokiem wejściowym workflow. Główny przepływ pracy używa przepływu pracy GREETING_WORKFLOW prawie (nie całkiem) jak procesu i przekazuje kanał names jako argument.

Wnioski

W tej sekcji nauczyłeś się kilku ważnych koncepcji:

  • Nazwane przepływy pracy: Tworzenie nazwanego przepływu pracy (GREETING_WORKFLOW), który można importować i ponownie używać
  • Interfejsy przepływu pracy: Definiowanie jasnych wejść za pomocą take: i wyjść za pomocą emit:, aby utworzyć komponowalny przepływ pracy
  • Punkty wejścia: Zrozumienie, że Nextflow potrzebuje nienazwanego przepływu pracy wejściowego, aby uruchomić skrypt
  • Komponowanie przepływu pracy: Importowanie i używanie nazwanego przepływu pracy w innym przepływie pracy
  • Przestrzenie nazw przepływu pracy: Dostęp do wyjść przepływu pracy za pomocą przestrzeni nazw .out (GREETING_WORKFLOW.out.greetings)

Masz teraz działający przepływ pracy powitania, który:

  • Przyjmuje kanał nazw jako wejście
  • Waliduje każdą nazwę
  • Tworzy powitanie dla każdej poprawnej nazwy
  • Dodaje znaczniki czasu do powitań
  • Udostępnia zarówno oryginalne, jak i powitania ze znacznikami czasu jako wyjścia

To modularne podejście pozwala testować przepływ pracy powitania niezależnie lub używać go jako komponentu w większych potokach.


2. Dodaj przepływ pracy transformacji

Teraz stwórzmy przepływ pracy, który stosuje transformacje tekstowe do powitań.

2.1. Utwórz plik przepływu pracy

touch workflows/transform.nf

2.2. Dodaj kod przepływu pracy

Dodaj ten kod do workflows/transform.nf:

workflows/transform.nf
include { SAY_HELLO_UPPER } from '../modules/say_hello_upper'
include { REVERSE_TEXT } from '../modules/reverse_text'

workflow TRANSFORM_WORKFLOW {
    take:
        input_ch         // Kanał wejściowy z wiadomościami

    main:
        // Zastosuj transformacje sekwencyjnie
        upper_ch = SAY_HELLO_UPPER(input_ch)
        reversed_ch = REVERSE_TEXT(upper_ch)

    emit:
        upper = upper_ch        // Pozdrowienia pisane wielkimi literami
        reversed = reversed_ch  // Odwrócone pozdrowienia pisane wielkimi literami
}

Nie będziemy powtarzać wyjaśnienia składni komponowalnej tutaj, ale zauważ, że nazwany przepływ pracy jest ponownie zadeklarowany z blokami take: i emit:, a zawartość przepływu pracy jest umieszczona wewnątrz bloku main:.

2.3. Zaktualizuj główny przepływ pracy

Zaktualizuj main.nf, aby używał obu przepływów pracy:

main.nf
include { GREETING_WORKFLOW } from './workflows/greeting'
include { TRANSFORM_WORKFLOW } from './workflows/transform'

workflow {
    names = channel.of('Alice', 'Bob', 'Charlie')

    // Uruchom workflow powitania
    GREETING_WORKFLOW(names)

    // Uruchom workflow transformacji
    TRANSFORM_WORKFLOW(GREETING_WORKFLOW.out.timestamped)

    // Wyświetl wyniki
    TRANSFORM_WORKFLOW.out.upper.view { "Uppercase: $it" }
    TRANSFORM_WORKFLOW.out.reversed.view { "Reversed: $it" }
}

Uruchom kompletny potok:

nextflow run main.nf
Wyjście polecenia
N E X T F L O W  ~  version 24.10.0
Launching `main.nf` [sick_kimura] DSL2 - revision: 8dc45fc6a8
executor >  local (13)
executor >  local (15)
[83/1b51f4] process > GREETING_WORKFLOW:VALIDATE_NAME (validating Alice)  [100%] 3 of 3 ✔
[68/556150] process > GREETING_WORKFLOW:SAY_HELLO (greeting Alice)        [100%] 3 of 3 ✔
[de/511abd] process > GREETING_WORKFLOW:TIMESTAMP_GREETING (adding tim... [100%] 3 of 3 ✔
[cd/e6a7e0] process > TRANSFORM_WORKFLOW:SAY_HELLO_UPPER (converting t... [100%] 3 of 3 ✔
[f0/74ba4a] process > TRANSFORM_WORKFLOW:REVERSE_TEXT (reversing UPPER... [100%] 3 of 3 ✔
Uppercase: /workspaces/training/side_quests/workflows_of_workflows/work/a0/d4f5df4d6344604498fa47a6084a11/UPPER-timestamped_Bob-output.txt
Uppercase: /workspaces/training/side_quests/workflows_of_workflows/work/69/b5e37f6c79c2fd38adb75d0eca8f87/UPPER-timestamped_Charlie-output.txt
Uppercase: /workspaces/training/side_quests/workflows_of_workflows/work/cd/e6a7e0b17e7d5a2f71bb8123cd53a7/UPPER-timestamped_Alice-output.txt
Reversed: /workspaces/training/side_quests/workflows_of_workflows/work/7a/7a222f7957b35d1d121338566a24ac/REVERSED-UPPER-timestamped_Bob-output.txt
Reversed: /workspaces/training/side_quests/workflows_of_workflows/work/46/8d19af62e33a5a6417c773496e0f90/REVERSED-UPPER-timestamped_Charlie-output.txt
Reversed: /workspaces/training/side_quests/workflows_of_workflows/work/f0/74ba4a10d9ef5c82f829d1c154d0f6/REVERSED-UPPER-timestamped_Alice-output.txt

Jeśli spojrzysz na jeden z tych odwróconych plików, zobaczysz, że jest to wersja powitania w wielkich literach, odwrócona:

cat /workspaces/training/side_quests/workflows_of_workflows/work/f0/74ba4a10d9ef5c82f829d1c154d0f6/REVERSED-UPPER-timestamped_Alice-output.txt
Zawartość odwróconego pliku
!ECILA ,OLLEH ]04:50:71 60-30-5202[

Wnioski

Powinieneś teraz mieć kompletny potok, który:

  • Przetwarza nazwy przez przepływ pracy powitania
  • Przekazuje powitania ze znacznikami czasu do przepływu pracy transformacji
  • Produkuje zarówno wersje powitań w wielkich literach, jak i odwrócone

Podsumowanie

W tej misji pobocznej zbadaliśmy potężną koncepcję komponowania przepływu pracy w Nextflow, która pozwala nam budować złożone potoki z mniejszych, wielokrotnego użytku komponentów.

To modularne podejście oferuje kilka zalet w porównaniu z monolitycznymi potokami:

  • Każdy przepływ pracy można rozwijać, testować i debugować niezależnie
  • Przepływy pracy można ponownie używać w różnych potokach
  • Ogólna struktura potoku staje się bardziej czytelna i łatwiejsza w utrzymaniu
  • Zmiany w jednym przepływie pracy niekoniecznie wpływają na inne, jeśli interfejsy pozostają spójne
  • Punkty wejścia można skonfigurować do uruchamiania różnych części potoku w razie potrzeby

Ważne jest jednak, aby zauważyć, że chociaż wywoływanie przepływów pracy jest trochę podobne do wywoływania procesów, nie jest to tak naprawdę to samo. Nie możesz na przykład uruchomić przepływu pracy N razy, wywołując go z kanałem o rozmiarze N - musiałbyś przekazać kanał o rozmiarze N do przepływu pracy i iterować wewnętrznie.

Stosowanie tych technik w swojej pracy umożliwi Ci budowanie bardziej wyrafinowanych potoków Nextflow, które mogą obsługiwać złożone zadania bioinformatyczne, pozostając jednocześnie łatwymi w utrzymaniu i skalowalnymi.

Kluczowe wzorce

  1. Struktura przepływu pracy: Zdefiniowaliśmy jasne wejścia i wyjścia dla każdego przepływu pracy, używając składni take: i emit:, tworząc dobrze zdefiniowane interfejsy między komponentami, i opakaliśmy logikę przepływu pracy w bloku main:.

    workflow EXAMPLE_WORKFLOW {
        take:
            // Kanały wejściowe są deklarowane tutaj
            input_ch
    
        main:
            // Logika workflow znajduje się tutaj
            // Tutaj wywoływane są procesy i manipulowane są kanały
            result_ch = SOME_PROCESS(input_ch)
    
        emit:
            // Kanały wyjściowe są deklarowane tutaj
            output_ch = result_ch
    }
    
  2. Importy przepływu pracy: Zbudowaliśmy dwa niezależne moduły przepływu pracy i zaimportowaliśmy je do głównego potoku za pomocą instrukcji include.

    • Zaimportuj pojedynczy przepływ pracy
    include { WORKFLOW_NAME } from './path/to/workflow'
    
    • Zaimportuj wiele przepływów pracy
    include { WORKFLOW_A; WORKFLOW_B } from './path/to/workflows'
    
    • Zaimportuj z aliasem, aby uniknąć konfliktów nazw
    include { WORKFLOW_A as WORKFLOW_A_ALIAS } from './path/to/workflow'
    
  3. Punkty wejścia: Nextflow wymaga nienazwanego przepływu pracy wejściowego, aby wiedzieć, gdzie rozpocząć wykonanie. Ten przepływ pracy wejściowy wywołuje Twoje nazwane przepływy pracy.

    • Nienazwany przepływ pracy (punkt wejścia)
    workflow {
        // To jest punkt wejścia, gdy skrypt jest uruchamiany
        NAMED_WORKFLOW(input_ch)
    }
    
    • Nazwany przepływ pracy (wywoływany z przepływu pracy wejściowego)
    workflow NAMED_WORKFLOW {
        // Musi być wywołany z głównego workflow
    }
    
  4. Zarządzanie przepływem danych: Nauczyliśmy się, jak uzyskać dostęp do wyjść przepływu pracy za pomocą notacji przestrzeni nazw (WORKFLOW_NAME.out.channel_name) i przekazywać je do innych przepływów pracy.

    WORKFLOW_A(input_ch)
    WORKFLOW_B(WORKFLOW_A.out.some_channel)
    

Dodatkowe zasoby


Co dalej?

Wróć do menu Misji pobocznych lub kliknij przycisk w prawym dolnym rogu strony, aby przejść do następnego tematu na liście.