PDA

View Full Version : زمان بندی خودکار کارها در هاست اشتراکی (Scheduled Tasks in sharing host)



Ehsan Rafsanjani
یک شنبه 21 فروردین 1390, 22:37 عصر
برای انجام یک کار ( اجرای یک کد دلخواه ) در دات نت به صورت خودکار در یک زمان و تاریخ معین روش های متفاوتی وجود دارد. روش هایی که اکثرا وابسته به سیستم عامل می باشند، و توسط یک نرم افزار دیگر کارهای مورد نظر ما اجرا می شوند.
میزبان های وب که خدمات خود را به صورت اشتراکی ارایه می کنند ، دسترسی به امکانات سیستم عامل را معمولا محدود می کنند و نمی توان از این نرم افزار های جانبی برای اجرای خودکار کارهای مورد نظر ما استفاده کرد! خوب، راه حل چیست؟
دات نت این امکان را به صورت مستقیم فراهم نکرده است! نا امید نشوید با کمک چند فوت فن کوچک (tricks) می توان این کار را انجام داد. :لبخندساده:

روش اول: Threading

این روش بسیار ساده است. در تابع Application_Start فایل global.asax این کد را اضافه می کنیم:



void Application_Start(object sender, EventArgs e)
{
// هنگامی که برنامه شروع می شود یک ترید جدید ایجاد می شود
ThreadStart tsTask = new ThreadStart(TaskLoop);
Thread MyTask = new Thread(tsTask);
MyTask.Start();
}


این توابع را هم در فایل global.asax اضافه می کنیم:



static void TaskLoop()
{

// در این مثال از یک حلقه نامتناهی استفاده کرده ایم
// اگر شما بخواهید این تابع رو از یک صفحه دیگر متوقف کنید می تونید
// پارامتر های دیگر رو به این تابع اضافه کنید
while (true)
{
// فراخوانی تابع زمان بندی کارها
ScheduledTask();

// وقفه به میزان زمان تعیین شده
System.Threading.Thread.Sleep(TimeSpan.FromHours(8 ));
}

}



static void ScheduledTask()
{
// کد های که قرار است در فواصل معین اجرا شوند
}



روش دوم: Timers

در این روش در فایل global.asax در تابع Application_Start ابتدا یک تایمر ایجاد می کنیم ، تایمر ها وقتی منقضی می شوند، می توانند یک تابع را اجرا کنند. با توجه به همین نکته از رویداد انقضا تایمر (Elapsed Event) برای فراخوانی کدهای مورد نظر برای اجرا استفاده می کنیم و در عین حال در این مرحله تایمر مجددا ایجاد می شود.



void Application_Start(object sender, EventArgs e)
{
// ایجاد یک تایمر به صورت خودکار
System.Timers.Timer timScheduledTask = new System.Timers.Timer();

// وقفه تایمر به صورت میلی ثانیه می باشد
// در این مثال هر یک دقیقه
timScheduledTask.Interval = 60 * 1000;

timScheduledTask.Enabled = true;

// فراخوانی تابع مورد نظر زمانی که تایمر منقضی می شود
timScheduledTask.Elapsed +=
new System.Timers.ElapsedEventHandler(timScheduledTask _Elapsed);
}

void timScheduledTask_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
// فراخوانی تابع مورد نظر
FirstTask();
}

void FirstTask()
{
// کد های که قرار است در فواصل معین اجرا شوند

}


روش سوم: Cache expiration

در asp.net هنگامی که کش منقضی می شود می توان یک تابع را فراخوانی کرد. با توجه به همین نکته از رویداد انقضا کش برای فراخوانی کدهای مورد نظر برای اجرا استفاده می کنیم و در عین حال در این مرحله دوباره کش ایجاد می شود.
برای شروع یک آیتم به کش اضافه می کنیم، مهم نیست که این آیتم محتوی چه چیزی باشد به عنوان مثال می تواند یک استرینگ ساده مثلا "1" باشد.
مانند مراحل قبلی در فایل global.asax این توابع اجرا می شوند:




void Application_Start(object sender, EventArgs e)
{
// فراخوانی تابع اجرا کدهای مورد نظر برای اولین بار
ScheduleTask();
}

static void ScheduleTask()
{
HttpRuntime.Cache.Add(
// نام آیتم کش و مقدار آن
"ScheduledTask",
"1",
null,
// کش از متد همیشگی برای انضا استفاده نمی کند
Cache.NoAbsoluteExpiration,
// کش بعد از 1 ساعت منقضی می شود
TimeSpan.FromHours(1),
// کش بعد از انقضا پاک نشود
CacheItemPriority.NotRemovable,
// فانکشن مورد نظر هنگام انقضا کش فراخوانی شود
new CacheItemRemovedCallback(SetTimer));
}

// این فانکشن هنگام انقضا کش فراخوانی می شود
static void SetTimer(string key, Object value, CacheItemRemovedReason reason)
{

DoTask();
// فراخوانی دوباره برای اجرای مجدد
ScheduleTask();
}

static void DoTask()
{
// کد های که قرار است در فواصل معین اجرا شوند
}




جمعبندی:

Scheduled Task ها کاربردهای زیادی دارند، مثلا ارسال ایمیل به طور خودکار ،پشتیبانی از فایل ها ، پاک کردن فایل های temp و ....
همینطور که در بالا مشاهده کردید asp.net هیچ روش مستقیمی برای این کار ندارد و ما بوسیله امکانات سایر روش ها این کار رو عملی کردیم، با این وجود این روش ها هیچ کدام استاندارد نیست (شخصا روش های تایمر و کش رو بیشتر دوست دارم) ولی بهترین روش این است که ما از یک سرور مستقل برای این منظور استفاده کنیم! و بر گردیم سراغ سرویس های ویندوز برای اجرای یک کار به صورت زمان بندی شده و متوالی ...

مشکل اول: اگر وب سایت ما هیچ درخواستی (بازدید) نداشته باشد application متوقف می شود!
برای حل این موضوع نیز باید یک Task جدید ایجاد کنیم که با استفاده از کلاس WebClient یک درخواست جدید به سایت بفرستد. (مثلا هر 10 دقیقه)
این لینک (http://www.dotnetperls.com/webclient)اطلاعات بیشتری را در مورد کلاس WebClient به ما می دهد.

مشکل دوم: در واقع این مهمترین ضعف در روش های بالاست!!!
اگر IIS شروع دوباره (restart) شود تا زمانی که بازدیدی از وب سایت ما صورت نگیرد هیچ کدام از Scheduled Task ها اجرا نمی شوند.

منبع:
http://www.beansoftware.com/ASP.NET-Tutorials/Scheduled-Tasks.aspx

reza_program
چهارشنبه 16 فروردین 1391, 12:58 عصر
نه متاسفانه هنوز مشکل دارم
دوستان من یک کا رو میخوام بطور مداوم انجام بدم
چه از روش اول و چه از روش دوم که استفاده میکنم به همین خطا برخورد میکنم
خطا از این قرار است که من یک کلاس پایه دارم و یک کلاس مشتق
تو کلاس پایه تنظیمات رو در نظر گرفتم مثل کش و ...

مثلا خط کد کش اینطوری هست:


public static System.Web.Caching.Cache Cache
{
get { return HttpContext.Current.Cache; }
}

وقتی اون کد آپدیت رو تو Global میذارم
از همین خطا بالا خطا میگیره و میگه هنوز کانتنت جاری ساخته نشده!!!:

Object reference not set to an instance of an object.

85176

maryam_vb
دوشنبه 18 اردیبهشت 1391, 10:23 صبح
سلام

من از روش روش سوم: Cache expiration استفاده کردم ، در حالت لوکال (سیستم خودم) کار زمان بندی مرتب در فواصل خواسته شده اجرا میشه ولی رو هاست انجام نمیشه، علت چیه؟ چه کاری باید انجام بدم تا رو هاست هم مثل سیستم خودم کار زمانبندی دلخواهم حتما اجرا شه؟