ASP.Net er þannig að þegar maður skellir inn nýjum .dll þá endurræsir IIS þráðinn sem er keyra og öll session, application og cache gögn tapast. Ég á það til að henda inn nýjum .dll á miðjum degi þegar slatti umferð er á vefnum. Þetta er slæmur ávani hjá mér en ég er bara ekki alltaf til í að bíða til kl. 4 á nóttinni til að gera þetta.
Málið er að mikið af gögnunum hjá mér er í Cache hlutanum til að auka hraðann á vefnum. Þegar ég hleð nýjum .dll þá þarf að hlaða upp aftur í cache hlutina og þegar hundruði manna eru að spyrja vefinn á sekúndu þá vil ég að aðeins einn aðili fái að fylla í Cache objectin. Tökum sem dæmi þýðingarkerfið. Ef 100 manns koma inná vefinn þegar hann er endurræstur og það tekur segjum 2 sekúndur að hlaða inn allri tungumála skránni þá vil ég ekki að 100 manns séu að gera það á sama tíma því það veldur biðröð og meiri töfum. Aðeins eitt request má fá að hlaða inn tungumála skránni og allir hinir þurfa að bíða á meðan.
Mér finnst engin ein góð lausn á þessu, allavega hef ég ekki fundið hana. Ég hef séð Mutex klasann vera notaðann og var sjálfur að nota hann en svo kom í ljós að hann er ekki að virka eins og ég vildi, væntanlega því ég var að nota hann rangt.
Lausnin er eitthvað á þessa leið
1. public class Foo {
2. private static Foo f = new Foo();
3.
4. public static Foo Current {
5. if (Cache["foo_" + webId] == null) {
6. lock (f) {
7. if (Cache["foo_" + webId] == null) {
8. //load language file, takes about 2 seconds
9. Foo f2 = new Foo();
10. f2.Load(webId);
11. }
12. }
13. }
14.
15. return (Foo) Cache["foo_" + webId];
16. }
17.
18. private void Load(int webId) {
19. //load stuff, takes 2 seconds
20. }
21.}
Ef ég reyni að útskýra kóðann þá er það einhvernveginn svona.
Lína 2: Bý til static tilfelli af Foo klasanum sem verður til þegar fyrsta request gerist. Þar sem ég er að keyra marga vefi á sama AppDomain-inu(sama process) þá gengur ekki fyrir mig að láta þessa statíska breytu vera "Cache-ið" mitt, því gögnin í Foo eru mismunandi eftir vefjum.
Lína 5: Athuga fyrst hvort Cache hluturinn sé til, þetta er gert því í 99,99% er hann til og kostnaðurinn við að læsa(lock) er mikill. Því er best að gera það aldrei nema bara þegar verið er að endurræsa vefinn.
Lína 6:Notum lock til að læsa öllum þráðum þannig að aðeins enn þráður keyri næstu skipun, þarna er mikilvægt að læsa tilvikinu af f því það er static og það er aðeins til eitt tilvik af því í öllu AppDomain-inu. Hafi tilvikið ekki verið statískt þá mundi lock ekki virka því það mundi aðeins læsa því tilviki sem það er að keyra.
Lína 7:Athugum hvort Cache hluturinn er tómur, ef ské kynni að það væri búið að hlaða í hann á meðan læsingin átti sér stað, þannig þurfum við ekki að hlaða aftur í hann ef það hefur gerst.
Lína 9:Búum til nýtt tilvik af Foo þar sem við getum ekki notað f því það er statískt og er því alltaf eins milli vefja sem eru að nota sama AppDomain-ið. Því að Foo er mismunandi eftir vefjum en margir vefir geta verið að keyra á sama AppDomain.
Lína 10:Setjum gögnin í Foo hlutinn.
Lína 15:Skilum tilviki af Foo
Með því að gera þetta þá tryggi ég að aðeins einn aðili muni spyrja um gögnin og hlaða því í Cache hlutinn á meðan hinir bíða. Þetta gerir kerfið hraðara að endurræsa sig því töfin sem varð af því að allir voru að spyrja á sama tíma gat valdið því að vefinn fór á hausinn og það var ekkert grín að koma honum aftur upp.
Ég er ekkert voðalega sáttur við þess leið, en hún var sú eina sem ég sá að virkaði. Ef þú veist um einhverja aðra leið þá máttu endilega láta mig vita því það væri gott að hafa þetta snyrtilegra en ekki þessar leiðinlegu if setningar.