Console Application Task Scheduler

di il
12 risposte

Console Application Task Scheduler

Buon Pomeriggio a tutti,
ho creato una console application in vb.net, che cattura alcuni documenti da un server e poi li va a trasferire via ftp, sul nostro server aziendale,
fin qui tutto funziona a dovere. Senza alcun problema, ma ora viene uno dei punti più divertenti in materia, ho al necessità che questa applicazione si si avvii alle 7 del pomeriggio tutti i giorni, e dunque ho configurato il launch della console application in in modo da farlo automaticamente, a computer acceso(chiaramente) con utente admin pre-inserito. Per una settimana ha funzionato, poi ha smesso, quando guardo lo status sullo scheduler, non ci sono errori, ma quando vado a verficare l'applicazione è come se non fosse partita.

Sono dunque andato di conseguenza, a lancaire l'applicazione a mano, ed è partita con i risultati che mi aspettavo, ora dunque mi sono nate alcune domande, sbaglio io qualcosa con il task scheduler? magari è necessario integrarlo a livello di codice? come gestite questo tipo di situazioni?

12 Risposte

  • Re: Console Application Task Scheduler

    Potresti fare in modo che la tua applicazione sia in esecuzione automatica e che quando sia una certa ora effettui certe operazioni
  • Re: Console Application Task Scheduler

    Se hai usato il Task Scheduler di Windows, a mio avviso si tratta di uno strumento utile per svolgere pianificazioni semplici, ma è necessario un adeguato supporto/feedback dal punto di vista applicativo.

    Mi spiego: se il tuo programma viene lanciato a una determinata ora e, in quel momento, la connessione Internet non è disponibile, il trasferimento via FTP che auspichi di fare non verrà eseguito, a meno che lo Scheduler non venga istruito per ritentare ancora, o a meno che non sia la tua applicazione a gestire questa eventualità e comportarsi di conseguenza (ad esempio, con retry e altre operazioni simili).

    Per rendere il tutto più affidabile, io agirei come segue.

    Per iniziare, modificherei l'applicazione trasformandola in Windows Service: in questo modo, la tua applicazione può tranquillamente essere installata come servizio che gira in background e rimane pronta a svolgere il proprio compito (ossia in "idle") anche senza richiedere necessariamente il login dell'utente, che potrebbe essere una possibile causa di mancata esecuzione (se manca corrente e il PC si riavvia, senza login la tua applicazione non può essere lanciata).

    Se hai realizzato un applicazione Console, puoi utilizzare una libreria per trasformarla rapidamente in un servizio, ad esempio appoggiandoti a (vedi la documentazione della libreria per scoprire come fare).

    In secondo luogo, abbandonerei il Task Scheduler di Windows per adottare qualcosa di più "programmabile", ad esempio integrando la libreria , molto efficiente e soprattutto affidabile, in modo che il tuo servizio sempre in running in background lanci il job di trasferimento via FTP (ed eventuali altri job integrabili) quando è il momento opportuno.

    Ciao!
  • Re: Console Application Task Scheduler

    Che tip Fantastici che mi hai dato, mi metto subito sotto! ti farò sapere!
  • Re: Console Application Task Scheduler

    Mi sono ridato un po' da fare, Topshelf è stato un grandissimo consiglio, non conoscendo però c# ho difficoltà nel fare l'applicazione con quartz, infatti ho trovato solamente pochi esemp in vbi che mi permettesesro di capire come strutturarlo. Ne hai qualcuno da passare?
  • Re: Console Application Task Scheduler

    Timer86 ha scritto:


    non conoscendo però c# ho difficoltà nel fare l'applicazione con quartz, infatti ho trovato solamente pochi esemp in vbi che mi permettesesro di capire come strutturarlo. Ne hai qualcuno da passare?
    Se hai difficoltà a tradurre gli esempi, puoi aiutarti usando questo tool online creato da Telerik.

    Ciao!
  • Re: Console Application Task Scheduler

    Alka ha scritto:


    Timer86 ha scritto:


    non conoscendo però c# ho difficoltà nel fare l'applicazione con quartz, infatti ho trovato solamente pochi esemp in vbi che mi permettesesro di capire come strutturarlo. Ne hai qualcuno da passare?
    Se hai difficoltà a tradurre gli esempi, puoi aiutarti usando questo tool online creato da Telerik.

    Ciao!
    Ciao Alka, grazie mille ancora per il tuo aiuto, che è stato veramente prezioso e continua ad esserlo ancora, ho importato quartz sulla nuget, e poi successivamente mi sono andato ad inserire così topshelf e quartz.

    ho installato il servizio da command prompt, correttamente, ma lo schedule non parte mai.. ti do un esempio del codice che ho fatto, modificandolo in base alle conversioni di telerik.
    secondo quello che sono riuscito acapire dovrebbe partire, tutti i giorni, alle 11:15, negativo il servizio non è partito.
           Private Shared Sub Main3(ByVal args As String())
                Try
                    Dim schedFact As ISchedulerFactory = New StdSchedulerFactory()
                    Dim sched As IScheduler = schedFact.GetScheduler()
                    sched.Start()
                    Dim job As IJobDetail = JobBuilder.Create(Of LoggingJob)().WithIdentity("Job1", "group1").Build()
                    Dim trigger As ITrigger = TriggerBuilder.Create().WithDailyTimeIntervalSchedule(Function(s) s.WithIntervalInSeconds(10).OnEveryDay().StartingDailyAt(TimeOfDay.HourAndMinuteOfDay(11, 15))).Build()
                    sched.ScheduleJob(job, trigger)
                Catch e As ArgumentException
                    Log.[Error](e)
                End Try
            End Sub
    
        End Class
    
    
        Public Class LoggingJob
                Implements IJob
                Public Function Execute(context As IJobExecutionContext) As Task Implements IJob.Execute
                Console.WriteLine("Processo Invio")
                Common.Logging.LogManager.Adapter.GetLogger("LoggingJob").Info(String.Format("Logging job : {0} {1}, and proceeding to log", DateTime.Now.ToShortDateString(), DateTime.Now.ToLongTimeString()))
                    Main()
                End Function
    
            End Class
    
    
    
    
            Sub Main()
    
                HostFactory.Run(
                Sub(x)
                    x.Service(Of ServiceClass)(
                Sub(s)
                    s.ConstructUsing(Function(name) New ServiceClass())
                    s.WhenStarted(Sub(tc) tc.StartService())
                    s.WhenStopped(Sub(tc) tc.StopService())
                End Sub)
                    x.RunAsLocalSystem()
                    x.SetDescription("Kot FTP Application START")
                    FileProc()
                    x.SetDisplayName("KFTP Service")
                    x.SetServiceName("VBService")
    
                End Sub)
    
    
            End Sub
  • Re: Console Application Task Scheduler

    secondo quello che sono riuscito acapire dovrebbe partire, tutti i giorni, alle 11:15, negativo il servizio non è partito.
    Il codice che crea scheduler e trigger, contenuto nel metodo Main3(), viene richiamato da qualche parte?
  • Re: Console Application Task Scheduler

    Alka ha scritto:


    secondo quello che sono riuscito acapire dovrebbe partire, tutti i giorni, alle 11:15, negativo il servizio non è partito.
    Il codice che crea scheduler e trigger, contenuto nel metodo Main3(), viene richiamato da qualche parte?
    Ciao,

    hai ragione non lo richiamavo da nessuna parte, ma ricontrollando la matrice del codice ho provato a conglomerarlo in un unica pianta per eseguirlo dal mail, ma niente. .
        Sub Main()
            Try
                Dim schedFact As ISchedulerFactory = New StdSchedulerFactory()
                Dim sched As IScheduler = schedFact.GetScheduler()
                sched.Start()
                Dim job As IJobDetail = JobBuilder.Create(Of LoggingJob)().WithIdentity("Job1", "group1").Build()
                Dim trigger As ITrigger = TriggerBuilder.Create().WithDailyTimeIntervalSchedule(Function(s) s.WithIntervalInSeconds(10).OnEveryDay().StartingDailyAt(TimeOfDay.HourAndMinuteOfDay(11, 15))).Build()
                sched.ScheduleJob(job, trigger)
            Catch e As ArgumentException
                Log.[Error](e)
            End Try
    
            HostFactory.Run(
            Sub(x)
                x.Service(Of ServiceClass)(
            Sub(s)
                s.ConstructUsing(Function(name) New ServiceClass())
                s.WhenStarted(Sub(tc) tc.StartService())
                s.WhenStopped(Sub(tc) tc.StopService())
            End Sub)
                x.RunAsLocalSystem()
                x.SetDescription("Kot FTP Application START")
                ' FileProc()
                x.SetDisplayName("KFTP Service")
                x.SetServiceName("VBService")
    
            End Sub)
    
    
        End Sub
    
    ma vi evidenzia l'errore su uqesta riga.
    Dim sched As IScheduler = schedFact.GetScheduler()
  • Re: Console Application Task Scheduler

    Timer86 ha scritto:


    ma vi evidenzia l'errore su uqesta riga.
    Dim sched As IScheduler = schedFact.GetScheduler()
    Che errore ti da? Direi che si tratta di una informazione fondamentale per capire cosa è successo di sbagliato.
  • Re: Console Application Task Scheduler

    Quell'errore sono riuscito a mitigarlo, trasformando il tutto così.
    Sub Main()
            Try
                Common.Logging.LogManager.Adapter = New Common.Logging.Simple.ConsoleOutLoggerFactoryAdapter() _
                    With {.Level = Common.Logging.LogLevel.Info}
    
                ' Grab the Scheduler instance from the Factory 
                '  Dim scheduler As IScheduler = StdSchedulerFactory.GetDefaultScheduler()
                Dim scheduler As IScheduler = StdSchedulerFactory.GetDefaultScheduler().GetAwaiter().GetResult()
                'GetdeScheduler().GetAwaiter().GetResult()
                ' and start it off
                scheduler.Start()
    
                ' define the job and tie it to our HelloJob class
                Dim job As IJobDetail = JobBuilder.Create(Of LoggingJob)().WithIdentity("job1", "group1").Build()
    
                ' Trigger the job to run now, and then repeat every 10 seconds
                Dim trigger As ITrigger = TriggerBuilder.Create().WithIdentity("trigger1", "group1").StartNow().WithSimpleSchedule(Function(x) x.WithIntervalInSeconds(120).RepeatForever()).Build()
                ' Dim trigger As ITrigger = TriggerBuilder.Create().WithDailyTimeIntervalSchedule
    
                ' Tell quartz to schedule the job using our trigger
                scheduler.ScheduleJob(job, trigger)
    
                ' some sleep to show what's happening
                Thread.Sleep(TimeSpan.FromSeconds(60))
    
                ' and last shut down the scheduler when you are ready to close your program
                scheduler.Shutdown()
    
    
    
    
            Catch se As SchedulerException
                Console.WriteLine(se)
            End Try
    
            Console.WriteLine("Press any key to close the application")
            Console.ReadKey()
        End Sub
    
    
    
        Public Class LoggingJob
            Implements IJob
            Public Function Execute(context As IJobExecutionContext) As Task Implements IJob.Execute
                Console.WriteLine("Processo Invio")
                Common.Logging.LogManager.Adapter.GetLogger("LoggingJob").Info(String.Format("Logging job : {0} {1}, and proceeding to log", DateTime.Now.ToShortDateString(), DateTime.Now.ToLongTimeString()))
                HostFactory.Run(
                                 Sub(x)
                                     x.Service(Of ServiceClass)(
             Sub(s)
                 s.ConstructUsing(Function(name) New ServiceClass())
                 s.WhenStarted(Sub(tc) tc.StartService())
                 s.WhenStopped(Sub(tc) tc.StopService())
             End Sub)
                                     x.RunAsLocalSystem()
                                     x.SetDescription("Kot FTP Application START")
                                    ' FileProc()
                                    x.SetDisplayName("KFTP Service")
                                     x.SetServiceName("VBService")
    
                                 End Sub)
            End Function
    
    
        End Class
    Ora non ho errori, ovunque mi supera l'installazine, ma non vedo mai l'automazione che parte e seguendo il fatto dovrebbe partire ogni 10 secondi.
    sono andato da cmd e gli ho detto servizio e autostart -- e ha processato correttametne tutto. il probelma è che sembra non ripartire mai da solo
  • Re: Console Application Task Scheduler

    Temo ci sia parecchia confusione, perché stai lanciando il servizio (chiamando HostFactory.Run) all'interno del LoggingJob, che presumo sia il job da eseguire con Quartz.

    La procedura da seguire per inizializzare il tutto è diversa.

    Nel metodo Main() devi inizializzare entrambe le API: quella di Topshelf per agganciare la classe del tuo servizio e definire cosa fare all'avvio e all'arresto del programma.

    Ciò che deve avvenire allo "start" e "stop" del servizio sono rispettivamente la configurazione dello Scheduler di Quartz e del relativo trigger a fronte dell'avvio, mentre sull'arresto del servizio puoi inserire la chiamata per lo shutdown dello Scheduler, in modo che il job non venga più considerato (sebbene la chiusura del programma dovrebbe ottenere lo stesso effetto).

    Prima di testare il servizio, devi fare debugging in Visual Studio lanciando l'eseguibile come applicazione Console (è appunto uno dei vantaggi di usare Topshelf) e verificare che lo Scheduler sia inizializzato, che il job venga chiamato e che tutto funzioni.

    Fossi in te, procederei per step implementando le parti sopra un po' alla volta, e verificando (banalmente stampando sulla Console, in assenza di soluzioni migliori) che ogni passaggio dia il risultato sperato (prima l'esecuzione del servizio, poi la configurazione dello schedulatore, poi l'esecuzione del job e così via).

    Ciao!
  • Re: Console Application Task Scheduler

    Alka ha scritto:


    Temo ci sia parecchia confusione, perché stai lanciando il servizio (chiamando HostFactory.Run) all'interno del LoggingJob, che presumo sia il job da eseguire con Quartz.

    La procedura da seguire per inizializzare il tutto è diversa.

    Nel metodo Main() devi inizializzare entrambe le API: quella di Topshelf per agganciare la classe del tuo servizio e definire cosa fare all'avvio e all'arresto del programma.

    Ciò che deve avvenire allo "start" e "stop" del servizio sono rispettivamente la configurazione dello Scheduler di Quartz e del relativo trigger a fronte dell'avvio, mentre sull'arresto del servizio puoi inserire la chiamata per lo shutdown dello Scheduler, in modo che il job non venga più considerato (sebbene la chiusura del programma dovrebbe ottenere lo stesso effetto).

    Prima di testare il servizio, devi fare debugging in Visual Studio lanciando l'eseguibile come applicazione Console (è appunto uno dei vantaggi di usare Topshelf) e verificare che lo Scheduler sia inizializzato, che il job venga chiamato e che tutto funzioni.

    Fossi in te, procederei per step implementando le parti sopra un po' alla volta, e verificando (banalmente stampando sulla Console, in assenza di soluzioni migliori) che ogni passaggio dia il risultato sperato (prima l'esecuzione del servizio, poi la configurazione dello schedulatore, poi l'esecuzione del job e così via).

    Ciao!
    Ciao, ricapitolo un attimo.

    vediamo se ho compreso bene, IO ho una Classe chiamata Service Class che è colei che gestisce il Topshelf
    
    Imports Topshelf
    
    Public Class ServiceClass
        Public Sub StartService()
            WriteToEventLog("Service started")
        End Sub
        Public Sub StopService()
            WriteToEventLog("Service stopped")
        End Sub
    
        Private Sub WriteToEventLog(ByVal Message As String)
            Dim el As New EventLog("Application")
            el.Source = "VSS"
            Try
                FileProc()
            Catch ex As Exception
                Debug.WriteLine(ex.Message)
            End Try
        End Sub
    End Class
    
    successivamente ho un altra classe che invece "dovrebbe Gestire il Quartz"
    
        Public Class LoggingJob
            Implements IJob
            Public Function Execute(context As IJobExecutionContext) As Task Implements IJob.Execute
                Console.WriteLine("Processo Invio")
                Common.Logging.LogManager.Adapter.GetLogger("LoggingJob").Info(String.Format("Logging job : {0} {1}, and proceeding to log", DateTime.Now.ToShortDateString(), DateTime.Now.ToLongTimeString()))
    
            End Function
    
        End Class
    
    infine ho creto il main()
    dove faccio partire il Run di TopShelf e la Sub Scheduler.
    
        Sub Main()
            Try
    
                HostFactory.Run(
                                 Sub(x)
                                     x.Service(Of ServiceClass)(
             Sub(s)
                 s.ConstructUsing(Function(name) New ServiceClass())
                 s.WhenStarted(Sub(tc) tc.StartService())
    
                 s.WhenStopped(Sub(tc) tc.StopService())
                 scheduler()
    
             End Sub)
                                     x.RunAsLocalSystem()
                                     x.SetDescription("Kot FTP Application START")
                                     ' FileProc()
                                     x.SetDisplayName("KFTP Service")
                                     x.SetServiceName("VBService")
    
                                 End Sub)
    
            Catch se As SchedulerException
                Console.WriteLine(se)
            End Try
    
            Console.WriteLine("Press any key to close the application")
            Console.ReadKey()
        End Sub
    
    la sub Scheduler invece è la schedulazione
    
        Sub scheduler()
            Try
                Common.Logging.LogManager.Adapter = New Common.Logging.Simple.ConsoleOutLoggerFactoryAdapter() _
                    With {.Level = Common.Logging.LogLevel.Info}
                ' Grab the Scheduler instance from the Factory 
                '  Dim scheduler As IScheduler = StdSchedulerFactory.GetDefaultScheduler()
                Dim scheduler As IScheduler = StdSchedulerFactory.GetDefaultScheduler().GetAwaiter().GetResult()
                'GetdeScheduler().GetAwaiter().GetResult()
                ' and start it off
                scheduler.Start()
    
                ' define the job and tie it to our HelloJob class
                Dim job As IJobDetail = JobBuilder.Create(Of LoggingJob)().WithIdentity("job1", "group1").Build()
    
                ' Trigger the job to run now, and then repeat every 10 seconds
                Dim trigger As ITrigger = TriggerBuilder.Create().WithIdentity("trigger1", "group1").StartNow().WithSimpleSchedule(Function(x) x.WithIntervalInSeconds(120).RepeatForever()).Build()
                ' Dim trigger As ITrigger = TriggerBuilder.Create().WithDailyTimeIntervalSchedule
    
                ' Tell quartz to schedule the job using our trigger
                scheduler.ScheduleJob(job, trigger)
    
                ' some sleep to show what's happening
                Thread.Sleep(TimeSpan.FromSeconds(60))
    
                ' and last shut down the scheduler when you are ready to close your program
                scheduler.Shutdown()
    
            Catch se As Exception
                Console.WriteLine(se)
            End Try
        End Sub
    

    infine il famoso FileProc è il programma(che funziona)
    al lancio dell'automazione il programma funziona correttamente. non rifunziona la parte schedulata, infine quando voglio interrompere il servizio vedo che lui continua a riprocessare il programma da 0.
    Allora pensavo che l'errore fosse qui:
    
            Try
    
                HostFactory.Run(
                                 Sub(x)
                                     x.Service(Of ServiceClass)(
             Sub(s)
                 s.ConstructUsing(Function(name) New ServiceClass())
                 s.WhenStarted(Sub(tc) tc.StartService())
    
                 s.WhenStopped(Sub(tc) tc.StopService())
                 scheduler()
    
             End Sub)
    
    E ho provato a riformularla così,a mi va in overload la service class.
    
            Try
    
                HostFactory.Run(
                                 Sub(x)
                                     x.Service(Of ServiceClass)(
             Sub(s)
                 s.ConstructUsing(Function(name) New ServiceClass())
                 s.WhenStarted(Sub(tc) tc.StartService(Scheduler))
    
                 s.WhenStopped(Sub(tc) tc.StopService())
                 scheduler()
    
             End Sub)
    
    hai qualche consiglio? sfortunatamente sono impazzito quasi tutto il fine settimana sopra il codice.
Devi accedere o registrarti per scrivere nel forum
12 risposte