Quartz.NET - jak poczekać, aż zadanie się skończy

0

Witam.
Od jakiegoś czasu zacząłem używać Quartz.NET 3.0. Aktualizuje mój stary projekt do robienia kopii zapasowej baz danych i natknąłem się na problem prawdopodobnie związany z asynchronicznością.

SplashScreenManager.ShowDefaultWaitForm();
new CreateJobsSchedules().InitializeAndStartNow(_optimoJob);
SplashScreenManager.CloseDefaultWaitForm();

W usłudze nie ma problemu, ponieważ tam mnie progres nie interesuje, ale jeśli ktoś by chciał uruchomić kopie "now" z GUI to niestety mój WaitForm pojawia się i znika. Próbowałem await, próbowałem wszędzie wymusić na nim .Result, .Wait(). Niestety nic nie pomaga. Muszę użytkownikowi zablokować GUI na czas trwania zadania i poinformować go, że zadanie zostało zakończone.

    public class BackupJob : IJob
    {
        OptimoJob _databaseBackupJob;

        public async Task Execute(IJobExecutionContext context)
        {
            _databaseBackupJob = (OptimoJob)context.JobDetail.JobDataMap["jobData"];

            if (_databaseBackupJob != null)
            {
                BackupTask.DoBackup(_databaseBackupJob.SQLConfiguration);
                ZIPService.ZipBackupFiles(_databaseBackupJob.SQLConfiguration.BackupFilesSavePath);
                FTPService.SendZipFiles(_databaseBackupJob.FTPConfiguration, _databaseBackupJob.SQLConfiguration.BackupFilesSavePath);
                NotificationService.SuccessNotificationMessage(_databaseBackupJob.EmailConfiguration);
            }
        }
    }

Ja swoich metod nie robię asynchronicznych, ale Quartz tak. Jak to objeść?

0

sumie nie miałem doczynienia duzo z asynchronicznością ale w ten sposób próbowałeś

SplashScreenManager.ShowDefaultWaitForm();
await Task.Run(new CreateJobsSchedules().InitializeAndStartNow(_optimoJob))
SplashScreenManager.CloseDefaultWaitForm();
0

Poprawnie kod powinien wyglądać tak:

SplashScreenManager.ShowDefaultWaitForm();
await Task.Run( () => new CreateJobsSchedules().InitializeAndStartNow(_optimoJob));
SplashScreenManager.CloseDefaultWaitForm();

Niestety ale to samo. WaitForm pojawia się tylko na chwilę i znika.

0

CreateJobsSchedules to jest twoja klasa? Jeśli tak, pokaż kod.

0
public class CreateJobsSchedules
{
        public void InitializeAndStartNow(OptimoJob optimoJob)
        {
            ISchedulerFactory schedFact = new StdSchedulerFactory();
            IScheduler scheduler = schedFact.GetScheduler().Result;
            scheduler.Start();

            switch (optimoJob.JobType)
            {
                case JobType.BackupDatabase:
                    DatabaseBackupScheduleStartNow(optimoJob, scheduler);
                    break;
                case JobType.BackupFiles:
                    FilesBackupScheduleStartNow(optimoJob, scheduler);
                    break;
                case JobType.RestoreDatabase:
                    break;
            }
        }

        void DatabaseBackupScheduleStartNow(OptimoJob optimoJob, IScheduler scheduler)
        {
            JobDataMap jobData = new JobDataMap();
            jobData.Put("jobData", optimoJob);

            IJobDetail job = JobBuilder.Create<BackupJob>()
                .UsingJobData(jobData)
                .Build();
            ISimpleTrigger trigger = (ISimpleTrigger)TriggerBuilder.Create()
                .ForJob(job)
                .StartNow()
                .Build();

            var result = scheduler.ScheduleJob(job, trigger).Result;
        }
}
2

Nie znam tej bilbioteki, ale tak na szybko przeglądając przyklady w necie, to musisz zaimplementować Listenera - zobacz sobie przyklad w w tym linku na samym końcu prawie
https://blog.harveydelaney.com/introduction-to-quartz-net/

