Question

My vb.net service has a timer that ticks every minute or so, but before executing it checks if the previous thread has been completed (I don’t want duplicate results)

The problem is that at some times the process just get hung in the process, so I wrote that if the process is not finish within 5 minutes it should continue executing.

Now I have a few hung threads in the application… eating resources for nothing.

So my question is if I could kill those threads.

Protected Overrides Sub OnStart(ByVal args() As String)
    EmailTimer = New System.Timers.Timer(50000)
    EmailTimer.AutoReset = True
    AddHandler EmailTimer.Elapsed, AddressOf CheckNewEmails
    EmailTimer.Start()
 End Sub

worker code:

    Private Sub CheckNewEmails(ByVal sender As Object, e As System.Timers.ElapsedEventArgs)
           If _workStartTime <> DateTime.MinValue Then
                '  check how much time has elapsed since work started previously
                If DateDiff(DateInterval.Minute, _workStartTime, Now) > 5 Then
                    _workStartTime = DateTime.MinValue
                End If

            Else
                 _workStartTime = DateTime.Now

                Dim client As New ImapClient()
                client.Connect("imap.gmail.com", 993) 'that line could sleep forever..
               End if 
                _workStartTime = DateTime.Now
           End Sub
Was it helpful?

Solution 2

While @Jim Mischel's answer was very helpful, I still want to add my own answer which solved the problem in my case.

After a lot of digging I discovered that the problem is simply because the resources doesn't get disposed properly...

After enclosing the sub in a using clause, the problem disappeared.

I hope that will help someone in the future...

OTHER TIPS

It's possible that your client.Connect isn't hanging, but rather is throwing an exception, which escapes your exception handler, is squashed by the Timer object itself, and you're none the wiser. That's because System.Timers.Timer squashes exceptions. You should put a Try ... Catch ... Finally around your handler, like this:

Private Sub CheckNewEmails(ByVal sender As Object, e As System.Timers.ElapsedEventArgs)
   If _workStartTime <> DateTime.MinValue Then
       '  check how much time has elapsed since work started previously
       If DateDiff(DateInterval.Minute, _workStartTime, Now) > 5 Then
           _workStartTime = DateTime.MinValue
       End If

   Else
        Try
            _workStartTime = DateTime.Now

            Dim client As New ImapClient()
            client.Connect("imap.gmail.com", 993) 'that line could sleep forever..
        Catch  ` whatever exception
            ` log exception here
        Finally
            ' cleanup
        End Try
    End if 
    _workStartTime = DateTime.Now
End Sub

That will at least tell you if the Connect is really hanging, or if it's throwing an exception that's being suppressed.

Also see my comment about _workStartTime. I don't see where it's ever set back to DateTime.MinValue, which would definitely cause the problem that you describe.

If the call to Connect really is hanging and there is no call that will let you set a timeout, then you need to find a new IMAP client because that one is irretrievably broken. Hacking around limitations of poorly constructed libraries is never a good idea.

As for your timer, rather than setting a one-minute timer and checking to see if a tick is already being processed, set the timer up as a one-shot and reset the timer once it's done with its processing. That way it's impossible to get multiple concurrent ticks. So your timer initialization would look like this:

EmailTimer = New System.Timers.Timer(50000)
EmailTimer.AutoReset = False   ' Don't want auto reset!
AddHandler EmailTimer.Elapsed, AddressOf CheckNewEmails
EmailTimer.Start()

And your handler:

Private Sub CheckNewEmails(ByVal sender As Object, e As System.Timers.ElapsedEventArgs)
    Try
        Dim client As New ImapClient()
        client.Connect("imap.gmail.com", 993) 'that line could sleep forever..
    Catch   ' whatever exceptions you want to catch
        ' log exception

    Finally
        ' Now set the next timer interval.
        EmailTimer.Start()
    End Try
End Sub

This won't do a tick every 50 seconds. Rather, it will do a tick 50 seconds after the previous tick completed.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top