Conversation
Preserve streaming output and separate verbose stdout. Add five standalone shell lifecycle regression tests without changing alignment options.
SPPearce
left a comment
There was a problem hiding this comment.
This feels complicated.
Why does this tool not just make the output file and then gzip it?
|
That would be simpler, and seems a reasonable approach. I kept the existing streaming setup to make the correction small and avoid writing an intermediate uncompressed alignment. The problem is that the foreground command can finish successfully while compression is still running, or after the compressor has failed. Writing the alignment first and then running pigz would also address that, provided either failure makes the task fail. I’m happy to revise in that direction if that is your preference. I would retain the failure checks and verify the revised module through Nextflow/nf-test; the current five checks use shell stand-ins, so they do not establish native workflow integration. |
|
@lrauschning , @erikrikarddaniel , do you have any input on this? I don't know why it is being done in this way. |
No idea. I have no recollection of implementing this and have nothing against doing it the simple way, i.e. gzip after creation of the alignment file. That won't leave an intermediate which would be my only concern in general. |
|
Ok, let's do that, make the file and then gzip it if required, as we generally do. Much less error prone. |
|
Hi @SPPearce, I added this to the clustalo (and if memory serves, also to other MSA modules that don't support writing to stdout), as uncompressed MSA output can get very large due to gaps -- essentially, they scale with O(n^2) for diverse sequences. Writing uncompressed output to disk was both using a lot of scratch space and becoming a performance bottlenecks in some tests I ran. Cheers, |
|
Thanks Leon, that explains the streaming choice. Given the scratch-space cost you’ve seen, @SPPearce, do you still prefer writing the alignment first, or keeping streaming with the explicit wait? I’m happy with either approach provided completion and compressor failures are handled. I’ll follow the module’s usual test setup. |
|
Ok, if there is a significant reason not to write the intermediate file that is fine. |
|
Corroboration from the other end, in case it is useful: we hit this on real data in nf-core/phyloplace while turning
So this is a silent-corruption bug with a downstream reader that blocks indefinitely, not only an error-propagation one. That seems worth having in the PR description. I also checked and with a deliberately slow writer, @lrauschning's scratch-space point convinced me, for what it is worth — I had independently gone the write-then-compress route in #12991 and am dropping or converting that part to follow whatever lands here. One thing that may be out of scope for this PR: the same Investigated with AI assistance (Claude Code); the truncation, the container bash behaviour and the EPA-NG hang were all measured rather than inferred. |
nf-core#12894 fixes the same truncation there, predates this PR, and already has maintainer direction: keep streaming through the process substitution and add `&& wait $!`, rather than writing an uncompressed intermediate, because uncompressed MSA output scales with gaps and costs real scratch space. Carrying a competing change here would just duplicate it. The remaining four modules are about reading compressed input and stand on their own. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Dpvh3T7aVgU5XyjqcYQLQD
That PR fixes the truncated .gz independently and predates ours, and its approach was settled with the module's author: keep streaming through the process substitution and add `&& wait $!`, rather than writing an uncompressed intermediate, because uncompressed MSA output scales with gaps and costs real scratch space. This patch is now byte-identical to what is proposed there, so it will disappear cleanly at the next `nf-core modules update` instead of conflicting with it. Verified on the data that exposed the bug: all 21 *.aln.gz across the suite pass `gzip -t`, where previously everything above roughly 120 KB was truncated. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Dpvh3T7aVgU5XyjqcYQLQD
|
@dnncha , can you please join the organisation via the github-invitations channel on the nf-core slack, so your tests run. |
SPPearce
left a comment
There was a problem hiding this comment.
I'm happy to merge this pattern without the python script.
New compress_alignment take: input is passed to CLUSTALO_ALIGN and MAFFT_ALIGN, so callers can have the profile alignments written gzipped. Uncompressed alignments are mostly gaps and get large. The subworkflow also emits the EPA-NG log and the hmmbuild output. clustalo/align: wait for the pigz process substitution before exiting. The shell does not wait for >(...), so the task could finish before pigz had flushed, leaving a truncated .aln.gz (seen for outputs above ~120 KB, which made EPA-NG hang on the short stream). The fix is the `&& wait $!` from nf-core#12894, without its separate Python test. Callers must now pass compress_alignment; false keeps the old behaviour. Co-Authored-By: dnncha <5190258+dnncha@users.noreply.github.com> Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JqGkxDi4vYRXZJxVqkAcwU
Problem
The compressed output expression uses
clustalo ... -o >(pigz ... > result.aln.gz). Bash does not wait for that process substitution as part of the foreground command, and the compressor's status is not included in the Clustal Omega exit status, even withset -euo pipefail.This can report task success before compression finishes, or after a compressor failure when the producer has already successfully written its buffered output. The
.aln.gzfile may exist but be incomplete or invalid.Fix
Append
&& wait $!to the compressed-output command, with the dollar sign escaped in the Groovy string. The producer's failure is preserved by&&; after producer success, Bash waits for the compressor and returns its failure status. This keeps streaming, avoids an intermediate uncompressed file, and preserves the separation of alignment data from verbose stdout. The uncompressed branch and existing nf-test snapshots are unchanged.Reproduction and tests
Added a dependency-free regression test that extracts the actual module output expression and runs it in Bash with stand-in executables:
Five cases cover delayed compression completion, compressor failure after draining all input (no SIGPIPE assumption), producer failure, uncompressed output, and separation of stdout progress messages from the compressed alignment. Executed against the pinned original and patched source: 2 failures before; all 5 pass after.
These are shell lifecycle tests, not an alignment-engine or full Nextflow validation. Nextflow/nf-test and the native tools are unavailable in this execution environment; the existing native integration tests still need CI. The standalone regression is run with the command above and is not claimed to be automatically wired into nf-test.
Prepared with AI assistance. Based on upstream commit
781f2625386fe0bf2f337c7b99f56e618c59fc99.