none
Problem mit Synchronem Aufruf der Methoden RRS feed

  • Frage

  • Hallo Forum,

    das große Bild:
    ich möchte mehrere SQL-Server Agent-Jobs hintereinander aufrufen. Die Reihenfolge ist essentiell, da der Nachfolger auf dem Vorgänger basiert.
    Ich übertrage der Klasse eine List<string> mit Jobsnamen und arbeite sie in Schleife ab.
    Der Aufruf aus dem Hauptprogramm:

    using (SqlConnection conn = new SqlConnection(connString))
                                {
                                    List<string> jobList = new List<string>() { AdmSystemProjektStart, AdmSystemProjektEnde };
                                    Server server = new Server(new ServerConnection(conn));
                                    ExecuteSQLAgentJob aj = new ExecuteSQLAgentJob(server, jobList);
                                    aj.MainJob();
                                }

    Der Aufruf der Methode in der Sub-Klasse:

    public void MainJob()
            {
                //Enable Timer
                try
                {
                    foreach (string s in jobList)
                    {
                        SetTimer();
                        job = server.JobServer.Jobs[s]; //Get the specified job
                        StartJob();
                    }
                }
                catch (Exception ex)
                {
                    SetTimer(true);
                    //Console.WriteLine("Failed to start the job :" + ex.Message);
                    throw ex;
                }
                finally
                {
                    DestroyObjects();
                }

    und die StartJob()-Methode:

            private void StartJob()
            {
                try
                {
                    loopContinuity = false;
                    while (!loopContinuity) //Wait till the job is idle
                    {
                        job.Refresh();
                        if (job.CurrentRunStatus == JobExecutionStatus.Executing) //Check Job status and find if it’s running now
                        {
                            CurrentRunRetryAttempt++;
                            //We are not ready to fire the job
                            loopContinuity = false;
                            System.Threading.Thread.Sleep(10 * 1000); //Wait 10 secs before we proceed to check it again.
                        }
                        else
                        {
                            //We are ready to fire the job
                            loopContinuity = true; 
                            try
                            {
                                job.Start();
                                SetTimer(true);
                            }
                            catch
                            {
                                loopContinuity = false;
                                System.Threading.Thread.Sleep(10 * 1000);
                            }
                        }
                    }
                }
                catch
                {
                    throw;
                }
            }

    Ich dachte immer, die Methodenschritte werden synchron ausgeführt?
    Auf jedem Fall die beiden Jobs (nehmen sehr wenig Zeit in Anspruch) haben den gleichen TimeStamp und sozusagen der EndJob "wartet" nicht darauf, dass der "StartJob" fertig ist.
    Wie kann ich das lösen?
    vielen Dank

    P.






    • Bearbeitet Purclot Montag, 28. Januar 2013 13:30
    Montag, 28. Januar 2013 13:29

Alle Antworten

  • Es liest sich arg holprig. Und wozu der Timer??
    Montag, 28. Januar 2013 15:29
  • Hallo Stefan,

    ich räume der Methode 60 sek. Zeit (eben der Timer) ein. Wenn in dieser Zeit ein Job nicht ausgeführt werden konnte (z. B. weil != idle) wird der Timer.ElapsedEvent-Handler aktiv, setzt die bool-Laufvariabla auf true, damit die while(bool-variable) auch weiss, dass die Zeit abgelaufen ist. Dann wird die while-Schleife abgebrochen.

    P.

    Montag, 28. Januar 2013 15:43
  • Montag, 28. Januar 2013 15:46
    Beantworter
  • hallo Elmar,

    ja, ein wenig angepasst, aber kommt tatsächlich vom Codeproject.
    Ist das nicht erlaubt? Wenn ja, dann schade...

    Gruß P.

    Montag, 28. Januar 2013 15:59
  • Hallo,

    das sollte damit nicht gesagt sein.
    Die Nutzung ist im Rahmen der jeweiligen Lizenz (für oben CPOL) erlaubt.

    Ich hatte bin darüber gestolpert und hatte den Link gepostet, weil Dein Code etwas unvollständig ist.

    Da aber auch die vollständige Variante nicht gerade nach einem Optimum aussieht,
    ist mir eine vollständige Antwort nicht möglich gewesen. Selbst was Brauchbares zum Testen zusammenzustellen, dauert noch ein bissel länger.

    Gruß Elmar

    Montag, 28. Januar 2013 18:41
    Beantworter
  • Na ja, erlaubt schon. Aber dieses Stück Code ist, na ja nur 'ne Demo und nicht so toll als direkte Vorlage für 'nen Wrapper. Es sollte viel eher etwa so aussehen:

    namespace Kuthuparakkal.Util
    {
        using System.Collections.Generic;
        using System.Threading;
        using Microsoft.SqlServer.Management.Common;
        using Microsoft.SqlServer.Management.Smo;
        using Microsoft.SqlServer.Management.Smo.Agent;
    
        public class SqlJobs
        {
            private ServerConnection serverConnection;
            private Server server;
            private string sqlServerName;
    
            public SqlJobs(string sqlServerName)
            {
                this.sqlServerName = sqlServerName;
            }
    
            public void ExecuteJobs(IEnumerable<string> jobNames)
            {
                foreach (string jobName in jobNames)
                {
                    this.ExecuteJob(jobName);
                }
            }
    
            public void ExecuteJob(string jobName)
            {
                this.InitializeSmo();
                Job job = this.server.JobServer.Jobs[jobName];
                job.Start();
                job.Refresh();
                while (job.CurrentRunStatus == JobExecutionStatus.Executing)
                {
                    Thread.Sleep(10 * 1000);
                    job.Refresh();
                }
            }
    
            public void InitializeSmo()
            {
                if (this.serverConnection == null)
                {
                    this.serverConnection = new ServerConnection(this.sqlServerName);
                    this.server = new Server(this.serverConnection);
                }
            }
        }
    }

    Man muss sich halt noch schlau machen, wie und ob SMO Instance überhaupt beim Verlassen des Scopes explizit geschlossen und oderaufgeräumt werden müssen. Auf den ersten Blick nicht, da sie wohl alle nicht IDisposable implementieren.
    Montag, 28. Januar 2013 19:08
  • Hallo Purclot,

    Haben Dir die Antworten geholfen?

    Gruss,

    Ionur


    Montag, 4. Februar 2013 16:11
    Moderator