You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

366 lines
15 KiB

#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