Ááá

Další web používající WordPress

Úno

4

Thread-safety a webové aplikace

Jeden z nejdůležitějších aspektů, jeden z nejméně testovaných.

Prolog

Představte si modelovou situaci:

  • Zpřístupníte světu webovou aplikaci, kterou jste pečlivě ze všech stran otestovali a jste si jistí, že funguje správně.
  • Ze začátku o ni není velký zájem, ale těch pár lidí, co ji občas použije, si ji nemůže vynachválit a tak časem začne uživatelů přibývat. Word of mouth.
  • Pak se stane něco divného. Nějaká data se ztratí, nějaký uživatel dostane cizí data, něco se uloží dvakrát apod.
  • Zaboha nemáte tušení, čím to bylo. Nakonec to svedete na skvrny na slunci a pustíte to z hlavy.
  • S rostoucí popularitou podobných situací začne přibývat.
  • Jak podobých incidentů začne přibývat, začne se šířit pověst o nespolehlivé aplikaci. Popularita a důvěra klesá. Word of mouth.

Takhle můžete dopadnout, když nevěnujete dostatečnou pozornost tomu, co se všechno může stát, pokud k vaší aplikaci přistupuje více lidí zároveň.

Na co dávat pozor

Pozor je potřeba dávat vždy, když přistupujete k nějakým sdíleným zdrojům. Sdílené zdroje = cokoli mimo kontext aktuálního HTTP požadavku. Příkladem sdílených zdrojů jsou hlavně soubory a databáze, ale zdaleka nejen.

V některých prostředích, včetně ASP.NET, také statické členy tříd. Přestože pro každý požadavek se vytváří nová instance stránky, nový HttpContext a spousta dalších věcí, samotné třídy jsou v celé aplikaci sdílené (rozdíl od PHP). Lze snadno ověřit:

<%@ Page Language="C#" Inherits="System.Web.UI.Page" %>
<script runat="server">
    static string Blah = "Default value.";
</script>

<html>
<body>
    <p>
        <%= Blah %>
        <% Blah = "Changed value."; %>
    </p>
</body>
</html>

Při prvním spuštění vypíše „Default value“, při každém dalším obnovení stránky „Changed value“, až do restartu aplikace. Ovšem lze kód upravit tak, aby ten člen byl „statický“ jen v rámci aktuálního požadavku:

static string Blah
{
    get { return HttpContext.Current.Items["Blah"] as string; }
    set { HttpContext.Current.Items["Blah"] = value; }
}

HttpContext.Current je sice také statická property, ale používá různé instance HttpContext podle toho, z kterého ji voláme threadu.

Přístupy ke sdíleným zdrojům je nutné nějak synchronizovat. Aby například během procesu zápisu do souboru (od otevření až do zavření), žádný jiný thread nemohl ten soubor číst. Ale to teď nechám být, teď mi jde jenom o odhalení těch přístupů.

Dávat pozor nestačí

Jenže dávat pozor nestačí.

Často si nemusíte uvědomit, že zdroj, ke kterému přistupujete, je sdílený. Někdy to ani nemusí být moc zřejmé (třeba nějaké knihovny třetích stran můžou používat statické členy vnitřně). Nebo si nemusíte uvědomit, že některá operace není atomická.

Před třemi lety bych vůbec nepřemýšlel, jestli PHP funkce file_put_contents() je nebo není atomická. Kdyby mě to bylo napadlo, tak bych býval během chvilky splácl jednoduchý test, ale mě to ani nenapadlo… Udělal jsem za tu dobu dostatečný pokrok, abych se mohl spolehnout jen na svůj úsudek? Na to bych nespoléhal.

Epilog

Logicky tedy vyvstává potřeba nějak testovat chování aplikace při více uživatelích naráz. Zkoušel jsem najít nějaké nástroje a postupy, které by v tomhle pomáhali, ale asi jsem špatně hledal.

Představuju si to asi tak, že nadefinuju uživatelské kroky, které pak nechám provést třeba 50 robotů zároveň.

Nakonec jsem si vytvořil takovou jednoduchou utilitku sám. Používá Příkazový řádek, Selenium a spoustu Firefoxů… Až udělám nějaké screenshoty, sepíšu o tom článek a hodím to sem.

Ale už teď mě zajímá: Testujete nějak chování aplikace pod palbou uživatelských akcí, ještě před jejím vypuštěním?

This entry was posted by LLook on 23:16, Úno 4th 2009 and filed in Nezařazené.

Komentáře můžete sledovat přes RSS 2.0 kanál.

Leave a Reply


© Ááá * WordPress * LoseMyMind * Feed feed