beginner problem with a windows service

  • Thread starter Thread starter Fabio Papa
  • Start date Start date
F

Fabio Papa

I am trying to write a windows service that sends emails to clients at
specific times based on information in a sql db. Since this is done for
multiple cities, I start a thread for each city and continue the processing
from each thread. My service starts fine (gives me no errors, etc), but it
doesn't seem to start the new threads. I am new to windows services, so I
don't know if I'm doing something wrong. Should I maybe be doing this with
events? Below is the code for the OnStart Method and the thread that is
supposed to start multiple times. If you need the rest of the code, email
me and I will send to you. Thanks.

Public MustInherit Class EmailPump : Inherits ServiceBase

Public Const TwentyFourHrs As Long = 86400 'There are 86,400 seconds in
24 hours
Private name As String
Private index As Integer
Private dbObj As RgsDbConnection

......

Protected Overrides Sub OnStart(ByVal args() As String)
Dim i As Integer
Dim t(Me.dbObj.NumLocales - 1) As Thread
Dim log As EventLog = New EventLog()

log.WriteEntry(ServiceName, "Service started")
For i = 0 To Me.dbObj.NumLocales - 1
Me.index = i
t(i) = New Thread(AddressOf MainLoop)
t(i).Start()
'spin until thread starts
While Not (t(i).IsAlive)
End While
'yield to other threads
Thread.Sleep(0)
Dim logEntry As String
logEntry = String.Format("Waiting to send emails and " _
+ "faxes for {0}.", dbObj.Locale(i))
log.WriteEntry(ServiceName, logEntry)
Next i

End Sub


Public Sub MainLoop()

