avs099
avs099

Reputation: 11227

what's the right way to periodically query the database and upload data to external web service?

I have a Windows Forms application which collects data from multiple devices - and stores that data in the local SQLite database. Then, with a certain period, I need to upload new records to external webservice - meaning I need to read new records with "WasUploaded = 0" field, upload them, and then set "WasUploaded = 1" on success. Today I would do this the same way I would do it 10 years ago - fork a new background thread, and do endless cycle:

while(true) 
{
   try
   {
        var newRecords = dbRepo.ReadNew(10);    // read 10 records at a time
        UploadToExternalWebservice(newRecords);
        foreach (var r in newRecords)
        {
            r.WasUploaded = 1;
        }
        dbRepo.CommitChanges(newRecords);
    } 
    catch (Exception ex)
    {
        Logger.LogError(ex);
    }

    Thread.Current.Sleep(15*1000);
}

but I started to wonder - is there a better way to do this may be? Is it worth using Tasks library here?.. something else?

I'm on .Net 4.0 if that matters.

Thank you.

Upvotes: 0

Views: 1724

Answers (4)

Xelom
Xelom

Reputation: 1625

I've used DispatcherTimer class for this.

Example usage:

DispatcherTimer dt = new DispatcherTimer();
dt.Interval = TimeSpan.FromSeconds(1);
dt.Tick += delegate(object s, EventArgs args) {

//Your Logic here!!    

};
timer.Start();

And also here is the class: DispatcherTimer

Upvotes: 0

Jim Mischel
Jim Mischel

Reputation: 134125

Use a timer. Set it for every 10 minutes (or whatever), and do the upload then.

System.Threading.Timer uploadTimer = new Timer(UploadProc, null, TimeSpan.FromMinutes(10), TimeSpan.FromMinutes(10));

void UploadProc(object state)
{
    // do query, upload, and update logic here
}

There's no need for an explicit thread that spends most of its time sleeping.

If you want it to be more frequent (you have 15 seconds in your example), you run into the possibility of re-entrant timer ticks. That is, if you have it set for 15 seconds and it takes more than 15 seconds to do the processing, you'll end up with multiple threads running the upload code concurrently.

If that's a possibility, you have two choices: use a lock to prevent the re-entrancy, or use a one-shot timer that you update after every process.

The lock is pretty easy. Define a lock object at class scope:

private object uploadLock = new object();

And inside the UploadProc:

void UploadProc(object state)
{
    if (!Monitor.TryEnter(uploadLock))
    {
        // upload in progress. Quit.
        return;
    }
    try
    {
        // processing here
    } 
    finally
    {
        Monitor.Exit(uploadLock);
    }
}

That works well. The one-shot idea involves setting the timer to tick once and then stop. You then update it after you're done processing:

System.Threading.Timer uploadTimer = new Timer(
    UploadProc, null, TimeSpan.FromSeconds(15), TimeSpan.FromMilliseconds(-1));

void UploadProc(object state)
{
    // processing here
    // now reset the timer
    uploadTimer.Change(TimeSpan.FromSeconds(15), TimeSpan.FromMilliseconds(-1));
}

Upvotes: 1

MeTitus
MeTitus

Reputation: 3428

Use Quartz to set a job to to that periodically, using a Timer is definitively not the best way to do that, you can, but that is a quick dirt way of doing it.

http://quartznet.sourceforge.net/

And you could also use a queue for your jobs.

Upvotes: 0

iefpw
iefpw

Reputation: 7062

It is a basic push vs pull problem. If the datasource can notify you, you can do it then, but otherwise I think your approach is the correct one. You can set up different service that pulls these data.

Upvotes: 0

Related Questions