|
|
#Region "Includes"
|
|
|
|
|
|
Imports System.ServiceProcess
|
|
|
Imports System.Data.SqlClient
|
|
|
Imports System.Xml
|
|
|
|
|
|
Imports Common.Common
|
|
|
|
|
|
#End Region
|
|
|
|
|
|
Public Class BMSService
|
|
|
Inherits System.ServiceProcess.ServiceBase
|
|
|
|
|
|
#Region "Members"
|
|
|
|
|
|
Private m_TimerStarter As System.Threading.Timer
|
|
|
Private m_TimerWatcher As System.Threading.Timer
|
|
|
Private m_EventLog As EventLog
|
|
|
Private m_StartJobs As DataSet
|
|
|
Private m_WatchJobs As DataSet
|
|
|
Private m_Common As Common.Common
|
|
|
|
|
|
#End Region
|
|
|
|
|
|
#Region " Component Designer generated code "
|
|
|
|
|
|
Public Sub New()
|
|
|
MyBase.New()
|
|
|
|
|
|
' This call is required by the Component Designer.
|
|
|
InitializeComponent()
|
|
|
|
|
|
' Add any initialization after the InitializeComponent() call
|
|
|
|
|
|
End Sub
|
|
|
|
|
|
'UserService overrides dispose to clean up the component list.
|
|
|
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
|
|
|
If disposing Then
|
|
|
If Not (components Is Nothing) Then
|
|
|
components.Dispose()
|
|
|
End If
|
|
|
End If
|
|
|
MyBase.Dispose(disposing)
|
|
|
End Sub
|
|
|
|
|
|
' The main entry point for the process
|
|
|
<MTAThread()> _
|
|
|
Shared Sub Main()
|
|
|
' Dim ServicesToRun() As System.ServiceProcess.ServiceBase
|
|
|
|
|
|
' More than one NT Service may run within the same process. To add
|
|
|
' another service to this process, change the following line to
|
|
|
' create a second service object. For example,
|
|
|
'
|
|
|
' ServicesToRun = New System.ServiceProcess.ServiceBase () {New Service1, New MySecondUserService}
|
|
|
'
|
|
|
' ServicesToRun = New System.ServiceProcess.ServiceBase() {New BMSService}
|
|
|
|
|
|
' System.ServiceProcess.ServiceBase.Run(ServicesToRun)
|
|
|
|
|
|
'-----------------
|
|
|
'DEBUG check don't work in windows service manager...
|
|
|
#If DEBUG Then
|
|
|
Dim service As New BMSService
|
|
|
service.StartService()
|
|
|
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite)
|
|
|
#Else
|
|
|
Dim ServicesToRun() As System.ServiceProcess.ServiceBase
|
|
|
ServicesToRun = New System.ServiceProcess.ServiceBase() {New BMSService}
|
|
|
System.ServiceProcess.ServiceBase.Run(ServicesToRun)
|
|
|
#End If
|
|
|
|
|
|
End Sub
|
|
|
|
|
|
'Required by the Component Designer
|
|
|
Private components As System.ComponentModel.IContainer
|
|
|
|
|
|
' NOTE: The following procedure is required by the Component Designer
|
|
|
' It can be modified using the Component Designer.
|
|
|
' Do not modify it using the code editor.
|
|
|
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
|
|
|
'
|
|
|
'BMSService
|
|
|
'
|
|
|
Me.ServiceName = "BMS Serivce"
|
|
|
|
|
|
End Sub
|
|
|
|
|
|
#End Region
|
|
|
|
|
|
#Region "Service Start / Stopp"
|
|
|
|
|
|
Protected Overrides Sub OnStart(ByVal args() As String)
|
|
|
StartService()
|
|
|
End Sub
|
|
|
|
|
|
Protected Overrides Sub OnStop()
|
|
|
|
|
|
End Sub
|
|
|
|
|
|
#End Region
|
|
|
|
|
|
#Region "Private Methods"
|
|
|
|
|
|
'Occures ever time the timer elapses
|
|
|
Sub TimeElapsedStarter(ByVal stateInfo As Object)
|
|
|
Try
|
|
|
'Load and execute starter Jobs
|
|
|
m_StartJobs.Clear()
|
|
|
DataAccess.Job.LoadJobs(m_Common, JobType.StartJob, m_StartJobs)
|
|
|
ExecuteStartJobs()
|
|
|
Catch ex As Exception
|
|
|
WriteEventLog("Fehler TimeElapsedStarter: " & ex.Message & Environment.NewLine & Environment.NewLine & ex.StackTrace, EventLogEntryType.Error)
|
|
|
End Try
|
|
|
End Sub
|
|
|
|
|
|
'Occures ever time the timer elapses
|
|
|
Sub TimeElapsedWatcher(ByVal stateInfo As Object)
|
|
|
Try
|
|
|
'Load and execute starter Jobs
|
|
|
m_WatchJobs.Clear()
|
|
|
DataAccess.Job.LoadJobs(m_Common, JobType.WatchJob, m_WatchJobs)
|
|
|
ExecuteWatchJobs()
|
|
|
Catch ex As Exception
|
|
|
WriteEventLog("Fehler TimeElapsedWatcher: " & ex.Message & Environment.NewLine & Environment.NewLine & ex.StackTrace, EventLogEntryType.Error)
|
|
|
End Try
|
|
|
End Sub
|
|
|
|
|
|
'Initializes all the service start stuff...
|
|
|
Private Sub StartService()
|
|
|
Try
|
|
|
m_EventLog = New EventLog
|
|
|
m_Common = New Common.Common
|
|
|
|
|
|
'Cannot use System.Timers.Timer due a Bug (http://support.microsoft.com/default.aspx?scid=kb;en-us;842793)
|
|
|
Dim autoEvent As New System.Threading.AutoResetEvent(False)
|
|
|
Dim timerStarterDelegate As System.Threading.TimerCallback = AddressOf TimeElapsedStarter
|
|
|
Dim timerWatcherDelegate As System.Threading.TimerCallback = AddressOf TimeElapsedWatcher
|
|
|
|
|
|
m_TimerStarter = New System.Threading.Timer(timerStarterDelegate, autoEvent, 1000, m_Common.StartJobInterval)
|
|
|
m_TimerWatcher = New System.Threading.Timer(timerWatcherDelegate, autoEvent, m_Common.WatchJobInterval, m_Common.WatchJobInterval)
|
|
|
|
|
|
m_StartJobs = New DataSet
|
|
|
m_WatchJobs = New DataSet
|
|
|
|
|
|
Catch ex As Exception
|
|
|
WriteEventLog("Fehler: " & ex.Message & Environment.NewLine & Environment.NewLine & ex.StackTrace, EventLogEntryType.Error)
|
|
|
End Try
|
|
|
End Sub
|
|
|
|
|
|
'Executes all watch jobs
|
|
|
Private Sub ExecuteWatchJobs()
|
|
|
Try
|
|
|
'Check if there are any jobs
|
|
|
If m_WatchJobs.Tables.Count > 0 And m_WatchJobs.Tables.Item(0).Rows.Count > 0 Then
|
|
|
Dim dt As DataTable
|
|
|
Dim dsFailedJobs As New DataSet
|
|
|
Dim startTime As New DateTime, endTime As New DateTime
|
|
|
Dim houres As Integer, minutes As Integer
|
|
|
|
|
|
dt = m_WatchJobs.Tables.Item(0)
|
|
|
|
|
|
Dim dr As DataRow
|
|
|
|
|
|
For Each dr In dt.Rows
|
|
|
'Check if job is in valid date range
|
|
|
If dr.Item("DatumStart") <= DateTime.Now And CType(dr.Item("DatumEnde"), Date).AddDays(1) >= DateTime.Now Then
|
|
|
|
|
|
ConvertToDateTime(dr.Item("ZeitVon"), dr.Item("ZeitBis"), startTime, endTime)
|
|
|
|
|
|
If startTime <= DateTime.Now And endTime >= DateTime.Now Then
|
|
|
'job seems to be in his valid datetime range...
|
|
|
Dim lastRunStart As DateTime
|
|
|
If dr("LastRunStart") Is DBNull.Value Then
|
|
|
'use dummy date if the job never run before
|
|
|
lastRunStart = New DateTime(1)
|
|
|
Else
|
|
|
lastRunStart = CDate(dr("LastRunStart"))
|
|
|
End If
|
|
|
|
|
|
'get all failed starter jobs
|
|
|
dsFailedJobs.Clear()
|
|
|
DataAccess.Job.GetFailedStartJobs(m_Common, dr("ProgrammId"), dsFailedJobs)
|
|
|
SendNotifications(dsFailedJobs, "Das Programm ##PROG_NAME## hat nicht innerhalb der Zeitspanne von " & m_Common.MaximalStartDuration.ToString() & " Minuten die Start() Methode der BMS-Dll aufgerufen. M<>glicherweise konnte das Programm nicht gestartet werden.", JobType.StartJob)
|
|
|
|
|
|
'check for failed execution jobs
|
|
|
dsFailedJobs.Clear()
|
|
|
DataAccess.Job.GetFailedExecJobs(m_Common, dr("ProgrammId"), dsFailedJobs)
|
|
|
If dsFailedJobs.Tables.Count > 0 And dsFailedJobs.Tables(0).Rows.Count > 0 Then
|
|
|
SendNotifications(dsFailedJobs, "Das Programm ##PROG_NAME## konnte nicht innerhalb der vordefinierten Laufzeit von " & dsFailedJobs.Tables(0).Rows(0)("MaxLaufzeit").ToString() & " Minuten ausgef<65>hrt werden.", JobType.WatchJob)
|
|
|
End If
|
|
|
End If
|
|
|
End If
|
|
|
Next
|
|
|
End If
|
|
|
Catch ex As Exception
|
|
|
Throw ex
|
|
|
End Try
|
|
|
End Sub
|
|
|
|
|
|
'Executes all starter jobs
|
|
|
Private Sub ExecuteStartJobs()
|
|
|
Try
|
|
|
'Check if there are any jobs
|
|
|
If m_StartJobs.Tables.Count > 0 And m_StartJobs.Tables.Item(0).Rows.Count > 0 Then
|
|
|
Dim dt As DataTable
|
|
|
Dim startTime As New DateTime, endTime As New DateTime
|
|
|
|
|
|
dt = m_StartJobs.Tables.Item(0)
|
|
|
|
|
|
Dim dr As DataRow
|
|
|
|
|
|
For Each dr In dt.Rows
|
|
|
If dr("RunJob") Then
|
|
|
'RunJob has to run as fast as possible
|
|
|
If Not dr("IsRunning") Then
|
|
|
'job isn't already running
|
|
|
Dim job As New Job(m_Common, dr("JobId"), dr("Beschreibung"), dr("ProgrammId"), CType(dr("JobTypId"), JobType), CType(dr("JobStartTypId"), JobStartType))
|
|
|
If Not dr("ParentProgrammId") Is DBNull.Value Then
|
|
|
Dim parentProgrammId As Integer = dr("ParentProgrammId")
|
|
|
'job has a relation to another job, validate if parent job is currently executing...
|
|
|
If Not DataAccess.Job.CheckIsRunning(m_Common.DSN, parentProgrammId) Then
|
|
|
'parent job is not running, -> run job
|
|
|
'NachLetzterAusfuerung False, cause no one cares about next start time on RunJobs
|
|
|
job.Launch(True, False)
|
|
|
End If
|
|
|
Else
|
|
|
'run job
|
|
|
job.Launch(True, False)
|
|
|
End If
|
|
|
End If
|
|
|
Else
|
|
|
'Check if job is in valid date range
|
|
|
If dr.Item("DatumStart") <= DateTime.Now And CType(dr.Item("DatumEnde"), Date).AddDays(1) >= DateTime.Now Then
|
|
|
|
|
|
ConvertToDateTime(dr.Item("ZeitVon"), dr.Item("ZeitBis"), startTime, endTime)
|
|
|
|
|
|
If startTime <= DateTime.Now And endTime >= DateTime.Now Then
|
|
|
If dr("NextStartDate") < DateTime.Now Then
|
|
|
'interval has elapsed (should already be checked in GetJobs SP...)
|
|
|
If Not dr("IsRunning") Then
|
|
|
'job isn't already running
|
|
|
Dim job As New Job(m_Common, dr("JobId"), dr("Beschreibung"), dr("ProgrammId"), CType(dr("JobTypId"), JobType), CType(dr("JobStartTypId"), JobStartType))
|
|
|
If Not dr("ParentProgrammId") Is DBNull.Value Then
|
|
|
Dim parentProgrammId As Integer = dr("ParentProgrammId")
|
|
|
'job has a relation to another job, validate if parent job is currently executing...
|
|
|
If Not DataAccess.Job.CheckIsRunning(m_Common.DSN, parentProgrammId) Then
|
|
|
'parent job is not running, -> run job
|
|
|
job.Launch(False, dr("NachLetzterAusfuerung"))
|
|
|
End If
|
|
|
Else
|
|
|
'run job
|
|
|
job.Launch(False, dr("NachLetzterAusfuerung"))
|
|
|
End If
|
|
|
End If
|
|
|
End If
|
|
|
End If
|
|
|
End If
|
|
|
End If
|
|
|
Next
|
|
|
End If
|
|
|
Catch ex As Exception
|
|
|
Throw ex
|
|
|
End Try
|
|
|
End Sub
|
|
|
|
|
|
'Sends notifications to the pre-definied receivers (file or mail)
|
|
|
Private Sub SendNotifications(ByVal ds As DataSet, ByVal message As String, ByVal jobType As JobType)
|
|
|
Try
|
|
|
Dim drFailed As DataRow, drNotifications As DataRow
|
|
|
Dim dsNotifications As New DataSet
|
|
|
Dim hasNotiLimitReached As Boolean
|
|
|
|
|
|
hasNotiLimitReached = False
|
|
|
|
|
|
If ds.Tables.Count > 0 Then
|
|
|
If ds.Tables(0).Rows.Count > 0 Then
|
|
|
For Each drFailed In ds.Tables(0).Rows
|
|
|
|
|
|
'check if we already reached the limits for sending start/satch notifications
|
|
|
If jobType = jobType.WatchJob Then
|
|
|
If drFailed("NotiCounter") >= m_Common.MaxWatcherNotifications Then
|
|
|
hasNotiLimitReached = True
|
|
|
Else
|
|
|
hasNotiLimitReached = False
|
|
|
End If
|
|
|
Else
|
|
|
If drFailed("NotiCounter") >= m_Common.MaxStarterNotifications Then
|
|
|
hasNotiLimitReached = True
|
|
|
Else
|
|
|
hasNotiLimitReached = False
|
|
|
End If
|
|
|
End If
|
|
|
|
|
|
If Not hasNotiLimitReached Then
|
|
|
'get all notifications to a programm
|
|
|
dsNotifications.Clear()
|
|
|
DataAccess.Job.GetNotifications(m_Common, CInt(drFailed("ProgrammId")), dsNotifications)
|
|
|
If dsNotifications.Tables.Count > 0 Then
|
|
|
'seems to have rows in a table...
|
|
|
DataAccess.Job.SendNotification(m_Common, CInt(drFailed("ProgrammId")), dsNotifications, message, drFailed("JobId"), jobType)
|
|
|
End If
|
|
|
End If
|
|
|
|
|
|
If drFailed("NachLetzterAusfuerung") Then
|
|
|
DataAccess.Job.SetJobLastRun(m_Common.DSN, drFailed("JobId"), LastRun.End)
|
|
|
If Not drFailed("RunJob") Then
|
|
|
'calc next start exec time if its not a run job
|
|
|
DataAccess.Job.SetNextExecDateTime(m_Common.DSN, drFailed("JobId"))
|
|
|
End If
|
|
|
End If
|
|
|
Next
|
|
|
End If
|
|
|
End If
|
|
|
Catch ex As Exception
|
|
|
Throw ex
|
|
|
End Try
|
|
|
End Sub
|
|
|
|
|
|
#End Region
|
|
|
|
|
|
#Region "Helper Methods"
|
|
|
|
|
|
'Converts the times from database to a datetime datatyp for better handling
|
|
|
Private Sub ConvertToDateTime(ByVal startTime As String, ByVal endTime As String, ByRef startDateTime As DateTime, ByRef endDateTime As DateTime)
|
|
|
Try
|
|
|
Dim houres As Integer, minutes As Integer
|
|
|
|
|
|
'let's parse some time stuff to get start and end time in a better datatype...
|
|
|
houres = Left(startTime, 2)
|
|
|
minutes = Right(startTime, 2)
|
|
|
|
|
|
startDateTime = DateTime.Today.AddHours(houres)
|
|
|
startDateTime = startDateTime.AddMinutes(minutes)
|
|
|
|
|
|
houres = Left(endTime, 2)
|
|
|
minutes = Right(endTime, 2)
|
|
|
|
|
|
endDateTime = DateTime.Today.AddHours(houres)
|
|
|
endDateTime = endDateTime.AddMinutes(minutes)
|
|
|
|
|
|
'if endtime is less, endtime is on next day
|
|
|
'Ex: Start 23:15; End 02:45
|
|
|
If endDateTime < startDateTime Then
|
|
|
endTime = endDateTime.AddDays(1)
|
|
|
End If
|
|
|
Catch ex As Exception
|
|
|
Throw ex
|
|
|
End Try
|
|
|
End Sub
|
|
|
|
|
|
'Writes an message to windows event log
|
|
|
Private Sub WriteEventLog(ByVal errorMessage As String, ByVal eventLogType As EventLogEntryType)
|
|
|
Try
|
|
|
m_Common.Log(m_Common.SERVICE_DISPLAY_NAME, "Quelle: " & SERVICE_DISPLAY_NAME & Environment.NewLine & "Meldung: " & errorMessage, eventLogType)
|
|
|
Catch ex As Exception
|
|
|
System.Diagnostics.EventLog.WriteEntry(SERVICE_DISPLAY_NAME, errorMessage, eventLogType)
|
|
|
System.Diagnostics.EventLog.WriteEntry(SERVICE_DISPLAY_NAME, ex.Message + Environment.NewLine + ex.StackTrace, eventLogType.Error)
|
|
|
End Try
|
|
|
End Sub
|
|
|
|
|
|
#End Region
|
|
|
|
|
|
End Class
|