اجرای وظایف زمان بندی شده با Quartz.NET - قسمت دوم
اندازه‌ی قلم متن
تخمین مدت زمان مطالعه‌ی مطلب: پنج دقیقه

در این قسمت، نحوه‌ی استفاده از قابلیت‌های کتابخانه‌ی Quartz.NET را در قالب پرسش و پاسخ ادامه می‌دهیم.

ابتدا یک توضیح کلی:
برای مدیریت وظیفه‌ها در Quartz.NET، در هر جای پروژه می‌توانید به صورت ذیل به مدیر وظیفه‌ها دسترسی داشته باشید.
var scheduler = new StdSchedulerFactory().GetScheduler();
از حالا به بعد، هر جا که در کدها کلمه‌ی scheduler را دیدید، ایجاد آن از طریق خط قبل بوده است.
سعی کنید همیشه هنگام ایجاد اشیا از نوع IJobDetail و ITrigger، از متد WithIdentity (همان طور که در قسمت قبل مشاهده کردید) برای نامگذاری وظایف و triggerها استفاده کنید تا بتوانید بعداً با استفاده از نامشان به آنها ارجاع پیدا کرده و مدیریتشان کنید

1) سوال: چگونه می‌توان در یک زمان دلخواه (مثلاً در زمان کلیک بر روی یک دکمه)، اجرای یک وظیفه را متوقف کرد؟
جواب: برای توقف تمامی وظایف می‌توان از متد ()Shutdown شی scheduler استفاده کرد:
scheduler.Shutdown(true);
در صورتی که مقدار true را به متد Shutdown پاس دهید، تا زمانی که وظایفی که در وسط اجرای خود هستند کارشان به پایان نرسد، کنترل اجرای برنامه به خط بعد نمی‌رود، اما در صورتی که این متد را بدون پارامتر فراخوانی کنید یا مقدار false را به آن پاس دهید، کنترل اجرای برنامه به دستور بعد می‌رود و وظایف در پشت صحنه به کار خود ادامه می‌دهند. دقت داشته باشید که منظور از ادامه‌ی کار یک وظیفه، ادامه‌ی کار آن در وضعیت جاری خود است. به بیان واضح تر، اگر مرتبه‌ی اجرای یک وظیفه 20 مرتبه بود و در مرتبه‌ی دوم اجرای آن، متد ()Shutdown به هر صورتی فراخوانی شد، مرتبه‌های دیگر به هیچ وجه اجرا نمی‌شوند.
اگر چند وظیفه به طور همزمان در حال اجرا باشند و قصد داشته باشید تا یکی از آنها را متوقف کنید، یکی از دو حالت زیر وجود دارد:
1)  یک وظیفه به چند trigger نسبت داده شده است.
2)  هر وظیفه فقط یک trigger دارد.
در صورتی که قصد دارید وظیفه از تمامی triggerها گرفته شود (معمولاً هم همین رفتار مد نظر است)، از متد DeleteJob استفاده کنید؛ و اگر قصد دارید تا اجرای وظیفه توسط یک trigger مشخص لغو شود و triggerهای دیگر مختص آن وظیفه به کار خود ادامه دهند، از متد UnscheduleJob استفاده کنید. اگر از متد DeleteJob استفاده می‌کنید، نام وظیفه را با ایجاد نمونه ای از کلاس JobKey برای آن مشخص کنید و در صورتی که از متد UnscheduleJob استفاده می‌کنید، نام trigger را با ایجاد نمونه ای از کلاس TriggerKey تعیین کنید.
scheduler.DeleteJob(new JobKey("job1"));
// or
scheduler.UnscheduleJob(new TriggerKey("trigger1"));

2) سوال: چگونه می‌توان اجرای وظیفه‌ها را به حالت تعلیق در آورد؟
جواب: برای به تعلیق در آوردن اجرای تمامی وظایف، از متد ()StandBy استفاده کنید:
scheduler.Standby();
برای ادامه‌ی کار، متد ()Start را مجدداً فراخوانی کنید.
در صورتی که قصد دارید اجرای وظیفه ای خاص را به حالت تعلیق در آورید، از متد ()PauseJob استفاده کنید. نام وظیفه را با ایجاد نمونه ای از کلاس JobKey برای آن مشخص کنید:
scheduler.PauseJob(new JobKey("job1"));
برای ادامه‌ی وظیفه، از متد ()ResumeJob استفاده کنید. نام وظیفه را با ایجاد نمونه ای از کلاس JobKey برای آن مشخص کنید:
scheduler.ResumeJob(new JobKey("job1"));
برای تعلیق اجرای تمامی وظایف، متد ()PauseAll، و برای ادامه‌ی کار تمامی وظایف، متد ()ResumeAll را فراخوانی کنید.

3) سوال: چگونه می‌توان یک وظیفه‌ی در حال اجرا را آپدیت کرد و تغییر مشخصات داد؟
جواب: با استفاده از متد AddJob و تنظیم پارامتر دوم آن به مقدار true:
IJobDetail job = JobBuilder.Create<NewJob>()
                             .WithIdentity("job1")
                             .Build();

