Try catch in Nextflow processes - groovy

How can I perform a try catch in nextflow?
I am currently writing a pipeline where it is possible that the bash command I am executing exits with an exitcode 1 under certain conditions. This brings my pipeline to a grinding halt. I would now like to use a try catch clause to define some alternative behavior in case this happens.
I have tried doing this in groovy fashion which does not seem to work:
process align_kallisto {
publishDir "${params.outdir}/kallisto", mode: 'copy', saveAs:{ filename -> "${name}_abundance.tsv" }
input:
tuple val(name), file(fastq) from fq_kallisto.dump(tag: 'kallisto fq')
file(index) from kallisto_index.collect().dump(tag: 'kallisto index')
output:
file("output/abundance.tsv") into kallisto_quant
// this can throw an exit 1 status
try {
"""
kallisto quant -i ${index} --bias --single --fr-stranded -o output --plaintext \
--fragment-length ${params.frag_length} --sd ${params.frag_deviation} ${fastq}
"""
}
// if this happens catch and do something else
catch (Exception e) {
println("Exception: ${e} for $name")
"""
// execute some alternative command
"""
}
}
Any advise?
I could tell nextflow to just ignore this error and still continue, but I would rather learn how to do a proper try catch.

AFAIK there's no way to handle errors in your process definition using a try/catch block. Rather than trying to catch all of the scenarios that result in an exit status 1, could you better define those conditions and handle them before trying to execute your process? For example, if an empty FASTQ file (or a FASTQ file with an insufficient number of reads as required by your process) was supplied as input and this resulted in an exit status 1, a pre-processing command that filtered out those files could be useful here.
But if it's not possible to better define the condition(s) that your command produces exit status 1 or any non-zero exit status, you can ignore them like you have suggested by appending errorStrategy 'ignore' to your process definition. Below is an example of how you could get the 'success' and 'failed' outputs, so they can be handled appropriately:
nextflow.enable.dsl=2
process test {
errorStrategy 'ignore'
input:
tuple val(name), path(fastq)
output:
tuple val(name), path("output/abundance.tsv")
"""
if [ "${fastq.baseName}" == "empty" ]; then
exit 1
fi
mkdir output
touch output/abundance.tsv
"""
}
workflow {
fastqs = Channel.fromFilePairs( './data/*.fastq', size: 1 )
test(fastqs) \
.join(fastqs, remainder: true) \
.branch { name, abundance, fastq_tuple ->
failed: abundance == null
return tuple( name, *fastq_tuple )
succeeded: true
return tuple( name, abundance )
} \
.set { results }
results.failed.view { "failed: $it" }
results.succeeded.view { "success: $it" }
}
Run with:
mkdir data
touch data/nonempty.fastq
touch data/empty.fastq
nextflow run -ansi-log false test.nf
Results:
N E X T F L O W ~ version 20.10.0
Launching `test.nf` [suspicious_newton] - revision: b883179718
[08/60a99f] Submitted process > test (1)
[42/358d60] Submitted process > test (2)
[08/60a99f] NOTE: Process `test (1)` terminated with an error exit status (1) -- Error is ignored
success: [nonempty, /home/user/working/stackoverflow/66119818/work/42/358d60bd7ac2cd8ed4dd7aef665d62/output/abundance.tsv]
failed: [empty, /home/user/working/stackoverflow/66119818/data/empty.fastq]

Related

Groovy compare string

I have the Groovy code as below
def retVal = sh(returnStdout: true, script: "curl ${URI}; echo \$?")
println("Return value: ${retVal}") -> it printed 0
if (retVal == "0") {
println("Successfull") -> it doesn't go here
}
why the above condition can't be catched?
First of all, you seem to be using the Jenkins API incorrectly.
If all you need is the exit code of the process, use returnStatus: true:
def retVal = sh(returnStatus: true, script: "curl ${URI}")
if (retVal == 0) {
println 'success'
} else {
println "Something wrong, exit code was $retVal")
}
Now, if you really want the stdout instead, perhaps clean up the String first by calling trim() on it or try to match the String against a regex:
if (retValue ~== /\s*0\s*/) {
println "success"
} else {
println "Something wrong, exit code was '$retVal'")
}
I always put quotes around a value I print to make sure new-lines or whitespaces don't make me waste time with bad values.

Groovy code not returning true for folders

