.Net Circular Queue Wrapper

Geçtiğimiz aylara kadar java ile haşır neşir olurken bir anda ibre .net tarafına kaydı. Birbirleri ile çok ortak noktaları olsa da implementasyonlar ve api lar farklı olabiliyor. Java yazarken circular queue (aka ring buffer) ihtiyacım olduğu zaman guava içindeki com.google.common.collect.EvictingQueue sınıfını kullanıyordum. .Net Frameworkü üzerinde circular queue implementasyonu bulamadım. Stackoverflow üzerinde yaptığım arama sonucunda https://stackoverflow.com/a/9371346  adresindeki çözüme ulaştım. Problemimiz web api uygulamamıza gelen son 100 isteğin cevap zamanlarının ortalaması belli bir değeri aşarsa başka bir uygulamaya uyarı göndermek. İlgili kısımları burada paylaşıyorum.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
public class FixedSizedQueue<T> : ConcurrentQueue<T>
{
    private object lockObject = new object();

    private int limit;

    public FixedSizedQueue(int limit)
    {
        this.limit = limit;
    }
    public new void Enqueue(T obj)
    {
        base.Enqueue(obj);
        lock (lockObject)
        {
            T overflow;
            while (base.Count > limit && base.TryDequeue(out overflow)) ;
        }
    }

    public T[] ReadAll()
    {
        return base.ToArray();
    }
}

public class StopWatchAttribute : ActionFilterAttribute
{
    private static string KEY = "Response.Time";
    private static long LastWarning = DateTime.Now.Ticks;
    private static long PERIOD = TimeSpan.TicksPerSecond * 15;
    private static int SIZE = 100;
    private FixedSizedQueue<long> queue = new FixedSizedQueue<long>(SIZE);

    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        base.OnActionExecuting(actionContext);
        actionContext.Request.Properties[KEY] = Stopwatch.StartNew();
    }

    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
    {
        base.OnActionExecuted(actionExecutedContext);
        Stopwatch stopwatch = (Stopwatch)actionExecutedContext.Request.Properties[KEY];
        var elapsed = stopwatch.ElapsedMilliseconds;
        queue.Enqueue(elapsed);

        var averageResponseTime = queue.ReadAll().Sum() / SIZE;
        var responseTimeIncresing = averageResponseTime > 100;
        var notInPeriod = DateTime.Now.Ticks - LastWarning > PERIOD;
        if (responseTimeIncresing && notInPeriod)
        {
            LastWarning = DateTime.Now.Ticks;
            Debug.WriteLine($"{elapsed} ms elapsed.");
            // TODO whatever you want with this, log or feed another service
        }
    }
}

public class ValuesController : ApiController
{
    [StopWatch]
    public string Get()
    {
        return "ok";
    }
}