scheduler.AddJob(job, true);

اگر قبلاً کلاسی با عنوان OldJob برای وظیفه ای با نام job1 تعریف شده است، با استفاده از قطعه کد بالا می‌توان کلاس NewJob را به جای آن معرفی کرد. البته به شرطی که نام وظیفه‌ی جدید با نام وظیفه‌ی قدیم، یکسان باشد. پارامتر دوم متد AddJob مشخص می‌کند که آیا در صورتی که نام وظیفه ای که قرار است در فرایند زمانبندی قرار بگیرد با نام یکی از وظایف موجود یکسان باشد، وظیفه‌ی جدید، جایگزین وظیفه‌ی قدیم شود یا خیر.

4) سوال: چگونه می‌توان یک trigger در حال اجرا را آپدیت کرد و تغییر مشخصات داد؟
جواب: یک trigger جدید ایجاد و با استفاده از متد ()RescheduleJob، جایگزین trigger قدیمی کنید:
ITrigger trigger = TriggerBuilder.Create()
                                 .WithIdentity("newTrigger")
                                 .StartNow()
                                 .ForJob("job1")
                                 .WithSimpleSchedule(x => x.WithIntervalInSeconds(5).WithRepeatCount(20))
                                 .Build();

scheduler.RescheduleJob(new TriggerKey("oldTrigger"), trigger);

نام trigger جدید می‌تواند با نام trigger قدیم یکسان باشد. در تکه کد قبل، triggerیی با نام newTrigger ایجاد و زمان اجرای آن به حال تنظیم شده است. با استفاده از متد ()ForJob و تعیین نام وظیفه، trigger جدید را به وظیفه ای با نام job1 نسبت داده ایم. بازه‌ی زمانی اجرا، هر 5 ثانیه و 21 مرتبه خواهد بود. در متد ()RescheduleJob و در پارامتر اول آن، نام trigger قدیمی را با ایجاد شی ای از کلاس TriggerKey مشخص کرده ایم و به پارامتر دوم، شی ایجاد شده برای trigger جدید را پاس داده ایم.

5) سوال: چگونه می‌توان تعداد دفعات اجرای یک وظیفه را بی نهایت تعیین کرد؟
پاسخ: با استفاده از متد ()RepeatForever در هنگام ایجاد trigger:
ITrigger trigger = TriggerBuilder.Create()
                                 .WithIdentity("trigger1")
                                 .StartAt(startTime)
                                 .ForJob("job1")
                                 .WithSimpleSchedule(x => x.WithIntervalInSeconds(5).RepeatForever())
                                 .Build();

6) سوال: چگونه می‌توان تعداد دفعات اجرای تمامی وظایف را به دست آورد؟
پاسخ: با استفاده از متد ()GetMetaData:
SchedulerMetaData metaData = scheduler.GetMetaData();

int numberOfJobsExecuted = metaData.NumberOfJobsExecuted;
متد ()GetMetaData، اطلاعاتی در مورد مدیر وظایف می‌دهد. نوع برگشتی این متد، SchedulerMetaData است. یکی از خصیصه‌های این نوع، NumberOfJobsExecuted نام دارد که تعداد دفعات اجرای تمامی وظایف تا زمان حال را برگشت می‌دهد.

7) سوال: چگونه می‌توان زمان آغاز به کار مدیر زمانبندی را متوجه شد؟
پاسخ: یکی دیگر از خصیصه‌های نوع RunningSince ،SchedulerMetaData نام دارد که بدین منظور استفاده می‌شود.
SchedulerMetaData metaData = scheduler.GetMetaData();

DateTimeOffset? runningSince = metaData.RunningSince;