groovy code for jenkinspipeline to check for directory or not, is giving false even if it is directoy.
def folderExists(folderName) {
if(fileExists(folderName))
{
def file = new File(folderName)
echo "file/folder exists: "+folderName
echo "Is directry "+ file.isDirectory().toString()
return file.isDirectory()
}
else{
echo "Not found: "+folderName
return false
}
}
Any suggestions??
As far as I remember, Java's File object either won't work in sandboxed mode, or will run only on master node. If you want to check for folder on a slave node, you need to invoke Pipeline methods, or pure shell.
The below code works for me. You had echo instead of println, I'm not au fait with Groovy in Jenkins but in pure Groovy there is no echo that I am aware of. Also, i moved the statement def file = new File(folderName) to before the if decision.
def folderExists(folderName) {
def file = new File(folderName)
if(file.exists())
{
println "file/folder exists: "+folderName
println "Is directry "+ file.isDirectory().toString()
return file.isDirectory()
}
else{
println "Not found: "+folderName
return false
}
}
println folderExists('C:\\temp')

Search a string with Javascript

Hi everyone,
I am trying to test C programs that use an user input... Like a learning app. So the avaliator(teacher) can write tests and I compile the code with a help of a docker and get back the result of the program that I send. After that I verify if one of the case tests fails..
for that I have two strings, like this:
result = "input_compiled1540323505983: /home/compiler/input/input.c:9: main: Assertion `B==2' failed. timeout: the monitored command dumped core Aborted "
and an array with case tests that is like:
caseTests = [" assert(A==3); // A must have the value of 3;", " assert(B==2); // B must have the value of 2; ", " assert(strcmp(Fulano, "Fulano")==0); //Fulano must be equal to Fulano]
I need to send back from my server something like this:
{ console: [true, true, true ] }
Where each true is the corresponding test for every test in the array of tests
So, I need to test if one string contains the part of another string... and for now I did like this:
criandoConsole = function(arrayErros, arrayResult){
var consol = arrayErros.map( function( elem ) {
var local = elem.match(/\((.*)\)/);
if(arrayResult.indexOf(local) > -1 ) {
return false;
}
else return true;
});
return consol;
}
I am wondering if there are any more efective way of doing that. I am using a nodejs as server. Does anyone know a better way?!
ps: Just do like result.contains(caseTests[0]) did not work..
I know this is changing the problem, but can you simplify the error array to only include the search terms? For example,
result = "input_compiled1540323505983: /home/compiler/input/input.c:9: main: Assertion `B==2' failed. timeout: the monitored command dumped core Aborted ";
//simplify the search patterns
caseTests = [
"A==3",
"B==2",
"strcmp(Fulano, \"Fulano\")==0"
]
criandoConsole = function(arrayErros, arrayResult){
var consol = arrayErros.map( function( elem ) {
if (arrayResult.indexOf(elem) != -1)
return false; //assert failed?
else
return true; //success?
});
return consol;
}
console.log(criandoConsole(caseTests,result));

searching for a word in expect output

I have an expect command
expect "~]#" { send "virsh list --all\r"}
and the output would be
[root#lht1oneems-unit0 ~]# virsh list --all
Id Name State
----------------------------------------------------
399 lht1duplexvm-0 running
- rhelvm shut off
I want to use $expect_out(buffer) and have an if statement to do something if it finds running and do something else if not.
how can I parse into the result of $expect_out(buffer)?
expect "~]#"
send "virsh list --all\r"
# I assume another prompt follows this
expect "~]#"
if { [regexp {running} $expect_out(buffer)] } {
do-something-for-running-process
} else {
do-something-for-no-running-process
}
You could also do
if {[string first "running" $expect_out(buffer)] >= 0} {

CliBuilder Arguments Are Empty

Here's a working example of my problem:
def cli = new CliBuilder(usage: 'cli-test -d <argument>')
cli.with {
h(longOpt: 'help', 'usage information')
d(longOpt: 'do-something', required: true, args: 1, 'Do Something' )
}
OptionAccessor options = cli.parse(args)
if(!options) {
return
}
// print usage if -h, --help, or no argument is given
if(options.h || options.arguments().isEmpty()) {
println options.arguments().size()
cli.usage()
return
} else if (options.d) {
println options.d
}
When I execute the script with the following:
groovy cli-test.groovy -d hello
I get this output:
0
usage: cli-test -d <argument>
-d,--do-something <arg> Do Something
-h,--help usage information
The 0 is my println is the arguments length. I can't get any options to work other than h. I'm not sure if I'm doing something wrong.
The reason is that there are no arguments! You've swallowed them all in options.
If you call
groovy cli-test.groovy -d hello foo
then the arguments() list is [foo]
The -d arg is automatically checked for because you made it required, so there's no need to test for it later on.
Not sure why this works this way, but removing:
|| options.arguments().isEmpty()
from the initial if check makes everything work.

Resources