Zepnij to razem jakims mechanizmem synchronizacji, np ManualResetEvent i gotowe.
Możliwe że można to jakoś latwiej i szybciej zrobić, chociaż tym sposobem też nie będziesz miał wiele kodu do napisania.

1

A, że tak zapytam po co w takim razie odpalasz to przez Quartza?

0

@some_ONE:
Masz inną bibliotekę? Jedna z najpopularniejszych na nuget i tym się zasugerowałem żeby skorzystać. Nie przypuszczałem, że to będzie aż taki problem. Spróbuje jeszcze rozwiązanie @kzkzg

0

A więc temat został rozwiązany sposobem @kzkzg

private static readonly ManualResetEvent _manualEvent = new ManualResetEvent(false);

private void btnStartNow_Click(object sender, EventArgs e)
{
    splashScreenManager1.ShowWaitForm();
    Task.Factory.StartNew( () => new CreateJobsSchedules(_manualEvent).InitializeAndStartNow(_optimoJob));
    _manualEvent.WaitOne();
    splashScreenManager1.CloseWaitForm();
}

_manualResetEvent przekazuje do jobListenera

public void InitializeAndStartNow(OptimoJob optimoJob)
{
     ISchedulerFactory schedFact = new StdSchedulerFactory();
     IScheduler scheduler = schedFact.GetScheduler().Result;
     scheduler.ListenerManager.AddJobListener(new BackupListener(_manualResetEvent));
     scheduler.Start();
     switch (optimoJob.JobType)
     {
          case JobType.BackupDatabase:
               DatabaseBackupScheduleStartNow(optimoJob, scheduler);
               break;
          case JobType.BackupFiles:
               FilesBackupScheduleStartNow(optimoJob, scheduler);
               break;
          case JobType.RestoreDatabase:
               break;
     }
}

W JobWasExecuted resetuje _manualResetEvent, aby zamknąć SplashScreen.

    public class BackupListener : IJobListener
    {
        ManualResetEvent _manualResetEvent;

        public BackupListener(ManualResetEvent manualResetEvent)
        {
            _manualResetEvent = manualResetEvent;
        }

        public string Name
        {
            get { return "JobListenerName"; }
        }

        public async Task JobExecutionVetoed(IJobExecutionContext context, CancellationToken cancellationToken = default(CancellationToken))
        {
            Console.WriteLine("Vetoed");
        }

        public async Task JobToBeExecuted(IJobExecutionContext context, CancellationToken cancellationToken = default(CancellationToken))
        {
            Console.WriteLine("To be executed");
        }

        public async Task JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException, CancellationToken cancellationToken = default(CancellationToken))
        {
            Console.WriteLine("Executed");
            _manualResetEvent.Set();
        }
    }

Trochę to takie przekombinowane, ale działa.

0
AdamWox napisał(a):

@some_ONE:
Masz inną bibliotekę? Jedna z najpopularniejszych na nuget i tym się zasugerowałem żeby skorzystać. Nie przypuszczałem, że to będzie aż taki problem. Spróbuje jeszcze rozwiązanie @kzkzg

Nie chodzi o to.
Chodzi o to, że chcesz za pomocą schedulera stworzyć silnik gry.
Po prostu quartz nie jest stworzony do tego typu zadań.
Quartz.NET is a full-featured, open source** job scheduling system** that can be used from smallest apps to large scale enterprise systems.

A job scheduler is a computer application for controlling unattended background program execution of jobs
https://en.wikipedia.org/wiki/Job_scheduler (czytałem tylko pierwsze zdanie)

Jak chcesz to obejść to zrób po prostu event.

0

Ja tworzę silnik gry za pomocą schedulera? Gdzie tak napisałem? Scheduler jest mi potrzebny do usługi jaka działa w tle, a że aplikacja, którą tę usługę konfiguruje ma opcję "Wykonaj teraz" to po co miałem robić osobno, kolejną metodę, skoro mogę wywołać scheduler jego metodą StartNow().

1

Zawsze możesz też logikę z Joba wynieść do innej klasy i jak chcesz coś schedulować to robisz to za pomocą Quartza, a jak chcesz wykonać natychmiast to po prostu wołasz tę klasę.

1 użytkowników online, w tym zalogowanych: 0, gości: 1