Dim TimeDiff As Integer
Dim Interval As Integer
Dim i As Integer = Me.index
Dim secsFromMidnightToGo As Integer
Dim secsFromMidnightToNow As Integer
secsFromMidnightToGo = CInt(DateDiff("s", CDate("12/30/1899 12:00:00
AM"), _
Me.dbObj.GoTime(i)))
secsFromMidnightToNow = CInt(DateDiff("s", TimeOfDay, Today))
Dim hrs, mins, secs As Integer

Do
If secsFromMidnightToNow > secsFromMidnightToGo Then
TimeDiff = secsFromMidnightToNow - secsFromMidnightToGo
Interval = (TwentyFourHrs - TimeDiff) * 1000 'miliseconds
ElseIf secsFromMidnightToGo > secsFromMidnightToNow Then
TimeDiff = secsFromMidnightToGo - secsFromMidnightToNow
Interval = TimeDiff * 1000
End If

Dim log As EventLog = New EventLog()
Dim logEntry As String
secs = ((Interval / 1000) Mod 3600) Mod 60
mins = (((Interval / 1000) - secs) Mod 3600) / 60
hrs = ((Interval / 1000) - secs - (mins * 60)) / 3600
logEntry = String.Format("Waiting for {0}hrs, {1}min " _
+ "and {2} sec to send emails and faxes for {3}.", _
hrs, mins, secs, Me.dbObj.Locale(i))
log.WriteEntry(ServiceName, logEntry)
Thread.Sleep(Interval)
logEntry = String.Format("Sending emails for {0}...", _
Me.dbObj.Locale(i))
log.WriteEntry(ServiceName, logEntry)
Me.dbObj.SendEMails(i)
logEntry = String.Format("Done sending emails for {0}", _
Me.dbObj.Locale(i))
log.WriteEntry(ServiceName, logEntry)
logEntry = String.Format("Sending faxes for {0}...", _
Me.dbObj.Locale(i))
log.WriteEntry(ServiceName, logEntry)
Me.dbObj.SendFaxes(i)
logEntry = String.Format("Done sending faxes for {0}", _
Me.dbObj.Locale(i))
log.WriteEntry(ServiceName, logEntry)
Loop

End Sub

......
 
Fabio,

From just looking at the code, I think that the problem lies in that your variable t in the OnStart event is declared in the wrong
place, so as soon as the OnStart event is completed, the variable will be destroyed, and with it all your threads. Move it to the
top of the class, and try it again.

One other thing, your threads will all just run once, and never again, so what you also might try doing is put in a variable that
monitors whether the service is still running, and then run your MainLoop in a loop that checks if the service is still running.
That way you won't have to stop and start your service every day.

HTH

Thys Brits
MCSD/MCSD.Net

I am trying to write a windows service that sends emails to clients at
specific times based on information in a sql db. Since this is done for
multiple cities, I start a thread for each city and continue the processing
from each thread. My service starts fine (gives me no errors, etc), but it
doesn't seem to start the new threads. I am new to windows services, so I
don't know if I'm doing something wrong. Should I maybe be doing this with
events? Below is the code for the OnStart Method and the thread that is
supposed to start multiple times. If you need the rest of the code, email
me and I will send to you. Thanks.

Public MustInherit Class EmailPump : Inherits ServiceBase

Public Const TwentyFourHrs As Long = 86400 'There are 86,400 seconds in
24 hours
Private name As String
Private index As Integer
Private dbObj As RgsDbConnection

......

Protected Overrides Sub OnStart(ByVal args() As String)
Dim i As Integer
Dim t(Me.dbObj.NumLocales - 1) As Thread
Dim log As EventLog = New EventLog()

log.WriteEntry(ServiceName, "Service started")
For i = 0 To Me.dbObj.NumLocales - 1
Me.index = i
t(i) = New Thread(AddressOf MainLoop)
t(i).Start()
'spin until thread starts
While Not (t(i).IsAlive)
End While
'yield to other threads
Thread.Sleep(0)
Dim logEntry As String
logEntry = String.Format("Waiting to send emails and " _
+ "faxes for {0}.", dbObj.Locale(i))
log.WriteEntry(ServiceName, logEntry)
Next i

End Sub


Public Sub MainLoop()

Dim TimeDiff As Integer
Dim Interval As Integer
Dim i As Integer = Me.index
Dim secsFromMidnightToGo As Integer
Dim secsFromMidnightToNow As Integer
secsFromMidnightToGo = CInt(DateDiff("s", CDate("12/30/1899 12:00:00
AM"), _
Me.dbObj.GoTime(i)))
secsFromMidnightToNow = CInt(DateDiff("s", TimeOfDay, Today))
Dim hrs, mins, secs As Integer

Do
If secsFromMidnightToNow > secsFromMidnightToGo Then
TimeDiff = secsFromMidnightToNow - secsFromMidnightToGo
Interval = (TwentyFourHrs - TimeDiff) * 1000 'miliseconds
ElseIf secsFromMidnightToGo > secsFromMidnightToNow Then
TimeDiff = secsFromMidnightToGo - secsFromMidnightToNow
Interval = TimeDiff * 1000
End If

Dim log As EventLog = New EventLog()
Dim logEntry As String
secs = ((Interval / 1000) Mod 3600) Mod 60
mins = (((Interval / 1000) - secs) Mod 3600) / 60
hrs = ((Interval / 1000) - secs - (mins * 60)) / 3600
logEntry = String.Format("Waiting for {0}hrs, {1}min " _
+ "and {2} sec to send emails and faxes for {3}.", _
hrs, mins, secs, Me.dbObj.Locale(i))
log.WriteEntry(ServiceName, logEntry)
Thread.Sleep(Interval)
logEntry = String.Format("Sending emails for {0}...", _
Me.dbObj.Locale(i))
log.WriteEntry(ServiceName, logEntry)
Me.dbObj.SendEMails(i)
logEntry = String.Format("Done sending emails for {0}", _
Me.dbObj.Locale(i))
log.WriteEntry(ServiceName, logEntry)
logEntry = String.Format("Sending faxes for {0}...", _
Me.dbObj.Locale(i))
log.WriteEntry(ServiceName, logEntry)
Me.dbObj.SendFaxes(i)
logEntry = String.Format("Done sending faxes for {0}", _
Me.dbObj.Locale(i))
log.WriteEntry(ServiceName, logEntry)
Loop

End Sub

......
 
But isn't the code looping and checking for isalive , which would ensure
that the all the threads has completed execution.

Thys Brits said:
Fabio,

From just looking at the code, I think that the problem lies in that your
variable t in the OnStart event is declared in the wrong
place, so as soon as the OnStart event is completed, the variable will be
destroyed, and with it all your threads. Move it to the
top of the class, and try it again.

One other thing, your threads will all just run once, and never again, so
what you also might try doing is put in a variable that
monitors whether the service is still running, and then run your MainLoop
in a loop that checks if the service is still running.
 
Hi Thys,

Thanks for your help, but this didn't seem to solve my problem. Does anyone
have any other ideas out there?


Thys Brits said:
Fabio,

From just looking at the code, I think that the problem lies in that your
variable t in the OnStart event is declared in the wrong
place, so as soon as the OnStart event is completed, the variable will be
destroyed, and with it all your threads. Move it to the
top of the class, and try it again.

One other thing, your threads will all just run once, and never again, so
what you also might try doing is put in a variable that
monitors whether the service is still running, and then run your MainLoop
in a loop that checks if the service is still running.
 
Hi again,

Have you tried debugging the service to see where it's getting stuck? If you're having trouble debugging the service, let me/us
know.

Thys

Hi Thys,

Thanks for your help, but this didn't seem to solve my problem. Does anyone
have any other ideas out there?


Thys Brits said:
Fabio,

From just looking at the code, I think that the problem lies in that your
variable t in the OnStart event is declared in the wrong
place, so as soon as the OnStart event is completed, the variable will be
destroyed, and with it all your threads. Move it to the
top of the class, and try it again.

One other thing, your threads will all just run once, and never again, so
what you also might try doing is put in a variable that
monitors whether the service is still running, and then run your MainLoop
in a loop that checks if the service is still running.
 
Hi Thys,

I really appreciate you helping me out! Thanks so much. I don't really
know how to debug a windows service since I have to install the service in
order to run it. Kinda confusing. As a work-around, I have set some lines
in the code to write to the application event log. From that, I can tell
that all the code in OnStart runs (it writes to the event log before and
after the threads are supposedly started) and it even writes the name of the
cities that it retrieves from the DB. But it never runs any code from
MainLoop, which should be run 5 times (that's how many cities I have in the
DB), in 5 seperate threads. I know this because the threads never write to
the event log.

Would it be easier/better to write the mainloop method in a seperate class
and then call that method asynchronously from OnStart? Thanks again.


fp


Thys Brits said:
Hi again,

Have you tried debugging the service to see where it's getting stuck? If
you're having trouble debugging the service, let me/us
 
Hi Fabio,

There are two thngs that occur to me that you can do.

Firstly, write this as a standard application. It's not doing anything
particulalry 'servicey', like watching the system for 48 hours and amassing
data, etc. So write it as an aplication where you are in familiar territory
debugging-wise. Then, when you've got it working, take out the guts and
transplant them into a Windows Service framework.

Secondly, when working with Threads, its useful to take advantage of the
Name property. When you create your Threads, given them a name which you can
subsequently display in any debug output. This will let you know who is doing
what.

If you continue to have problems, I'm happy to take your project for a
spin - but give it a bash yourself first. Good luck. :-)

Regards,
Fergus
 
Hi again Fabio,

A further thought.

Yes, do move the mailing code into a class of its own. If nothing else, it
will separate the application framework from the functionality. Much cleaner.

Regards,
Fergus
 
Hi,

I was currently working on such situation. I am not sure what is wrong
in your code. But don't you have to wait for your threads to get
finish before you return from OnStart() method.

And make sure that OnStart() does not get called while any of the
previous thread is not finished. I can say that even now the threads
are executing Main Loop but they will not put any message in event
viewer until some time passes or until they are done. I have observed
that all the threads post message to event viewer at the same time.
And it may be happening that the MainLoop for each thread waits for
each other somehow and it may be going into infinite wait..

Put a sleep wait in OnStart() and then after some time, INTERRUPT each
thread if they are still alive. After interruption they all will
display message in event viewer.

Thanks,
piyush
 
Back
Top