简体   繁体   中英

How to refresh data at midnight in a MVC application?

For a client we are building a website that displays products. Once a day, at midnight, the order of the products on the homepage must be changed. In other words, the order of the products must be shuffled.

I now have this solved as follows, but I don't think this is the way to go...

  1. In application_start in global.asax , load the product ids and shuffle them.
  2. In IIS set recycle of the app pool at 00:00:00.
  3. In IIS set idle time-out to 1440 minutes (24 * 60)

So my question is, how would you handle this requirement?

There are million reasons why "sleeps" on task threads from IIS can fail and never be executed.

One other option is to use Windows Task Scheduler There you can call you own C# code (windows application) that can wake up your IIS webapplication, targeting a specific URL, and there you do your own clean up tasks.

Other similar way is to use those "ping" services that are used to verify if a site is alive, and if there you can change the "time intervals" you might would be able to pass the same "maintenance url".

Oher option: in case you use SQL Server, SQL Server Batch or Task Scheduling (from here you can invoke an application)

You can evaluate a library like FluentScheduler that with 1 line of code can solve your problem

Great post about this argument on hanselman.com

If the products have to be shuffled at midnight, strictly once a day, the most effective way of handling this would be to ensure that the shuffled IDs are stored somewhere independent of the application. There are many reason why the application may reload and solely relying on settings in IIS isn't the most reliable means of controlling this (although they can massively help.)

Personally, if the requirement is as strict as you suggest, I would diregard the IIS configuration and save the shuffled IDs (and date) to a separate table in the database (or something like Redis). If they're in separate rows you'd be able to inner join on them. If they're comma delimited in a single row then you can use LINQ to order your products.

You would cache them in your application setting an absolute expiry set to midnight. If the cache expires whilst the application is running it must be midnight, so re-shuffle the IDs, replace in the database and re-cache. If the application restarts (therefore there is no cache), check the data saved against the IDs in the database, and either re-shuffle if necessary, but then retrieve and cache again.

Either way, if you use IIS configuration or save them to an independent source you still need to re-shuffle the IDs and store them somewhere, so I would keep them independent of the application lifecycle.

Note: If the requirement isn't so strict and you just ned to ensure that the product orders are different on a daily basis but that they could potentially change within the same day, just cache the IDs with an absolute expiry of midnight.

Note: If you're using something like Redis, you can set an auto-expire value on the data, so it would be irrelevant when you updated the data.

You could use OutputCaching but you'd need to be a little bit clever in how you use it:

public class OutputCacheMidnightAttribute : OutputCacheAttribute
{
    public OutputCacheMidnightAttribute()
    {
        // remaining time to midnight
        Duration = (int)((new TimeSpan(24, 0, 0)) - DateTime.Now.TimeOfDay).TotalSeconds;
    }
}

This will set the cache to expire for the server's cache at midnight of each day. Now decorate each method you'd like this functionality with:

OutputCacheMidnight(Location=OutputCacheLocation.ServerAndClient)]

Then in your method for that, have the code to randomly shuffle the order, ie return db.Products.OrderBy(x => Guid.NewGuid()) . Because of output caching this will only get hit once per day.

You can use Quartz.net to schedule something at particular time or even particular interval of time as well

public static void Main()
    {
        IScheduler scheduler = StdSchedulerFactory.GetDefaultScheduler();
        scheduler.Start();
        IJobDetail job = JobBuilder.Create<ShuffleProducts>().Build();

        //On Particular Time of day

        ITrigger trigger = TriggerBuilder.Create()
            .WithDailyTimeIntervalSchedule
              (s =>
                 s.WithIntervalInHours(24)
                .OnEveryDay()
                .StartingDailyAt(TimeOfDay.HourAndMinuteOfDay(23,00))
              )
            .Build();         


        scheduler.ScheduleJob(job, trigger);
    }




public class ShuffleProducts : IJob
    {        
        public void Shuufle(IJobExecutionContext context)
        {
           //Shuffle products here... 
        }
    }

Now Call the Main from Application_Start() in Global.asax

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM