2

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?

Martijn
  • 24,441
  • 60
  • 174
  • 261

5 Answers5

4

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)

Dryadwoods
  • 2,875
  • 5
  • 42
  • 72
  • Windows Task Scheduler to call a 'hidden' (no link on the UI) shuffle action (that also checks the time / user / etc) is definitely the way to go. – freedomn-m Jul 24 '15 at 08:37
  • Nice idea, the 'hidden' link. So you would suggest to call this link, say every 30 minutes, and the action of this link checks date and time en when it is midnight or past midnight, it should refresh the data. Is that the way to go? – Martijn Jul 24 '15 at 08:53
  • There is not a "100%" way to go :) there are simply things that have lower probability of failing :) and that one is one of them. And at professional level I have used it before and it worked great. – Dryadwoods Jul 24 '15 at 08:55
  • Thanks. I store the id's in cache, but when the site is idle, the site shuts down and my cache is lost. How would you solve this problem? By increasing the idle timeout on IIS? I can't store the id's in the DB. – Martijn Jul 24 '15 at 08:59
  • Store it on the DB always, dont rely on memory (server might need a restart or something like that).... then you "hiden target url" will read the IDs to process from the DB.... – Dryadwoods Jul 24 '15 at 09:01
  • Well, if you cant use DB, then maybe store it on a file or something.... Basically trying to keep it on memory is risky (mainly when u are even trying to share it among different applications... not counting the difficulty of that) – Dryadwoods Jul 24 '15 at 09:02
  • The way for me I think I have 2 options: store ids external in a testfile or something, or call the hidden URL every 10 minutes or so.. What would be preferrable? EDIT: I think you would go for the external file :) – Martijn Jul 24 '15 at 09:03
  • url request is light and fast --> stick with it. – Dryadwoods Jul 24 '15 at 09:04
  • Okay, I trust you with this one and will go for a request to the hidden url every 10 minutes. Thanks – Martijn Jul 24 '15 at 09:06
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/84154/discussion-between-dryadwoods-and-martijn). – Dryadwoods Jul 24 '15 at 09:09
  • @Dryadwoods I'm at the chat.. sorry for the delay – Martijn Jul 24 '15 at 11:06
0

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

Luca
  • 1,588
  • 2
  • 22
  • 26
0

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.

ataravati
  • 8,891
  • 9
  • 57
  • 89
Digbyswift
  • 10,310
  • 4
  • 38
  • 66
  • Just noticed that you mention in a comment you can't store anything in the database. There are other independent data sources, you could store the IDs as a TXT or JSON file, or even set a cookie provided there aren't a large number of products. – Digbyswift Jul 24 '15 at 09:13
0

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, i.e. return db.Products.OrderBy(x => Guid.NewGuid()). Because of output caching this will only get hit once per day.

ediblecode
  • 11,701
  • 19
  • 68
  • 116
0

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