2008年12月18日 星期四

用 ASP.NET 的 Cache 做週期執行的程式

要寫一個週期執行的工作,如果不能寫 windows service,也不能在 server 上安裝程式的話,可以寫一個 aspx 頁面並且定期去執行它,只不過要誰來執行這個 aspx?一個人做在電腦前不斷 reload?寫個程式放在不關機的電腦不斷向 web server 送出 request?

透過前輩提點使用 Cache,先去找幾篇基本用法:

http://blog.darkthread.net/blogs/darkthreadtw/archive/2007/08/30/tips-asp-net-cache-mini-guide.aspx

http://www.dotblogs.com.tw/jeff377/archive/2008/08/28/5236.aspx

http://msdn.microsoft.com/zh-tw/library/system.web.caching.cacheitemremovedcallback(VS.80).aspx

然後我寫了一個 aspx 網頁,其 *.cs 如下:


using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

using System.Web.Caching;
using System.IO;


public partial class cacheTest : System.Web.UI.Page
{
static public string status = "";

protected void RemovedCallback(String k, Object v, CacheItemRemovedReason r)
{
if (status.Equals("PLAY"))
{
addCache();
}

log(string.Format("CacheItemRemovedReason={0}", r.ToString()));
}

protected void log(string str)
{
StreamWriter sr;

FileInfo fi = new FileInfo(Server.MapPath("cacheTest7.txt"));
sr = new StreamWriter(fi.Open(FileMode.OpenOrCreate | FileMode.Append, FileAccess.Write));
sr.WriteLine(string.Format("{0}, {1}, {2}"
, DateTime.Now.ToString("yyyyMMdd HHmmss")
, str
, Cache.Count
));
sr.Flush();
sr.Close();
}

protected void addCache()
{
log("[addCache start]");

if (Cache["AutoTask"] == null)
{
Cache.Add("AutoTask", "xxx", null
, DateTime.Now.AddSeconds(10), TimeSpan.Zero
, CacheItemPriority.High, new CacheItemRemovedCallback(this.RemovedCallback));
}

log("[addCache end]");
}

protected void remove()
{
if (Cache["AutoTask"] != null)
{
Cache.Remove("AutoTask");
}
}

protected void Page_Load(object sender, EventArgs e)
{
if (Request["stop"] != null)
{
status = "STOP";
remove();
}
else
{
status = "PLAY";
addCache();
}

}
}



第一次進入,會執行 addCache(),並會設定 10 秒後到期,以及到期時要執行的 RemovedCallback(),然後再次重複執行 addCache()。

寫入紀錄檔的內容:


//用ff開網頁
20081218 153238, [addCache start], 0
20081218 153238, [addCache end], 1

20081218 153300, [addCache start], 1
20081218 153300, [addCache end], 2
20081218 153300, CacheItemRemovedReason=Expired, 2

20081218 153320, [addCache start], 1
20081218 153320, [addCache end], 2
20081218 153320, CacheItemRemovedReason=Expired, 2

20081218 153340, [addCache start], 1
20081218 153340, [addCache end], 2
20081218 153340, CacheItemRemovedReason=Expired, 2

//用ie開相同網頁
20081218 153356, [addCache start], 1
20081218 153356, [addCache start], 1
20081218 153356, [addCache end], 2
20081218 153356, CacheItemRemovedReason=Expired, 2
20081218 153356, [addCache end], 1

20081218 153420, [addCache start], 1
20081218 153420, [addCache end], 2
20081218 153420, CacheItemRemovedReason=Expired, 2

20081218 153440, [addCache start], 1
20081218 153440, [addCache end], 2
20081218 153440, CacheItemRemovedReason=Expired, 2

20081218 153500, [addCache start], 1
20081218 153500, [addCache end], 2
20081218 153500, CacheItemRemovedReason=Expired, 2


* 即使瀏覽器被關掉了,這個執行緒仍會不斷跑。
* 開不同的瀏覽器、另一個人瀏覽此網頁,可造成上次的 cache 立即到期,然後建立新的 cache。
* web server 重開好像不會造成中斷,www 服務重開才會造成中斷。

這樣就可以寫週期執行、排程程式了。

7 則留言:

joehwang 提到...

這真是太酷了XD

匿名 提到...

Hi 邦邦您好,

從業界得知你的大名,想與你談談關於遊戲開發的事項。本公司是一間外商公司專門開發線上遊戲(例如Live, P2P..etc)。研發部門在台灣尋找專業AS3高手來一起合作開發。希望能有時間與你談談。請有空回覆我,希望能聽到你的回覆。

Max
02-8751-0899(#218)

Ben Chang 提到...

從您留下來的電話來看,貴公司是 日嘉 對吧?

http://www.sunplus-technology.com/contact_us.html

說來有意思,我印象中前陣子也投過貴公司在 104 的履歷:

http://www.104.com.tw/jobbank/cust_job/job.cfm?j=5e4e462b403a435a35363e6730683b2196274462d5a604225252525673d552a29745j01&intro=1&jobsource=checkcpage=1&page=1

沒想到與您聯繫 竟然還是仰賴我的 blog,而非我 104 的履歷表,可見得我的履歷表實在是太不吸引人了,呵呵!

Freshman 提到...

Hi 您好,

我想請問有關您分享的用Cache執行週期性程式的方法,因為您在該文章的註解有提到:
* 開不同的瀏覽器、另一個人瀏覽此網頁,可造成上次的 cache 立即到期,然後建立新的 cache。*
如果我不想讓這個功能發揮作用,也就是不要建立新的cache,該如何做呢?
因為我需要自行設定一天執行一次我的ASP.NET裡的一個副程式,其餘時間點都不需要執行該副程式。

謝謝您!

Ben Chang 提到...

一般來說,我只有 "啟動" 或 "停止" 的時候需要去瀏覽該網頁,該網頁應該是一個不讓外界所知道的網址,所以這應該是人為可以決定的,不要時常去瀏覽他就好了吧。

若是一天只執行一次,程式的機制部分也可以製做 已執行的記錄 的機制,這樣一來,就算每天執行多次,也可藉由判斷記錄檔而決定本日是否要再執行。我會考慮基於程式有可能因非預期的情況而沒執行,經修正後隨時可以再次啟動的可能性,而以記錄檔來當作當天不要重複執行的判斷依據。

若是真想要研究 Cache 的使用方式的話,可以試試看 Cache.Get("xxx") 取得該名稱的 cache,以判斷是否已經有在執行。

aio 提到...

不好意思, 我想請問一下,
在您的範例程式碼裡面有一行 "if (Request["stop"] != null)",
這邊Request物件裡面的stop的值是在哪裡設定的呢?? 我從範例程式碼裡還是沒看出來@@, thanks.

Ben Chang 提到...

......

意思是,連到這個網址時,要用以下連結:

http://xx.yy.zz/do_xxx.aspx?stop=

要有 stop 參數的意思~

當然,這個範例只是示意用的,你可以自己設計改成 do_xxx.aspx?act=start 與 do_xxx.aspx?act=stop,然後改改判段程式 即可!