挂在BackgroundWorker中

时间:2014-03-12 18:43:16

标签: vb.net backgroundworker

我有一个应用程序,每隔几秒检查一次新订单。 如果它在数据库中看到一个新条目,它会触发BackgroundWorker来处理它。

我的表单上有3个列表框,待处理,已完成并失败。

Theres是第二个BackgroundWorker进程,在将有问题的项目移动到“已完成”列表框之前,它会异步检查api以查看订单是否已完全处理完毕。

在我在应用程序中一次抛出几个订单之前,一切似乎都工作正常。

它处理订单很好并将它们添加到待处理状态,它将检查其中的一些,但最终会陷入secondbackground工作进程。 它最终会因"This BackgroundWorker is currently busy"错误而崩溃。

我已经多次查看我的代码了,我无法看到它会崩溃的地方。 对我来说诊断这个的最好方法是什么?

下面是背景工作者的代码,我被卡住了......

Private Sub BuildProgressCheck_DoWork(sender As Object, e As ComponentModel.DoWorkEventArgs) _
    Handles BuildProgressCheck.DoWork

    lblstatus.Text = "Checking back on async jobs"

    Dim i As Integer
    For i = 0 To buildpendinglist.Items.Count - 1
        Beep()

        Dim cn As New MySqlConnection
        cn.ConnectionString = "server=" & dbserver & "; userid=" & dbusername & "; password=" & dbpassword & "; database=" & dbdatabase & ";Convert Zero Datetime=True"
        Dim jobcheck As New MySqlDataAdapter("Select * FROM dbcpman_jobs WHERE dbxid='" & buildpendinglist.Items(i) & "'", cn)
        Dim jobcheck_table As New DataTable
        jobcheck.Fill(jobcheck_table)
        Dim jobrow As DataRow
        jobrow = jobcheck_table.Select("failed = 'false'").FirstOrDefault()

        If Not jobrow Is Nothing Then

            Dim job_id As String = jobrow.Item("id")
            Dim job_jobid As String = jobrow.Item("jobid")
            Dim job_status As String = jobrow.Item("status")
            Dim job_dbxid As String = jobrow.Item("dbxid")
            Dim jobcommand As String = "command=queryAsyncJobResult&jobId=" & job_jobid
            Dim fulljobapicheckurl = cpapiurl & jobcommand

            Try
                Dim jobapicall As New System.Net.WebClient
                jobcheckresult = jobapicall.DownloadString(fulljobapicheckurl)

            Catch ex As Exception
                ''Problem submitting the api request?
            End Try

            If jobcheckresult.Contains("<jobstatus>1</jobstatus>") Then  ''If true, job has completed

                Dim doc As New System.Xml.XmlDocument
                doc.LoadXml(jobcheckresult) ''api_result contains xml returned from a http request.

                If doc.GetElementsByTagName("virtualmachine") IsNot Nothing Then
                    Dim elem As XmlNodeList = doc.GetElementsByTagName("virtualmachine").Item(0).ChildNodes
                    For Each item As XmlNode In elem
                        If item.Name.Equals("state") Then
                            new_vm_state += ((item.InnerText.ToString()) + Environment.NewLine)
                        ElseIf item.Name.Equals("hostname") Then
                            new_vm_hostname += ((item.InnerText.ToString()) + Environment.NewLine)
                        ElseIf item.Name.Equals("templatename") Then
                            new_vm_templatename += ((item.InnerText.ToString()) + Environment.NewLine)
                        ElseIf item.Name.Equals("cpunumber") Then
                            new_vm_cpunumber += ((item.InnerText.ToString()) + Environment.NewLine)
                        ElseIf item.Name.Equals("cpuspeed") Then
                            new_vm_cpuspeed += ((item.InnerText.ToString()) + Environment.NewLine)
                        ElseIf item.Name.Equals("memory") Then
                            new_vm_memory += ((item.InnerText.ToString()) + Environment.NewLine)
                        ElseIf item.Name.Equals("nic") Then
                            new_vm_netmask += ((item.ChildNodes.Item(3).InnerText.ToString()) + Environment.NewLine)
                            new_vm_gateway += ((item.ChildNodes.Item(4).InnerText.ToString()) + Environment.NewLine)
                            new_vm_ipaddress += ((item.ChildNodes.Item(5).InnerText.ToString()) + Environment.NewLine)
                            new_vm_macaddress += ((item.ChildNodes.Item(11).InnerText.ToString()) + Environment.NewLine)
                        ElseIf item.Name.Equals("instancename") Then
                            new_vm_instancename1 += ((item.InnerText.ToString()) + Environment.NewLine)
                        End If
                    Next
                End If

                new_vm_macaddress = new_vm_macaddress.ToUpper
                Dim privateip As String = new_vm_ipaddress.Replace(" ", "").ToString
                Dim publicip As String = privateip.Replace("172.16.11.", "198.73.112.")

                Try
                    Dim myCommand As New MySqlCommand
                    Dim myAdapter As New MySqlDataAdapter
                    Dim SQL As String
                    myCommand.Connection = cn
                    cn.Open()
                    myAdapter.SelectCommand = myCommand
                    SQL = "DELETE FROM dbcpman_jobs WHERE jobid = '" & job_jobid & "'"
                    myCommand.CommandText = SQL
                    myCommand.ExecuteNonQuery()
                    SQL = "UPDATE dbcpman_vm SET deployresponse = '" & jobcheckresult & "' WHERE dbx_id = '" & job_dbxid & "'"
                    myCommand.CommandText = SQL
                    myCommand.ExecuteNonQuery()
                    SQL = "UPDATE dbcpman_vm SET macaddress = '" & new_vm_macaddress & "' WHERE dbx_id = '" & job_dbxid & "'"
                    myCommand.CommandText = SQL
                    myCommand.ExecuteNonQuery()
                    SQL = "UPDATE dbcpman_vm SET publicip = '" & publicip & "' WHERE dbx_id = '" & job_dbxid & "'"
                    myCommand.CommandText = SQL
                    myCommand.ExecuteNonQuery()
                    SQL = "UPDATE dbcpman_vm SET privateip = '" & privateip & "' WHERE dbx_id = '" & job_dbxid & "'"
                    myCommand.CommandText = SQL
                    myCommand.ExecuteNonQuery()

                    cn.Close()

                    Dim new_vm_username As String = "clouduser"
                    Dim new_vm_password As String = GeneratePassword(7)
                    System.Threading.Thread.Sleep(1000)
                    Dim new_vm_support_username As String = "dbxsupport"
                    Dim new_vm_support_password As String = GenerateSupportPassword(7)

                    cn.Open()
                    myAdapter.SelectCommand = myCommand
                    SQL = "INSERT into dbcpman_credentials(username1, username2, password1, password2, type, link) VALUES ('" & new_vm_username & "','" & new_vm_support_username & "','" & new_vm_password & "','" & new_vm_support_password & "','Server root logon','" & job_dbxid & "')"
                    myCommand.CommandText = SQL
                    myCommand.ExecuteNonQuery()
                    SQL = "INSERT into dbcpman_vm_boot(dbxid, ip, macaddress, hostname) VALUES ('" & job_dbxid & "','" & new_vm_ipaddress & "','" & new_vm_macaddress & "','" & job_dbxid & "')"
                    myCommand.CommandText = SQL
                    myCommand.ExecuteNonQuery()
                    cn.Close()

                    Try  ''''add monitoring for this new host
                        Dim monitorurl As String = "http://192.168.16.32/addhost.php?hostname=" & job_dbxid & "&ipaddr=" & publicip
                        Dim webClient As New System.Net.WebClient
                        Dim monresult As String = webClient.DownloadString(monitorurl)
                        If monresult = "SUCCESS" Then
                            ''success message
                        Else
                            ''fail message

                        End If
                    Catch ex As Exception

                    End Try

                    buildcompletedlist.Items.Add(buildpendinglist.Items(i))
                    buildpendinglist.Items.Remove(buildpendinglist.Items(i))

                    buildprogresscheckactive = 0
                    BuildProgressCheck.CancelAsync()

                Catch ex As Exception

                End Try

            ElseIf jobcheckresult.Contains("<jobstatus>0</jobstatus>") Then  ''If true, job is still pending
                ''job still pending - do nothing, will check again on next pass

            ElseIf jobcheckresult.Contains("<jobstatus>2</jobstatus>") Then  ''If true, job has failed
                Try
                    Dim myCommand As New MySqlCommand
                    Dim myAdapter As New MySqlDataAdapter
                    Dim SQL As String
                    myCommand.Connection = cn
                    cn.Open()
                    myAdapter.SelectCommand = myCommand
                    SQL = "UPDATE dbcpman_jobs SET failed = 'true' WHERE jobid = '" & job_jobid & "'"
                    myCommand.CommandText = SQL
                    myCommand.ExecuteNonQuery()
                    cn.Close()

                    buildfailedlist.Items.Add(buildpendinglist.Items(i))
                    buildpendinglist.Items.Remove(buildpendinglist.Items(i))
                                        Catch ex As Exception
                    BuildProgressCheck.CancelAsync()
                    buildprogresscheckactive = 0
                End Try

            End If
        End If

    Next
    buildprogresscheckactive = 0
End Sub

1 个答案:

答案 0 :(得分:0)

基于附加文本和代码的最佳猜测如下:

  • "..checks every few seconds for new orders."
  • 错误: "This BackgroundWorker is currently busy"

因此,我相信您在Tick的{​​{1}}事件中开始异步工作。所以,让我们说你的计时器每2秒钟滴答一次。

Timer

现在,让我们假设在Friend WithEvents mytimer As New System.Windows.Forms.Timer With {.Interval = 2000, .Enabled = True} Private Sub _Tick(sender As Object, e As EventArgs) Handles mytimer.tick Me.BuildProgressCheck.RunWorkerAsync() End Sub 中执行6个刻度BuildProgressCheck_DoWork。没有错误发生,一切似乎都没问题。但是,在第7个刻度,它需要less than 2 seconds。然后,当计时器第8次加注时,3 secondsBackGroundWorker并抛出错误。

您需要做的是在运行worker之前暂停计时器,并在worker完成后恢复它。这是一个例子:

"currently busy"