ادامه دارد...
  • #
    ‫۱۲ سال و ۲ ماه قبل، جمعه ۲۷ مرداد ۱۳۹۱، ساعت ۱۵:۰۸
    آقای راد خیلی ممنون از مطلب مفیدتون. اگر بخواهیم مثلاً یک قسمت از UI رو هر چند دقیقه آپدیت کنیم، نحوه انجام ای کار به چه صورتی خواهد بود؟
    • #
      ‫۱۲ سال و ۲ ماه قبل، جمعه ۲۷ مرداد ۱۳۹۱، ساعت ۱۷:۴۹
      البته نگفتید که منظورتون desktop یا وب هست، با این فرض که در مورد desktop می‌پرسید، یکی از روش‌ها اینه که یک متغیر عمومی تعریف کنید که ارجاعی به فرمی که قرار هست آپدیت باشه داشته باشه:
      using System.Windows.Forms;
      
      public static class GlobalData
      {
          public static Form ScheduleForm { get; set; }
      }
      در سازنده‌ی فرم می‌تونید اون رو به فرم جاری مقداردهی کنید:
      GlobalData.ScheduleForm = this;
      با این فرض که قرار هست عنوان یک دکمه در فرم با نام myButton به My Text تغییر کنه، کلاس پیاده ساز اینترفیس IJob به صورت زیر خواهد بود.
      namespace SchedulerDemo.Jobs
      {
          using System.Linq;
          using System.Windows.Forms;
          using Quartz;
      
          public class HelloJob : IJob
          {
              private delegate void ButtonTextWriter(string buttonId, string text);
              
              MainForm form = GlobalData.ScheduleForm as MainForm;
      
              private void SetButtonText(string buttonId, string text)
              {
                  (form.Controls.Find(buttonId, true).FirstOrDefault() as Button).Text = text;
              }
      
              public void Execute(IJobExecutionContext context)
              {
                  form.BeginInvoke(new ButtonTextWriter(SetButtonText), new object[] { "myButton", "My Text" });
              }
          }
      }

  • #
    ‫۱۲ سال و ۱ ماه قبل، سه‌شنبه ۱۴ شهریور ۱۳۹۱، ساعت ۰۰:۳۱
    سلام ... اگر دیده باشید سرویس‌های بلاگ نویسی سرویسی دارن که تو اون میشه یه پستو تایم ارسال بهش داد و در اون روز و ساعت پست تو وبلاگ نمایش داده میشه ... حالا آیا با Quartz.net میشه این کارو کرد؟ (تو asp.net mvc) ... اگه بشه فکر میکنم اگه راجع به این قضیه پستی بزنین خیلی خوب میشه :دی ... ممنون ...
    • #
      ‫۱۲ سال و ۱ ماه قبل، سه‌شنبه ۱۴ شهریور ۱۳۹۱، ساعت ۰۰:۴۱
      این کار ارتباطی با کتابخانه‌های زمانبندی نداره. اونها پست‌ها رو بر اساس تاریخ و ساعت نشون میدن => پست هایی که تاریخ نمایش اونها از زمان جاری قدیمی‌تر هست نشون داده میشن و پست هایی که تاریخ نمایش اونها از تاریخ جاری جدیدتر هست نشون داده نمیشن.
      • #
        ‫۱۲ سال و ۱ ماه قبل، سه‌شنبه ۱۴ شهریور ۱۳۹۱، ساعت ۰۵:۰۷
        در تاریخ و زمان مشخصی نمایش داده میشن بدون اینکه ادمین وبلاگ به وبلاگش سر بزنه پست در اون زمان مشخص شده در ویلاگ قرار میگیره و همگان اونو میبینن! ... این زمان بندی نیست الان؟! ... یا مثال دیگه : سیستم‌های یادآور یا ToDo که با توجه به زمان و ایمیلی که مشخص کردین براتون میلو ارسال میکنن (اینا منظورم بود :دی )
        • #
          ‫۱۲ سال و ۱ ماه قبل، سه‌شنبه ۱۴ شهریور ۱۳۹۱، ساعت ۰۵:۲۲
          همانطور که عنوان شد طراحی دیتابیس است نه استفاده از ابزارهای جانبی. یک وبلاگ در این حالت شبیه به کوئری زیر کار می‌کند (هر فراخوانی صفحه‌ای معادل است با یک کوئری از بانک اطلاعاتی):
          select * from tblPosts where (showDate is null) or (showDate<=getdate())
          فیلد showDate اگر نال بود، یعنی یک مطلب معمولی است که درجا نمایش پیدا می‌کند. اگر تاریخی برای آن مشخص شده بود، بر اساس تاریخ جاری یک مقایسه صورت گرفته و رکوردها انتخاب و نمایش داده می‌شوند.
          • #
            ‫۱۲ سال و ۱ ماه قبل، سه‌شنبه ۱۴ شهریور ۱۳۹۱، ساعت ۰۵:۲۸
            ممنون ... ولی بنده منظورم این نبود که الگوریتمش چجوریه! ... منظورم این بود که چیکار کنیم که پشت پرده و بدون این که توسط کاربر Request به پیجی داشته باشیم این کار انجام بشه! ... تو Application_start باید این کارو کرد؟! ... اگه آره چجوری؟
            • #
              ‫۱۲ سال و ۱ ماه قبل، سه‌شنبه ۱۴ شهریور ۱۳۹۱، ساعت ۰۵:۳۴
              سؤال شما این بود: «... تو وبلاگ نمایش داده میشه ...» این یعنی ارسال یک کوئری به بانک اطلاعاتی و دریافت پاسخ.  
              و چرا پشت پرده باید انجام بشه؟ یک وبلاگ بر اساس درخواست یک کاربر هست که صفحاتش نمایش داده میشه. یعنی همون کوئری فوق.

              • #
                ‫۱۲ سال و ۱ ماه قبل، سه‌شنبه ۱۴ شهریور ۱۳۹۱، ساعت ۰۵:۴۰
                کاربر میگه که میخوام 4 ساعت دیگه نمایش بدی! ... یعنی 4 ساعت دیگه باید این Task انجام بشه! ... حالا شما فکر کنین هزار تا کاربر داریم! هر کدوم یه تایمی رو در آینده میدن که پستشون به بازدیدکنندگان ویلاگشون نمایش داده بشه! ... خوب الان یه جورایی ما تو برناممون یه ترد بینهایت میخوایم که به لیست Task‌ها در زمان‌های مشخص شده رسیدگی کنه! ... بدون این که دیگه کاربر دخالتی داشته باشه! و همیشه هم این ترد باید کار کنه! ... پس اینجوری باید این ترد تو Application_start تنظیم بشه و تا وقتی سرور روشنه این کارارو انجام بده! ... اگه درست نمیگم تصحیح کنید!
                • #
                  ‫۱۲ سال و ۱ ماه قبل، سه‌شنبه ۱۴ شهریور ۱۳۹۱، ساعت ۰۵:۴۵
                  ما داریم در مورد یک وبلاگ بحث می‌کنیم. task نمایش در اینجا یعنی باز کردن یک صفحه توسط کاربر نهایی. در این حالت ابتدا یک کوئری به بانک اطلاعاتی ارسال شده و بر اساس فیلد showDate که پیشتر توسط نویسنده‌ها تنظیم شده (یا خیر ... حالت اختیاری)، اطلاعات نمایش خواهند یافت.
                  نیازی به ترد اضافی نیست. نیازی به ابزار زمانبندی نیست.  فقط یک کوئری ساده روی فیلد showDate یک رکورد موجود است.
                • #
                  ‫۱۲ سال و ۱ ماه قبل، جمعه ۳۱ شهریور ۱۳۹۱، ساعت ۲۳:۴۶
                  دوست عزیز برنامه‌های زمان بندی ابزاری بسیار زیبا و مفید هستند در صورتی که در مکان و زمان مناسب از آنها بهره ببریم.
                  جهت انجام این کار بسیار ساده ای که مد نظر شماست، ایجاد یک Task به مانند پیچاندن لقمه دور سر است.
                  این کاری که شما مثال زدید رو جناب نصیری خیلی روان و ساده توضیح دادند. هیچ کار اضافی هم نیاز نیست. تنها یک کوئری هست 
                  موفق باشید :)
  • #
    ‫۱۱ سال و ۱۰ ماه قبل، یکشنبه ۵ آذر ۱۳۹۱، ساعت ۰۴:۴۴
    با سلام
    ممنون بابت راهنمایی‌های اقای راد.
    اقای راد در مورد پست اول خودتون اومدید یه کلاس نوشتید و در پست دوم در مورد dll توضیح دادین.
    اگر ممکن یه سمل بزارین
    • #
      ‫۱۱ سال و ۱۰ ماه قبل، یکشنبه ۵ آذر ۱۳۹۱، ساعت ۱۳:۵۴
      در پست اول، گام به گام، کدهای یک مثال توضیح داده شده. شما فقط Copy & Paste کنید.
  • #
    ‫۱۱ سال و ۱۰ ماه قبل، یکشنبه ۵ آذر ۱۳۹۱، ساعت ۲۳:۲۳
    ممنون از مقالتون

    فقط یه سوالی که برام پیش اومده ,اینه که ایا این کتابخانه از چند نخی برای اجرای کارها استفاده می‌کنه ؟
    • #
      ‫۱۱ سال و ۱۰ ماه قبل، دوشنبه ۶ آذر ۱۳۹۱، ساعت ۱۰:۴۱
      این کتابخانه، متن باز هست. می‌تونید کدهاش رو بررسی کنید.
      • #
        ‫۱۱ سال و ۹ ماه قبل، شنبه ۱۶ دی ۱۳۹۱، ساعت ۲۰:۵۰
        با سلام
        اگر میشه سمپلی بزارید .

  • #
    ‫۱۱ سال و ۹ ماه قبل، جمعه ۲۹ دی ۱۳۹۱، ساعت ۱۳:۱۱
    سلام.
     من توی برنامم از این کتابخانه استفاده کردم و به صورت تستی گذاشتم که هر یک دقیقه یک کار خاصی رو انجام بده. ولی یک مشکلی که دارم اینه که وقتی برنامه رو می‌بندم به طور کامل از برنامه خارج نمیشه و هنوز پشت صحنه عمل مربوطه رو انجام میده و بایستی دکمه Stop رو بزنم تا اجراش متوقف بشه.
    میخواستم بدونم راه گرفتن یک Scheduler خاص چیست و چطور باید Shutdown اش کرد؟
    ممنون.
    • #
      ‫۱۱ سال و ۹ ماه قبل، جمعه ۲۹ دی ۱۳۹۱، ساعت ۱۴:۲۱
      چون Threadیی که ایجاد میشه، اصطلاحاً Foreground هست و باید به Background تبدیل بشه.
      جزئیات بیشتر...
      در ضمن توجه داشته باشید که اگر در وسط اجرای یک فرایند اون رو به زور متوقف کنید، مشکل هرز رفتن منابع رو خواهید داشت. در نظر بگیرید که فایلی رو باز کردید و قصد نوشتن در اون رو دارید، در همین هنگام پروسه رو قطع می‌کنید. فایل باز می‌مونه و پروسس‌های دیگه نمی‌تونن به اون دسترسی داشته باشن. به نظر من بهتره رفتار پیش فرض Quartz.NET رو تغییر ندید و بر روی منطق برنامه‌ی خودتون معطوف باشید.
  • #
    ‫۱۱ سال و ۸ ماه قبل، چهارشنبه ۱۸ بهمن ۱۳۹۱، ساعت ۰۱:۳۷

    با سلام؛ صرف نظر از اینکه ما کدهای زمانبندی رو چطور می‌نویسیم یا از چه کتابخانه‌ها و روش هایی استفاده می‌کنیم، برای پیاده سازی برنامه ای  هیچ قسمت یوزر اینترفیس ای ندارد (همانند وبلاگ‌ها یا برنامه های تیکتینگ) و صرفا اطلاعاتی را از دیتایبس (موجود) فراخوانی و عملیاتی روی آنها انجام می‌هد، (مثلا ارسال ایمیل یا پیامک)، از چه نوع application ای استفاده کنیم؟ (webapp - winapp - winservice).  

    من برای انجام اینکار از winapp استفاده نمی‌کنم چون نمی‌خواهم یک برنامه را روی ویندوز اجرا کنم. همچنین از webapp استفاده نمی‌کنم بنا به دلایلی خاص.  در حال حاظر از windows service‌ها استفاده می‌کنم.  آیا راه حل مناسب‌تری وجود دارد؟

    با تشکر از شما

    • #
      ‫۱۱ سال و ۸ ماه قبل، چهارشنبه ۱۸ بهمن ۱۳۹۱، ساعت ۰۲:۴۳
      سرور متعلق به خودتون است؟ دسترسی بالایی دارید مثل دسترسی نصب و همچنین دسترسی اجرای برنامه به صورت سرویس؟ اگر بله، استفاده از سرویس‌های ویندوز nt روش متداولی است. اگر نه، برنامه‌های وب با حداقل دسترسی همین کار رو می‌تونند انجام بدن.
      • #
        ‫۱۱ سال و ۸ ماه قبل، چهارشنبه ۱۸ بهمن ۱۳۹۱، ساعت ۱۴:۱۶

        ممنون از شما آقا سعید

        بله در بعضی موارد سرور می‌تواند از خود من باشد و در بعضی موارد دسترسی ریموت برای نصب و کنترل سرویس را دارم.

        درمورد برنامه‌های وب برای این کار : من یکبار این کار را انجام دادم و از cache expiration استفاده کردم. ولی چون این برنامه‌ی وب هیچ request ای نداشت برنامه down شد و عملیات زمان بندی متوقف شد.

        پس میشه گفت استفاده از سرویس‌های ویندوزی، راه حل متداولی هست؟

        • #
          ‫۱۱ سال و ۸ ماه قبل، چهارشنبه ۱۸ بهمن ۱۳۹۱، ساعت ۱۴:۲۳

          - تولید درخواست به یک سایت کار سختی نیست. از این سرویس‌هایی که مدام سایت رو ping می‌کنند زیاد هست. مثل سرویس‌های فید خوان. مثل سایت‌هایی که بررسی می‌کنند سایت شما آپ است یا داون.

          - نه الزاما. سرویس task scheduler ویندوز همیشه در حال اجرا است؛ دقیق و منظم. این سرویس می‌تونه خیلی راحت یک فایل exe معمولی یا حتی یک فایل bat رو در زمان‌های مشخصی اجرا کنه. برای کارهای مدیریت سیستم زیاد ازش استفاده می‌شه.

  • #
    ‫۱۱ سال و ۲ ماه قبل، سه‌شنبه ۲۲ مرداد ۱۳۹۲، ساعت ۱۴:۵۹
    با سلام؛ در قسمت تبلیغات سایتی کاربر بازه نمایش تبلیغ خود را وارد می‌کنه و من در مدیریت تائید می‌کنم در زمان تائید در قسمت تبلیغات نامه ای برای ایشان ارسال می‌کنم که از این تاریخ تبلیغ شما نمایش داده می‌شود
    مشکل من در اینجاست که می‌خواهم در زمان خاتمه تاریخ تبلیغ هم نامه ای برای شخص ارسال شود و به ایشان اطلاع داده شود که تبلیغ پایان یافته است. 
    راه حلی که من برای آن در نظر گرفته بودم این است که در زمان تائید اولیه تبلیغ با کوارتز یک Job درست کنم و با futuredate از وی بخواهم در روز اتمام تبلیغ ایمیل بزند
    سوال من این است که :
    1- آیا فعال بودن یک job آن هم در بازه هایی مانند 6 ماه یا بیشتر به تعداد بالا سرعت سرور را کاهش نمی‌دهد؟
    2- از آنجا که تبلیغ‌ها با هم متفاوت است و به فراخور آن نامه‌های ارسالی متفاوت است چگونه می‌توانم به ازای هر تبلیغ به صورت داینامیک Job مربوطه را تخصیص دهم یعنی آن که دستی with identity نزنم(هارد کد نزنم)
    پیشاپیش سپاسگزارم
    • #
      ‫۱۱ سال و ۲ ماه قبل، سه‌شنبه ۲۲ مرداد ۱۳۹۲، ساعت ۱۵:۱۶

      نیازی نیست به ازای هر تبلیغ یک جاب درست کنید. کلا یک جاب درست کنید که مثلا هر 5 دقیقه یکبار از دیتابیس کوئری بگیره. مواردی رو که منقضی شده (مقایسه تاریخ سرور با تاریخ فیلد انقضاء تبلیغ) پیدا کنه و براشون ایمیل ارسال کنه. به این صورت سربار خیلی خیلی کمی خواهید داشت.

  • #
    ‫۱۰ سال و ۸ ماه قبل، چهارشنبه ۲ بهمن ۱۳۹۲، ساعت ۱۳:۲۴
    سلام من تازه برنامه نویسی asp رو شروع کردم. در سایتی که در حال طراحی آن هستم یک مدیر سیستم دارم و یک سری مشتری که هرکدام نام کاربری و پسورد خودشان را دارند. می‌خواهم برنامه ام به گونه ای باشد که هرروز به طور خودکار بررسی کند اگر تولد یک مشتری است به او اس ام اس دهد یا اگر قرارداد مشتری در حال اتمام است به او اس ام اس دهد و به اطلاعش برساند. من برای این کار یک برنامه کوارتز نوشته ام ولی مشکلی که دارم این است که نمی‌دونم این برنامه را از کجا صدا بزنم. نمی‌تونم هر مشتری که لاگین می‌شود این برنامه رو صدا بزنم. چون ممکن است در طول روز مشتری چندین دفعه لاگین شود. می‌خواهم به گونه ای باشد که دفعه اول که مدیر سیستم وارد سایت شد همون بار اول جاب فراخوانی شود و تا بی نهایت ادامه یابد.جاب را به گونه ای تنظیم کرده ام که روزی یک بار اجرا می‌شود. اگر جاب را همون دفعه اولی که مدیر سیستم وارد می‌شود صدا بزنم درست است؟ بعد از اینکه مدیر سیستم صفحه اش را می‌بندد اجرای برنامه متوقف می‌شود یا ادامه می‌یابد؟
    • #
      ‫۱۰ سال و ۸ ماه قبل، چهارشنبه ۲ بهمن ۱۳۹۲، ساعت ۱۳:۳۲
      در نظرات قسمت اول بهش اشاره شده. این کدها باید در Application_Start فایل global.asax.cs فراخوانی شوند.
      • #
        ‫۱۰ سال و ۸ ماه قبل، چهارشنبه ۲ بهمن ۱۳۹۲، ساعت ۱۴:۴۹
        با تشکر ولی این فایل ISchedule را نمی‌شناسد!؟
        • #
          ‫۱۰ سال و ۸ ماه قبل، چهارشنبه ۲ بهمن ۱۳۹۲، ساعت ۱۴:۵۹
          دومین قطعه کدی که در مقاله‌ی قسمت اول معرفی شده تعریف اینترفیس ISchedule است. قطعه کد اول HelloJob هست از بالا و قطعه کد بعدی ISchedule.
          • #
            ‫۱۰ سال و ۸ ماه قبل، چهارشنبه ۲ بهمن ۱۳۹۲، ساعت ۱۵:۰۴
            من کلاس ISchedule رو تعریف کردم. برای تعریف global روی نام پروژه راست کلیک کردم و add neww item را انتخاب کردم و از آنجا global را انتخاب کرده ام . آیا این روش درست است؟
             <%@ Application Language="C#" %>
            <script runat="server">
            void Application_Start(object sender, EventArgs e)
            {
            }
            </script>
            • #
              ‫۱۰ سال و ۸ ماه قبل، چهارشنبه ۲ بهمن ۱۳۹۲، ساعت ۱۵:۱۰
              همانطور که قبلا عنوان شد، تعاریف myTask.Run را در Application_Start قرار بدید.
  • #
    ‫۱۰ سال و ۷ ماه قبل، جمعه ۲ اسفند ۱۳۹۲، ساعت ۲۳:۰۱
    با سلام؛ اگه می‌توانید یک مثال از Listener بگذارید ممنون می‌شوم. به این صورت که چک کند اگر کار قبلی در حال اجرا هست دیگر اجرا نشود و اگر کار به اتمام رسیده بود شروع به اجرای تابع مورد نظر کند.
    • #
      ‫۱۰ سال و ۷ ماه قبل، شنبه ۳ اسفند ۱۳۹۲، ساعت ۰۱:۰۹
      متد GetCurrentlyExecutingJobs لیست jobهای موازی در حال اجرا را می‌دهد:
      var jobs = scheduler.GetCurrentlyExecutingJobs();
      از نتیجه‌ی آن برای تصمیم گیری استفاده کنید؛ مثلا اگر این لیست خالی یا نال بود آنگاه job جاری اجرا شود.
      • #
        ‫۱۰ سال و ۷ ماه قبل، شنبه ۳ اسفند ۱۳۹۲، ساعت ۰۱:۱۷
        ممنون
        IJobListener  رو پیاده کردم. یک متد داره به نام JobWasExecuted
        در ابتدا یک متغییر استاتیک بولین تعریف کردم. وقتی تابع اجرا میشه یک میشود. و در 
        JobWasExecuted  اون متغییر رو 0 میکنم. تو تست خوب جواب داد. کاملا درست کار میکنه وقتی کار اتمام پیدا کنه اجرا میشه
        • #
          ‫۱۰ سال و ۷ ماه قبل، شنبه ۳ اسفند ۱۳۹۲، ساعت ۰۱:۳۰
          روش دیگر استفاده از MergedJobDataMap هست برای اشتراک گذاری داده‌ها در context آن.
      • #
        ‫۱۰ سال و ۷ ماه قبل، شنبه ۳ اسفند ۱۳۹۲، ساعت ۰۱:۳۸
        با تابع GetCurrentlyExecutingJobs() هم انجام شد پیاده سازیش هم راحتره ممنون.
  • #
    ‫۱۰ سال و ۷ ماه قبل، دوشنبه ۱۹ اسفند ۱۳۹۲، ساعت ۱۶:۳۸
    سلام من در برنامم برای ارسال اس ام اس از کوارتز استفاده کردم درست هم کار میکنه ولی مشکلی که داره اینه که می‌خوام روزی یکبار عمل ارسال اس ام اس انجام بشه بنابراین trigger را به صورت زیر تعریف کرده ام.
     ITrigger trigger = TriggerBuilder.Create().WithIdentity("trigger1").StartAt(starttime).WithSimpleSchedule(x => x.WithIntervalInHours(24).RepeatForever()).Build ();
    ولی انگار که این کد کار نمی‌کنه چون تقریبا ساعتی دو بار داره اس ام اس رو میفرسته لطفا راهنمایی ام کنید که مشکل چیه ؟ در ضمن ارسال اس ام اس در قسمت application_start به صورت زیر تعریف شده
       double h = DateTime.Now.Hour;
      h += 7.5;
      if (h >= 8)
      {
    SchedulerDemo.Interfaces.ISchedule mytask = new SchedulerDemo.Jobs.Sendschedule();
    mytask.run();
      }
    اضافه کردن 7.5 به ساعت سیستم به دلیل این است که مطابق با ساعت ایران شود. با تشکر
    • #
      ‫۱۰ سال و ۷ ماه قبل، دوشنبه ۱۹ اسفند ۱۳۹۲، ساعت ۱۷:۰۲
      در متد application_start لاگ کنید برنامه در چه زمان‌هایی ری‌استارت شده.
      • #
        ‫۱۰ سال و ۷ ماه قبل، دوشنبه ۱۹ اسفند ۱۳۹۲، ساعت ۱۷:۳۶
        ببخشید من درست متوجه منظورتون نشدم. لاگ سایت را از سرور گرفتم ولی چیزی ازش متوجه نشدم. آیا منظوظرتون این لاگه ؟ میشه بیشتر توضیح بدید ممنون
        • #
          ‫۱۰ سال و ۷ ماه قبل، دوشنبه ۱۹ اسفند ۱۳۹۲، ساعت ۱۷:۳۹
          در یک فایل متنی ساده ثبت کنید، متد application_start چندبار در طول روز فراخوانی شده یا حتی در طول یک ساعت (هر بار که این متد فراخوانی می‌شود، جایی آن‌را ثبت کنید). استفاده از ELMAH هم برای اینکار مفید است. ممکن است برنامه بیش از حد ری‌استارت می‌شود.
          • #
            ‫۱۰ سال و ۷ ماه قبل، چهارشنبه ۲۱ اسفند ۱۳۹۲، ساعت ۱۳:۲۵
            سلام من این کارو انجام دادم متد application_start  مرتب ری استارت میشه تقریبا هر 20 دقیقه یه بار. سرور ما یک هاست اشتراکی است. میشه لطفا راهنمایی کنید که مشکل چی می‌تونه باشه؟
            • #
              ‫۱۰ سال و ۷ ماه قبل، چهارشنبه ۲۱ اسفند ۱۳۹۲، ساعت ۱۳:۳۷
              - نکات مطلب «چه زمان‌هایی یک برنامه‌ی ASP.NET ری استارت می‌شود؟» را بررسی کنید.
              - همچنین اگر هاست نامبرده تمام سایت‌ها را با یک Application pool مدیریت می‌کند، کرش یکی از چند ده سایت دیگر می‌تواند سبب ری‌استارت شدن سایت شما هم بشود؛ چون برنامه‌ها از همه ایزوله نشده‌اند. راه حل آن ایجاد یک Application pool مجزا به ازای هر سایت هست (توسط هاست‌دار).
              • #
                ‫۱۰ سال و ۷ ماه قبل، چهارشنبه ۲۱ اسفند ۱۳۹۲، ساعت ۱۳:۴۶
                ممنون از جوابتون این اتفاق مرتب می‌افتد یعنی هر 17,18 دقیقه یکبار. اگر مشکل از کرش سایتهای دیگه باشه آیا این طور مرتب برنامه ری استارت میشه؟
                • #
                  ‫۱۰ سال و ۷ ماه قبل، چهارشنبه ۲۱ اسفند ۱۳۹۲، ساعت ۱۳:۴۹
                  بله. زمانیکه تمام سایت‌ها با یک Application pool مدیریت می‌شوند، تمام آن‌ها توسط یک وهله از w3wp.exe اجرا خواهند شد. با تعریف Application poolهای مجزا، هر سایت، یک وهله‌ی مجزا از w3wp.exe را به خود اختصاص خواهد داد. یعنی اگر Task manager سرور را بررسی کنید، به ازای هر سایت، یک w3wp.exe با pid مجزا قابل مشاهده است. به این ترتیب اگر pid=1234 کرش کرد، تاثیری روی pid=4321 نخواهد داشت.
                  • #
                    ‫۱۰ سال و ۷ ماه قبل، چهارشنبه ۲۱ اسفند ۱۳۹۲، ساعت ۱۴:۰۸
                    من با سرور تماس گرفتم گفتن که همه سایتها pool جدا دارن. توی مقاله هم که نگاه کردم هیچکدوم از موارد ذکر شده برای سایت ما صدق نمی‌کرد. نمیدونید مشکل دیگه می‌تونه ناشی از چی باشه؟ تشکر
                    • #
                      ‫۱۰ سال و ۷ ماه قبل، چهارشنبه ۲۱ اسفند ۱۳۹۲، ساعت ۱۴:۳۵
                      با تنظیمات Application pool همه کار می‌توان کرد. مثلا تنظیم کرد سایت هر 20 دقیقه یکبار پس از بیکاری از حافظه خارج شود. یا تنظیم کرد اگر مصرف حافظه‌ی برنامه به یک حد مشخصی رسید، سایت ری استارت شود. بررسی آن نیاز به بررسی کدهای شما و تنظیمات سرور دارد.
  • #
    ‫۱۰ سال و ۷ ماه قبل، سه‌شنبه ۲۰ اسفند ۱۳۹۲، ساعت ۱۴:۳۴
    یه برنامه نوشتم، که کاربر میتونه زمان رو انتخاب و Job رو ایجاد کنه... لیست Job‌ها هم در CheckedBoxList نشون داده میشه تا کاربر هر کدوم رو که دوست داشتم موقتا Pause و Resume کنه.

    job‌ها بدون نقص کار میکنن منتها Job‌ها بعد از Pause و Resume دیگه فعال نمیشن. مشکل از کجاست؟
      public void Run()
            {
    ...
      chkJobs.Items.Add(job.Key, true);
    }

        private void chkJobs_ItemCheck(object sender, ItemCheckEventArgs e)
            {
                int index = e.Index;
                var sch = Scheduler.GetScheduler();
                foreach (object item in chkJobs.Items)
                {
                    JobKey key = (JobKey)item;
    
                    if (e.NewValue == CheckState.Unchecked)
                    {
                        sch.PauseJob(key);
                    }
                    else
                    {
                            sch.ResumeJob(key);
                    }
                }
            }

            public class Jobs : IJob
            {
                public void Execute(IJobExecutionContext context)
                {
                    JobDataMap datamap = context.JobDetail.JobDataMap;
                    switch (Convert.ToInt32(datamap.GetString("OperationType")))
                    {
                        case 1:
                            MessageBox.Show(datamap.GetString("OperationValue"));
                            break;
                    }
    
                }
            }
  • #
    ‫۹ سال و ۱۱ ماه قبل، چهارشنبه ۱۴ آبان ۱۳۹۳، ساعت ۱۹:۳۷
    سلام
    میخواستم سایتی رو راه اندازی کنم که خیلی از کارهاشو  به صورت زمان بندی و با quartz انجام میده.یه قسمت بصورت آزمایشی نوشتم و روی هاست گذاشتم اما ظاهرا بعد از چند دقیقه استوپ میشه دلیلش رو جویا شدم و دست و پا شکسته یه چیزایی فهمیدم که کافی نبود، مثلا اینکه این موضوع به هاست مربوطه و وقتی که ریست میشه دیگه دیگه quartz از حالت run خارج میشه. لطفا اگه کسی در این زمینه اطلاعاتی داره راهنمایی کنه 
    • #
      ‫۹ سال و ۱۱ ماه قبل، پنجشنبه ۱۵ آبان ۱۳۹۳، ساعت ۰۱:۰۱
      از HangFire استفاده کنید، در این حالت Jobهاتون توی SQL Server ذخیره میشه، یعنی با بستن برنامه و ... Jobها به کارشون ادامه میدن(+).