7

We are indexing documents into Solr using Solrnet in asp.net c# project. We are having requirement where Solr DIH can not be used, so we are indexing products in certain batches to Solr using following code:

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();
}

With huge document size, it takes lot of time (most of times it takes few hours) to complete whole process, and sometimes we are having requirement to stop this process in-between by manual intervention.

However, I am not sure how to stop this indexing batch cycles in between before it completes. A single cycle with large batch size of documents, takes few seconds to complete and then it commit. But considering huge no. of documents, while performing full indexing it takes few hours and we're unable to stop this process in between.

Any idea - how can I stop this process in-between.. I'm unable to figure out what should be done here?

Please suggest.

croxy
  • 4,082
  • 9
  • 28
  • 46
Ankita
  • 1,416
  • 4
  • 17
  • 42
  • Try read http://www.davepaquette.com/archive/2015/07/19/cancelling-long-running-queries-in-asp-net-mvc-and-web-api.aspx I hope this will be helpfull – gabba Nov 25 '15 at 15:22
  • 2
    Keep track of a boolean "running". Set running to false, and then check it on every loop: if (!running) break; – danielmcn Nov 25 '15 at 15:27

2 Answers2

5

Two approaches you can take here are:

1 Use a global variable (this is not a good solution though, hopefully for obvious reasons):

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 Use a callback to check whether to keep running:

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();
        }
    }
}

The advantage of the second approach is that you decouple the decision logic from the indexing logic and avoid global variables, eg by capturing whether to keep running or not inside a closure around an async call to the long running process and an event handler.

David Arno
  • 42,717
  • 16
  • 86
  • 131
0

Another approach, perhaps a bit roundabout, is to create an application file "Global.asax" and try using a background worker as described here. You can also look at my example for 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();
                }
            }
        }
    }
}
Community
  • 1
  • 1
TheDanMan
  • 1,746
  • 1
  • 17
  • 22