Ignore:
Timestamp:
Jun 17, 2011, 1:54:56 PM (8 years ago)
Author:
robert@…
Message:
  • Installed templates (in order to extend session lifetime to 2 hours)
  • Implemented background worker to do work outside the HTTP request
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/grails-app/services/nl/tno/massSequencing/FastaService.groovy

    r68 r70  
    1515        def classificationService
    1616        def excelService
     17        def workerService
    1718
    1819        static transactional = false
     20       
     21        // After exporting sequence and qual files, the GSCF data has to be retrieved. However,
     22        // we don't know how long that takes, but is it proportional to the number of samples
     23        // For that reason, we append a number to the total size, so the progress bar will keep
     24        // some space open while fetching GSCF data
     25        def AMOUNT_PER_ASSAYSAMPLE = 100000;
    1926
    2027        /**
     
    523530                return lengthList;
    524531        }
     532       
     533        /**
     534         * Start the process of exporting fasta data in the background
     535         *
     536         * @param assaySamples  List of assaysamples to be exported
     537         * @param httpSession   Reference to the HTTP session
     538         * @param name                  Name of the exported filename
     539         * @return                              URL to redirect the user to, that shows information about the progress of the download
     540         */
     541        public String startExportProcess( def assaySamples, def httpSession, String name, String returnUrl, String finishUrl ) {
     542                // Determine the total filesize to be processed.
     543                def permanentDir = fileService.absolutePath( ConfigurationHolder.config.massSequencing.fileDir );
     544                def filesize = 0
     545                assaySamples.each { assaySample ->
     546                        assaySample.sequenceData.each {
     547                                filesize += fileService.get( it.sequenceFile, permanentDir )?.size() ?: 0;
     548                                if( it.qualityFile )
     549                                        filesize += fileService.get( it.qualityFile, permanentDir )?.size() ?: 0;
     550                        }
     551                };
     552       
     553                // After the files are concatenated, the system has to retrieve data from GSCF. However,
     554                // we don't know how long that takes, but is it proportional to the number of samples
     555                // For that reason, we append a number to the total size, so the progress bar will keep
     556                // some space open while fetching GSCF data
     557                filesize += assaySamples.size() * AMOUNT_PER_ASSAYSAMPLE;
     558       
     559                // Empty the assaySample list, since the objects should be retrieved from the database again by the
     560                // initiated thread. Otherwise, hibernate session errors occur, since the other thread has a different
     561                // hibernate session
     562                def assaySampleIds = assaySamples.collect { it.id }
     563                assaySamples = null;
     564               
     565                // Create a worker screen to create the fasta file in the background
     566                def processId = workerService.initProcess( httpSession, "Creating your download", 1, filesize )
     567                httpSession.process[ processId ][ "returnUrl" ] = returnUrl
     568                httpSession.process[ processId ].name = name;
     569               
     570                // Retrieve worker URL; returnUrl is the same as the errorUrl
     571                finishUrl = sprintf( finishUrl, processId );
     572                def url = workerService.startProcess( httpSession, processId, finishUrl, returnUrl, returnUrl )
     573               
     574                // Make sure the background process can send the progress to the HTTP session.
     575                def onProgress = { progress ->
     576                        // Update progress
     577                        httpSession.progress[ processId ].stepProgress = progress;
     578                }
     579               
     580                // Perform the real work in a background thread
     581                runAsync {
     582                        def samples = assaySampleIds.collect { AssaySample.get( it ) }
     583                       
     584                        def filename = fileService.getUniqueFilename( "fastadownload" );
     585                        def file = fileService.get( filename );
     586
     587                        try {
     588                                export( samples, new FileOutputStream( file ), httpSession.sessionToken, onProgress );
     589                        } catch( Exception e ) {
     590                                log.error( "Exception occurred during export of sequences: " );
     591                                e.printStackTrace();
     592
     593                                httpSession.progress[ processId ].error = true;
     594                                httpSession.progress[ processId ].errorMessage += e.getMessage();
     595                        }
     596                       
     597                        // Store the filename for later download
     598                        httpSession.process[ processId ].filename = filename;
     599                       
     600                        // Tell the frontend we are finished
     601                        httpSession.progress[ processId ].finished = true;
     602                }
     603               
     604                return url;
     605        }
    525606
    526607        /**
     
    530611         * @return
    531612         */
    532         public def export( List assaySamples, OutputStream outStream, String name = null ) {
     613        public def export( List assaySamples, OutputStream outStream, def sessionToken, Closure onProgress, String name = null ) {
    533614                if( !assaySamples || assaySamples.size() == 0 )
    534615                        return false;
     
    573654                BufferedWriter zipWriter = new BufferedWriter( new OutputStreamWriter( zipFile ) );
    574655
     656                // Initialize the progress. This is the combined filesize of the sequence and quality files
     657                def progress = 0;
     658               
     659                // Create a reference to the assaySample we're processing here, in order to have it set if
     660                // an error occurs
     661                def assaySample
     662
    575663                // We have to loop twice through the sequenceData, since we can't write part of the sequence
    576664                // file and part of the qual files mixed. We have to write the full sequence file first.
     
    578666                        zipFile.putNextEntry( new ZipEntry( name + ".fna" ) );
    579667
    580                         assaySamples.each { assaySample ->
     668                        for( def i = 0; i < assaySamples.size(); i++ ) {
     669                                assaySample = assaySamples[ i ];
     670                               
    581671                                if( assaySample.numSequences() > 0 ) {
    582672                                        def currentTag = tags.find { it.assaySampleId == assaySample.id };
    583673
    584674                                        assaySample.sequenceData.each { sequenceData ->
    585                                                 if( sequenceData && sequenceData.sequenceFile )
    586                                                         copyFastaFileForExport( fileService.get( sequenceData.sequenceFile, permanentDirectory ), currentTag.tag, zipWriter)
     675                                                if( sequenceData && sequenceData.sequenceFile ) {
     676                                                        def file = fileService.get( sequenceData.sequenceFile, permanentDirectory );
     677                                                       
     678                                                        def begin = System.currentTimeMillis();
     679                                                       
     680                                                        copyFastaFileForExport( file, currentTag.tag, zipWriter)
     681                                                       
     682                                                        log.trace "Exported FASTA: " + file + ": " + ( file.size() / 1000 ) + "kb / " + (System.currentTimeMillis() - begin ) + " ms";
     683
     684                                                        // Update progress
     685                                                        progress += file.size();
     686                                                        onProgress( progress );
     687                                                }
    587688                                        }
    588689                                }
     
    594695                                zipFile.putNextEntry( new ZipEntry( name + ".qual" ) );
    595696
    596                                 assaySamples.each { assaySample ->
     697                                for( def i = 0; i < assaySamples.size(); i++ ) {
     698                                        assaySample = assaySamples[ i ];
     699                                       
    597700                                        if( assaySample.numSequences() > 0 ) {
    598701                                                def currentTag = tags.find { it.assaySampleId == assaySample.id };
    599702
    600703                                                assaySample.sequenceData.each { sequenceData ->
    601                                                         if( sequenceData && sequenceData.sequenceFile && sequenceData.qualityFile )
     704                                                        if( sequenceData && sequenceData.sequenceFile && sequenceData.qualityFile ) {
     705                                                                def file = fileService.get( sequenceData.qualityFile, permanentDirectory );
     706
     707                                                                def begin = System.currentTimeMillis();
     708                                                       
    602709                                                                copyQualFileForExport( fileService.get( sequenceData.qualityFile, permanentDirectory ), currentTag.tag, zipWriter)
     710                                                               
     711                                                                log.trace "Exported QUAL: " + file + ": " + Math.round( file.size() / 1000 ) + "kb / " + (System.currentTimeMillis() - begin ) + " ms";
     712                                                               
     713                                                                // Update progress
     714                                                                progress += file.size();
     715                                                                onProgress( progress );
     716                                                        }
    603717                                                }
    604718                                        }
     
    607721                                zipWriter.flush();
    608722                                zipFile.closeEntry();
     723                        } else {
     724                                // Update progress with the filesize of all qual files
     725                                for( def i = 0; i < assaySamples.size(); i++ ) {
     726                                        assaySample = assaySamples[ i ];
     727                                       
     728                                        if( assaySample.numSequences() > 0 ) {
     729                                                assaySample.sequenceData.each { sequenceData ->
     730                                                        if( sequenceData && sequenceData.sequenceFile && sequenceData.qualityFile ) {
     731                                                                def file = fileService.get( sequenceData.qualityFile, permanentDirectory );
     732
     733                                                                // Update progress
     734                                                                progress += file.size();
     735                                                                onProgress( progress );
     736                                                        }
     737                                                }
     738                                        }
     739                                }
    609740                        }
    610741
    611742                } catch( Exception e ) {
    612743                        log.error "Error while writing to fastafile or qualfile: " + e.getMessage();
    613                         e.printStackTrace();
     744
     745                        // We shouldn't continue if anything went wrong
     746                        throw new Exception( "Error while exporting data for sample " + assaySample.sample.name + ": " + e.getCause().getMessage() );
    614747                } finally {
    615748                        // Always close zip entry
     
    620753                        }
    621754                }
    622 
     755               
    623756                // Export a tab delimited file with tags
    624757                zipFile.putNextEntry( new ZipEntry( name + ".tab" ) );
     
    635768                // Export an excel file with information about the samples
    636769                zipFile.putNextEntry( new ZipEntry( name + ".xls" ) );
     770                sampleExcelService.sessionToken = sessionToken
    637771                sampleExcelService.exportExcelSampleData( assaySamples, tags, zipFile );
    638772                zipFile.flush();
    639773                zipFile.closeEntry();
     774               
     775                // After the files are concatenated, the system has to retrieve data from GSCF. However,
     776                // we don't know how long that takes, but is it proportional to the number of samples
     777                // For that reason, we append a number to the total size, so the progress bar will keep
     778                // some space open while fetching GSCF data
     779                onProgress( progress + assaySamples.size() * AMOUNT_PER_ASSAYSAMPLE );
    640780               
    641781                // Export an excel file with information about the classification samples
     
    842982                } catch( Exception e ) {
    843983                        log.error( "An error occurred while copying contents from " + inFile.getName() + ": " + e.getMessage() );
    844                         e.printStackTrace();
    845                         return false;
     984                       
     985                        // Throw the exception, since the calling method should decide whether to continue or not
     986                        throw new Exception( "An error occurred while copying contents from FASTA file " + inFile.getName() + ": " + e.getMessage(), e );
    846987                }
    847988        }
     
    9411082                } catch( Exception e ) {
    9421083                        log.error( "An error occurred while copying contents from " + inFile.getName() + ": " + e.getMessage() );
    943                         e.printStackTrace();
    944                         return false;
     1084                       
     1085                        // Throw the exception, since the calling method should decide whether to continue or not
     1086                        throw new Exception( "An error occurred while copying contents from QUAL file " + inFile.getName() + ": " + e.getMessage(), e );
    9451087                }
    9461088        }
Note: See TracChangeset for help on using the changeset viewer.