How do I properly start a background thread for an MVC application on a shared host?

I need to start a background thread for my MVC 4 application where the thread wakes up every hour or so to delete old files in the database and then goes back to sleep. This method is shown below:

//delete old files from database
public void CleanDB()
{
    while (true)
    {
        using (UserZipDBContext db = new UserZipDBContext())
        {
            //delete old files
            DateTime timePoint = DateTime.Now.AddHours(-24);
            foreach (UserZip file in db.UserFiles.Where(f => f.UploadTime < timePoint))
            {
                db.UserFiles.Remove(file);
            }
            db.SaveChanges();
        }
        //sleep for 1 hour
        Thread.Sleep(new TimeSpan(1, 0, 0));
    }
}

      

but where should I start this topic? The answer to this question creates a new topic and launches it in Global.asax

, but this post also mentions that "ASP.NET is not designed for lengthy tasks." My application will run on a shared host where I don't have administrator rights, so I don't think I can install a separate program for this task.

shortly speaking,

  • Is it possible to start a thread in Global.asax since my thread is not very much (sleep most of the time and a small db)?

  • I read that the risk of this approach is that the thread might get killed (although not sure why). How can I detect when a thread is killed and what can I do?

  • If this is a VERY bad idea, what else can I do on a shared host?

Thank!

UPDATE

@usr mentioned that methods in Application_Start

can be called more than once and suggested using Lazy

. Before I read this thread, I thought about this. Calling SimplePrint.startSingletonThread()

multiple times would only create one thread (I think). It is right?

public class SimplePrint
{
    private static Thread tInstance = null;

    private SimplePrint()
    {
    }

    public static void startSingletonThread()
    {
        if (tInstance == null)
        {
            tInstance = new Thread(new ThreadStart(new SimplePrint().printstuff));
            tInstance.Start();
        }
    }

    private void printstuff()
    {
        DateTime d = DateTime.Now;
        while (true)
        {
            Console.WriteLine("thread started at " + d);
            Thread.Sleep(2000);
        }
    }
} 

      

+3


source to share


2 answers


ASP.NET isn't designed for long-running tasks, yes. But only because their work and data can be lost anytime the workflow is restarted.

You do not save any state between iterations of your task. The task can be safely canceled at any time. It is safe to run in ASP.NET.

Starting a thread in Application_Start

is a problem because this function can be called multiple times (surprisingly). I suggest you only run the delete task once, for example using Lazy<T>

and access the property Value

in Application_Start

.



static readonly Lazy<object> workerFactory =
     new Lazy<object>(() => { StartThread(); return null; });

Application_Start:
  var dummy = workerFactory.Value;

      

For some reason, I can't think of a better init-once sample right now. Nothing without locks, unstable or locked, that are the last resort.

+2


source


I think you should try Hangfire .

An incredibly easy way to fire and forget, postpone and repeat tasks inside ASP.NET applications. No Windows service required.

Supported by Redis, SQL Server, SQL Azure, MSMQ, RabbitMQ.



So, you don't need adventive privileges.

RecurringJob.AddOrUpdate(
() => 
{
    using (UserZipDBContext db = new UserZipDBContext())
    {
        //delete old files
        DateTime timePoint = DateTime.Now.AddHours(-24);
        foreach (UserZip file in db.UserFiles.Where(f => f.UploadTime < timePoint))
        {
        db.UserFiles.Remove(file);
        }
        db.SaveChanges();
    }    
}
Cron.Hourly);

      

+4


source







All Articles