0

I have a Windows Service running that is event driven and each event is handled by its own thread. Now the events are usually coming at a rate of around 10 per second. Last action of the event is to save data to a database.

If saving the data fails, because a connection cannot be established to the Database, I want the first thread that encounters this problem to start a new reconnecting Task running at some interval (e.g. every 30 seconds). Any following threads I wish to simply end. There should be only one reconnecting Task running at any time.

How do I code so that the following event threads safely know that there is already a reconnection Task running and end it's life? Maybe there is a good design pattern for this?

EDIT: Following FelixD's suggested links: Does cancelling a cancellation token trigger an exception in the Task?

If so, I could probably catch the exception, so it would save the incoming data in a file rather than commit it to the database. I have tried to search for this, but it is not clear to me what happens when a Task is cancelled.

12
  • 1
    Have a look at CancellationToken Commented Sep 25, 2017 at 10:06
  • @FelixD. If I understand the idea correctly, the first thread starting the reconnection job would cancel other running threads? As I understand the Cancellation Token, the threads will stop "mid-job". I my scenario I would like to save the data from the events before they are cancelled (and commit it when connection is up). Can I accomplish this with Cancellation tokens? Commented Sep 25, 2017 at 10:26
  • 1
    I guess so .. does this also help you ? Commented Sep 25, 2017 at 10:57
  • Why specifically have the first thread try to reconnect and dispose of all the others? Is it equally valid to dispose of all threads and then start a new one which checks the connection? Commented Sep 25, 2017 at 11:20
  • 1
    @Mr.Blonde you shouldn't be keeping a single connection for all threads. Open the connection as needed inside a using block. ADO.NET uses connection pooling so you don't have to open a new connection each time. By trying to use a global connection you end up hurting performance and scalability, as locks can accumulate and lead to excessive blocking and waits Commented Sep 25, 2017 at 11:37

2 Answers 2

2

I suggest creating a BlockingCollection, and a single worker thread that continually monitors it. When one of your receiver threads gets a message, it processes the message and then, rather than trying to write it to the database, writes it to the BlockingCollection.

The worker thread that monitors the BlockingCollection can have a single persistent connection to the database, and can write individual records, or batch them to do a bulk update, or write the records to a file if the database connection fails for some reason.

This kind of thing is easy enough to set up working directly with BlockingCollection, or you can use TPL Dataflow.

Sign up to request clarification or add additional context in comments.

3 Comments

Would a ConcurrentQueue be equivalent to a BlockingCollection if I need FIFO?
@Mr.Blonde: The default blocking store for BlockingCollection is a ConcurrentQueue. BlockingCollection is significantly easier to work with. See stackoverflow.com/questions/19847905/… for a simple example.
Thanks. I believe can accomplish what I want with your design suggestion.
0

Loss of connection a database is usually described as a transient fault. Often it occurs because the database cannot service the traffic that is being thrown at it, so it starts rejecting or timing out connections.

Have you actually observed this fault occurring or are you pre-empting it?

You should handle a transient fault by waiting for a period and then retrying the operation a number of times, including opening a new connection. Do this for all threads. If all retries fail, be prepared to fall back to a known state and return an error.

I find Polly (by the .Net foundation) to be very useful for handling this behaviour in structured way. http://www.thepollyproject.org/

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.