A service (Windows service) is used to create multiple threads and execute the different areas each thread is responsible for. For two specific threads the connection string and settings seems to be overwritten. Both these threads calls the same class at a point to execute the requirements. Both these threads are using a different connection string to a database, thus two different areas of where the database is hosted.
The problem is, the record that needs to be processed is picked up from the correct database and the error (due to incorrect setting) is returned and logged on the incorrect database. This problem is intermittent and does not occur regularly. A record being processed will fail with this problem, but when this same record is run 1 min later, everything succeeds (correct db connection and settings)
The two threads initiated in the class:
The connection string is located in a database that is retrieved via the DBUtils class
Public Class MyClassName
Private WithEvents MyTimer As Timers.Timer = Nothing
Private eveHUBSPOTUPDATEEVENTS_NZ As New Threading.Thread(AddressOf EventHubSpotUpdateEvents)
Private eveSYSEVENTS_AUS As New Threading.Thread(AddressOf EventSystemEvents_Aus)
End Class
Constructor for class
Public Sub New()
InitializeComponent()
//other config settings
ServicePointManager.SecurityProtocol = Net.SecurityProtocolType.Tls12 Or Net.SecurityProtocolType.Tls11 Or Net.SecurityProtocolType.Tls Or Net.SecurityProtocolType.Ssl3
End Sub
OnStart
event:
Protected Overrides Sub OnStart(ByVal args() As String)
SetTimerProps(False)
End Sub
Private Sub SetTimerProps(ByVal doDisable As Boolean)
ClearCounters()
If doDisable Then
If MyTimer IsNot Nothing Then
MyTimer.Enabled = False
MyTimer = Nothing
End If
Else
_mustDoHubspotEventsNZ = MustDOHubSpotEventsNZ()
_mustDoHubspotEvents_Aus = MustDoHubSpotEvents_Aus()
MyTimer = New Timers.Timer With {
.Interval = 10000, '10 Seconds
.AutoReset = False,
.Enabled = True
}
End If
End Sub
The threads are then created on a timer (same class as above):
Private Sub MyTimer_Elapsed(ByVal sender As Object, ByVal e As Timers.ElapsedEventArgs) Handles MyTimer.Elapsed
Try
MyTimer.Enabled = False
IncrementCounters()
If Not eveHUBSPOTUPDATEEVENTS_NZ.IsAlive Then
eveHUBSPOTUPDATEEVENTS = New Threading.Thread(AddressOf EventHubSpotUpdateEvents) With {
.IsBackground = True,
.Priority = Threading.ThreadPriority.Normal
}
eveHUBSPOTUPDATEEVENTS_NZ.Start()
End If
If nSYSEVENTS_AUS_Counter > 1 AndAlso Not eveSYSEVENTS_AUS.IsAlive Then
nSYSEVENTS_AUS_Counter = 0
If _mustDoSystemEvents_Aus Then
eveSYSEVENTS_AUS = New Threading.Thread(AddressOf EventSystemEvents_Aus) With {
.IsBackground = True,
.Priority = Threading.ThreadPriority.Highest
}
eveSYSEVENTS_AUS.Start()
End If
End If
Catch ex As Exception
//Error Handling
MyTimer.Enabled = True
End Sub
Both these threads then goes to a method to retrieve the records that needs to be processed.
For the NZ process the connection string
Public Class EventsNZ
Public Sub New()
_connectionString = DBUtils.SureSetting.GetSetting("ConnStringNZ")
_environment = DBUtils.SureSetting.GetSetting("Environment")
End Sub
End Class
And for the Aus process the connection string:
Public Class EventsAus
Public Sub New()
_connectionString = DBUtils.SureSetting.GetSetting("ConnStringAus")
_environment = DBUtils.SureSetting.GetSetting("Environment")
End Sub
End Class
The records is then retrieved (NZ):
Private Sub HandleEventsNZ()
Try
Const sqlEvents = "script to retrieve the required records"
Dim systemEventsData = _dbHelper.GetLongRunningSQLDataTable(sqlEvents, 600, Nothing)
For Each eventItem As DataRow In systemEventsData.Rows()
Dim feedback = HandleHubspotEvent(eventItem, _connectionString )
UpdateEventToCompleted(StringAsLong(eventItem("Sys_Key")), feedback)
Next
systemEventsData.Dispose()
Catch ex As Exception
//some error handling
End Try
End Sub
Private Function HandleHubspotEvent(eventData As DataRow, dbConnectionString As String) As String
Try
//some validations
Dim hubspotWorker As New HubspotIntegrator(_connectionString, productId, StringAsInteger(eventData("User_Cde")))
Return hubspotWorker.HubspotCreateOrUpdate(eventData("Area_Cde").ToString(),
StringAsLong(eventData("Reference_Cde")),
eventData("Other_Ref2").ToString(), eventResult)
Catch ex As Exception
//error handling
End Try
End Sub
End Function
The records is then retrieved (Aus):
Similar process to retrieve the records. Aus is only in its own class due to migration that will take place. Once the Aus data is migrated to the NZ side, this class and the corresponding thread will be removed.
Aus will reach this method:
Private Function HandleHubspotEvent(ByRef eventData As DataRow) As String
Try
//some validation
Dim hubspotWorker As New HubspotIntegrator(_connectionString, productId, StringAsInteger(eventData("Event_User_Cde")))
Return hubspotWorker.HubspotCreateOrUpdate(eventData("Event_Area_Cde").ToString(),
StringAsLong(eventData("Event_Reference_Cde")),
eventData("Event_Other_Ref2").ToString(), "")
Catch ex As Exception
//error handling
End Try
End Function
Up until this point the correct connection is used. They both reach the same class to handle the process.
The connection is set up with immutable properties when calling the HubspotIntegrator class. The connection is not changed anywhere in the process (or any setting). The connection string is passed to this class. But for some reason, the connection string ends up being changed during the process.
Public Sub New(ByVal dbConnectionString As String, ByVal productId As Integer, ByVal userId As Integer)
If String.IsNullOrEmpty(dbConnectionString) OrElse dbConnectionString = "" Then
Throw New ArgumentException("Invalid Connection String!")
End If
If productId = 0 Then
Throw New ArgumentException("Invalid Product ID!")
End If
_dbConnectionString = dbConnectionString
_dbHelper = New DBUtil(_dbConnectionString)
_dbLookup = New SureDBLookup(dbConnectionString)
_sureQuote = New SureQuote(dbConnectionString)
_productId = productId
_systemMappingWorker = New SureSystemMapping(_dbConnectionString)
_userId = userId
_hsDataHelpers = New HubspotDataHelpers(dbConnectionString)
Dim productRuleData = _dbLookup.GetProductRuleData(productId, 0, "ALLOW_HUBSPOT", Nothing)
If productRuleData Is Nothing OrElse productRuleData("Pro_Val1").ToString <> "Y" Then
Throw New ArgumentException("Invalid Product ID! Not a HubSpot product")
End If
_hubspotBearerToken = DBUtils.SureSetting.GetSetting(productRuleData("Pro_Val2").ToString().Trim())
If _hubspotBearerToken = Nothing Then
Throw New ArgumentException("Invalid Hubspot BearerToken - HUBSPOT_BEARERTOKEN is not defined")
End If
End Sub
Any advice will be appreciated on why/how this can happen? and if there is something I'm missing that I can look at (been looking at this for a week and still not seeing the issue)
It looks to me like both of your functions that retrieve your connection string and environment are setting the same top-level variables _connectionString and _environment. Since these are running in separate threads, it may look like things are partially working, but as you noted, the connection string gets changed because one of the two function calls is overwriting it.
How is your HandleEventsNZ sub going to know which connection string to use?