2015-11-25 13 views
7

Stiamo indicizzando i documenti in Solr utilizzando Solrnet nel progetto asp.net C#. Stiamo avendo requisito dove Solr DIH non può essere utilizzata, quindi stiamo indicizzazione delle prodotti in alcuni lotti di Solr utilizzando il codice seguente:Interrompi il ciclo for in-between prima che venga completato

decimal cycleCount = ProductCount/batchSize; 
for (int i = 0; i <= Math.Round(cycleCount); i++) 
{  
    var Products = Products(batchSize, languageId, storeId).ToList(); 
    solrCustomWorker.Add(solrProducts); 
    solrCustomWorker.Commit(); 
} 

con enormi dimensioni del documento, ci vuole molto tempo (la maggior parte delle volte ci vogliono pochi ore) per completare l'intero processo e talvolta abbiamo la necessità di interrompere questo processo tra un intervento manuale e l'altro.

Tuttavia, non sono sicuro di come interrompere questo ciclo di indicizzazione prima di completare. Un singolo ciclo con grandi dimensioni di batch dei documenti, richiede pochi secondi per essere completato e quindi viene eseguito il commit. Ma considerando l'enorme no. dei documenti, mentre si esegue l'indicizzazione completa ci vogliono poche ore e non siamo in grado di interrompere questo processo in mezzo.

Qualche idea - come posso interrompere questo processo nel mezzo ... Non riesco a capire cosa dovrebbe essere fatto qui?

Si prega di suggerire.

+0

Cercate leggere http://www.davepaquette.com/archive/2015/07/19/cancelling-long-running-queries-in-asp-net- mvc-and-web-api.aspx Spero che questo sia utile – gabba

+2

Tieni traccia di un "boule" booleano. Imposta l'esecuzione su false e quindi controlla su ogni ciclo: if (! Running) break; – dannymc18

risposta

5

due approcci si può prendere qui sono:

1 Utilizzare una variabile globale (questa non è una buona soluzione, però, si spera per ovvie ragioni):

public static bool KeepRunning; 

... 

for (int i = 0; i <= Math.Round(cycleCount); i++) 
{ 
    if (KeepRunning) 
    {  
     var Products = Products(batchSize, languageId, storeId).ToList(); 
     solrCustomWorker.Add(solrProducts); 
     solrCustomWorker.Commit(); 
    } 
} 

2 Utilizzare un callback per verificare se per continuare a correre:

public void SomeMethod(Func<bool> keepRunning) 
{ 
    for (int i = 0; i <= Math.Round(cycleCount); i++) 
    { 
     if (keepRunning()) 
     {  
      var Products = Products(batchSize, languageId, storeId).ToList(); 
      solrCustomWorker.Add(solrProducts); 
      solrCustomWorker.Commit(); 
     } 
    } 
} 

il vantaggio del secondo approccio è che si disaccoppiare la logica decisione dalla logica di indicizzazione e di evitare le variabili globali, ad esempio catturando se continuare a correre o no all'interno di una chiusura attorno a una chiamata asincrona al processo a lunga esecuzione e un gestore di eventi.

0

Un altro approccio, forse un po 'tondo, consiste nel creare un file dell'applicazione "Global.asax" e provare a utilizzare un worker in background come descritto in here. È inoltre possibile guardare il mio esempio per WinForms here

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Linq; 
using System.Threading; 
using System.Web; 
using System.Web.Security; 
using System.Web.SessionState; 

namespace AspNetBackgroundProcess 
{ 
    public static BackgroundWorker worker = new BackgroundWorker() 
    public static bool stopWorker = false; 

    public class Global : System.Web.HttpApplication 
    { 
     protected void Application_Start(object sender, EventArgs e) 
     { 
      worker.DoWork += new DoWorkEventHandler(DoWork); 
      worker.WorkerReportsProgress = true; 
      worker.WorkerSupportsCancellation = true; 
      worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(WorkerCompleted); 
      // Calling the DoWork Method Asynchronously 
      worker.RunWorkerAsync(); 
     } 

     protected void Application_End(object sender, EventArgs e) 
     { 
      if (worker != null) 
       worker.CancelAsync(); 
     } 

     //Start Process 
     private void button1_Click(object sender, EventArgs e) 
     { 
      worker.RunWorkerAsync(); 
     } 

     //Cancel Process 
     private void button2_Click(object sender, EventArgs e) 
     { 
      //Check if background worker is doing anything and send a cancellation if it is 
      if (worker.IsBusy) 
      { 
       worker.CancelAsync(); 
      } 

     } 

     private static void DoWork(object sender, DoWorkEventArgs e) 
     { 
      decimal cycleCount = ProductCount/batchSize; //Depending on where you get these variables, you might consider moving this to the class level along with the other variable declarations 
      for (int i = 0; i <= Math.Round(cycleCount); i++) 
      { 
       //Check if there is a request to cancel the process 
       if (worker.CancellationPending) 
       { 
        e.Cancel = true; 
        worker.ReportProgress(0); 
        return; 
       } 


       var Products = Products(batchSize, languageId, storeId).ToList(); 
       solrCustomWorker.Add(solrProducts); 
       solrCustomWorker.Commit(); 
      } 
     } 
     private static void WorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
     { 
      BackgroundWorker worker = sender as BackgroundWorker; 
      if (worker != null) 
      { 
       System.Threading.Thread.Sleep(3000); 
       if (!stopWorker) 
       { 
        worker.RunWorkerAsync(); 
       } 
       else 
       { 
        while (stopWorker) 
        { 
         Thread.Sleep(6000); 
        } 
        worker.RunWorkerAsync(); 
       } 
      } 
     } 
    } 
}