J'ai créé un petit service en VB.NET 2008 (framework 3.5) permettant d'afficher un message (je sais, c'est pas propre, mais c'est plus pour le debugging que pour la release...) dès qu'une entrée est ajoutée dans une table particulière d'une base. L'installation se déroule sans problèmes, mais lorsque je veux lancer mon service, j'ai le message suivant :
---------------------------
Services
---------------------------
The AlertSMS service on Local Computer started and then stopped. Some services stop automatically if they have no work to do, for example, the Performance Logs and Alerts service.
---------------------------
OK
---------------------------
Le code est pourtant bien présent et bien placé (si j'en crois toute la doc que j'ai lue). J'ai longuement cherché une solution sur divers forums, en vain...
Je déclare mon timer dans la fonction OnStart(), puis je le lie à la fonction Timer_Tick pour que l'exécution se fasse à intervalle régulier.
Voici le code :
------------------------------------------------------------------------------------------------------------------------------------
Public Class AlertSMS
Protected Overrides Sub OnStart(ByVal args() As String)
Dim time As System.Threading.Timer
Dim callBack As New TimerCallback(AddressOf Timer_Tick)
time = New System.Threading.Timer(callBack, Nothing, 0, 50)
MsgBox("Le service surveille maintenant la table Alert...", MsgBoxStyle.Information, "Service démarré")
End Sub
Public Sub Timer_Tick(ByVal state As Object)
'Parcours de la liste des entrées de la table Alert
Dim allalerts As New DAL.AlertCollection
allalerts.Load()
For Each elem As DAL.Alert In allalerts.GetCollection()
MsgBox("Nouvelle alerte : " + vbCrLf + "Message #" + elem.MsgID, MsgBoxStyle.Exclamation, "Attention")
'*** Traitement de l'alerte ***
elem.Delete()
elem.Save()
Next
End Sub
End Class
------------------------------------------------------------------------------------------------------------------------------------
Vide ta fonction OnStart de manière à vérifier si le problème est là.
Il faut d'abord essayer de localiser le problème.
Là je suis pas chez moi, mais j'essaiera de t'aider une fois rentré.
Peut etre aussi, comme te le dit le message que tu n'as pas configuré ton message de manière à continuer indéfiniment.
__________________________
Prière de ne pas oublier le magnifique tag (résolu) si votre sujet l'est !
J'ai effectivement enlevé la MessageBox du OnStart() et le service ne s'arrête plus...Visiblement, il aimait pas ça. Le code fonctionne désormais (presque) correctement. En revanche, à son lancement, il bouffe plus de 50 Mo de RAM, et après plusieurs dizaines de minutes (même quand il n'a rien à faire a priori), il finit par saturer la mémoire totalement (2 Go de RAM pour un petit service, j'aurais lancé une fork bomb, ça aurait fait le même effet ! ). Peut-être que c'est la fonction récursive qu'il aime pas trop...
Voici le code. Le service :
Imports DAL
Imports AlertSMS.Business
Imports System.Threading
Imports System.Configuration
Public Class ServiceAlertSMS
Dim time As System.Threading.Timer
Protected Overrides Sub OnStart(ByVal args() As String)
Dim callBack As New TimerCallback(AddressOf Timer_Tick)
time = New System.Threading.Timer(callBack, Nothing, 0, 500)
End Sub
Public Sub Timer_Tick(ByVal state As Object)
'Parcours de la liste des entrées de la table Alert
Dim cAlerts As New DAL.AlertCollection()
cAlerts.Load()
For Each elem As DAL.Alert In cAlerts.GetCollectionAlert()
'*** Traitement de l'alerte ***
Dim msg As New Message(New Guid(elem.MsgID))
Dim currentUserId As String = ConfigurationManager.AppSettings("DefaultUser")
Dim idGsm() As String = SearchForPeople(currentUserId, msg.DateTime).Split(" ")
'Formatage de l'alerte ???
'Envoi du message au GSM
Dim newMsg As New Message()
msg.DateTime = Today.Date
msg.Text = "alerte Orion"
SendMsg(msg, idGsm(1))
'Affectation d'une personne au message d'alerte courant
Dim newIsSent As New IsSentTo()
newIsSent.IDMessage = msg.ID
newIsSent.IDUser = idGsm(0)
newIsSent.Add()
newIsSent.Save()
Try
'Suppression du message d'alerte de la table Alerts
elem.Delete()
elem.Save()
Catch ex As Exception
Throw ex
End Try
Next
End Sub
Public Sub SendMsg(ByRef msg As Message, ByVal userGsm As String)
'Envoi du message par le modem GSM
'Si l'envoi a réussi :
msg.IDStatus = "sent"
msg.
End Sub
Protected Overrides Sub OnStop()
EventLog.WriteEntry("AlertSMS", "Service stoppé !", EventLogEntryType.Warning, 0)
End Sub
End Class
Les traitements métier : Business
Public Shared Function SearchForPeople(ByVal userID As String, ByVal dt As DateTime) As String
Dim idGsm As String = "6b3b5295-0d68-4eed-9bdc-c4478c14000d 0000000000"
Dim test As Boolean = False
Dim person As New DAL.User(New Guid(userID))
Dim cAvl As New DAL.AvailabilityCollection()
cAvl.FindByUser(person.ID) ' on cherche les disponibilités de la personne trouvée précédement
For Each avl As DAL.Availability In cAvl.GetCollectionAvl()
If (avl.Enable = True) Then ' si la personne est disponible
If (dt.Hour >= avl.HourStart And dt.Hour < avl.HourEnd) Then
If (dt.DayOfWeek = DayOfWeek.Saturday Or dt.DayOfWeek = DayOfWeek.Sunday) Then
idGsm = person.ID + " " + avl.Gsm
Else
idGsm = person.ID + " " + person.Gsm
End If
EventLog.WriteEntry("ServiceAlertSMS", userID, EventLogEntryType.Information, 666)
userID = person.ID
test = True
End If
End If
Next
If (test = False) Then
idGsm = SearchForPeople(person.IDBackup, dt)
End If
Return idGsm
End Function
en fait, j'ai déjà essayé l'appel à dispose() mais apparemment je suis obligé d'implémenter IDisposable dans mes objets métier (DAL). Je l'ai fait et j'ai donc pu avoir accès à cette fonction mais visiblement, sois je n'implémente pas dispose() correctement, soit je ne l'appelle pas sur les bons objets...
J'ai testé aussi la méthode "bourrine" du GC manuel (solution a priori non recommandée) : System.GC.Collect()
Essaie de mettre dans ton code Timer, seulement un appel test à SearchForPeople, ça nous permettra de savoir si la fuite est dans cette fonction ou pas .
PS : Bien que je ne pense pas que ça soit là le problème, ce bout de code m'a l'air bizarre :
Public Sub SendMsg(ByRef msg As Message, ByVal userGsm As String)
'Envoi du message par le modem GSM
'Si l'envoi a réussi :
msg.IDStatus = "sent"
msg.
End Sub
.
As-tu coupé un code car il était trop long ?
__________________________
Prière de ne pas oublier le magnifique tag (résolu) si votre sujet l'est !
Concernant le code bizarre, c'est juste un oubli de ma part (je faisais des tests et la ligne "msg." n'a rien à faire ici...et le reste ne sert pas pour l'instant).
Je testerai l'appel unique à SearchForPeople() dans le timer demain matin car je n'ai pas accès à Visual Studio pour le moment...
Encore merci de t'intéresser à mon souci
j'ai pu tester l'appel à SearchForPeople seul dans l'événement du timer. La charge en mémoire continue d'augmenter en flèche (20 Mo de RAM en plus par seconde, à peu près...). De même lorsque seules restent les lignes :
'Parcours de la liste des entrées de la table Alert
Dim cAlerts As New DAL.AlertCollection()
cAlerts.Load()
(on charge juste les éléments de la table Alerts de la base)
Problème réglé :
Pas de souci du côté du garbage collector, il fait bien son boulot.
Par contre, la fonction SearchForPeople() ne parvenait pas à trouver quelqu'un, puisque personne n'était disponible à l'horaire indiqué...donc la récursion tournait longtemps, très longtemps...et ça pouvait durer encore !
Donc plus de problème et j'ai également optimisé la fonction (plus de récursivité).
Résultat : le service (même bombardé de messages) ne dépasse pas les 25 Mo en charge mémoire...