AppBeat Blog

Perfect Monitoring for Your Cloud

C# - how to lock without deadlocks

In C# there is built-in keyword lock which enables you to create thread-safe methods. However, you must be aware that if you are not careful, you can create deadlock conditions where your method waits for lock indefinitely.

How lock keyword works? As described in "Locks and exceptions do not mix" blog article, in C# 4 compiler translates lock statement into this:

bool lockWasTaken = false;
var temp = obj;
try { Monitor.Enter(temp, ref lockWasTaken); { body } }
finally { if (lockWasTaken) Monitor.Exit(temp); }

We can use this to create utility method which works similarly to original lock, but waits only specified amount of time and prevents deadlocks:

using System;
using System.Threading;

namespace AppBeat.Utility
{
    public static class Concurrency
    {
        /// <summary>
        /// Method tries to run <seealso cref="doAction"/> in thread-safe manner but waits max <seealso cref="millisecondsTimeout"/> milliseconds for lock. If it can not acquire lock in specified time, exception is thrown.
        /// This method can be used to prevents deadlock scenarios.
        /// </summary>
        public static void LockWithTimeout(object lockObj, Action doAction, int millisecondsTimeout = 15000)
        {
            bool lockWasTaken = false;
            var temp = lockObj;
            try
            {
                Monitor.TryEnter(temp, millisecondsTimeout, ref lockWasTaken);
                if (lockWasTaken)
                {
                    doAction();
                }
                else
                {
                    throw new Exception("Could not get lock");
                }
            }
            finally
            {
                if (lockWasTaken)
                {
                    Monitor.Exit(temp);
                }
            }
        }
    }
}

Instead of this code:

lock (this)
{
    //do something
}

You could then have something like this:

AppBeat.Utility.Concurrency.LockWithTimeout(this, delegate () {
    //do something
}, 15000); //do not wait more than 15 seconds for lock

As you can see, usage is very similar but in second case we should never get deadlock, because code will simply throw exception if it can not get lock.

This code could be used in debug version when you stress test your multithreaded code, so you can see if you get any timeout exceptions (deadlocks occur). From stack trace you should be able to see which part of your code is problematic.

In production you can leave this or replace it back with standard lock statement.

Running .NET Core web application on Linux

As proof of concept we tried to run AppBeat frontend (web application on https://appbeat.io/) on Ubuntu Linux 14.04.

First we had to switch to portable NuGet client library for WCF. This is necessary for communication with our backend. We then used auto generated proxies from Visual Studio "Add Service Reference" utility and only changed few lines of code (to explicitly cast objects to IDisposable at the end).

With this change web project was successfully compiled under dnxcore50 profile! Now everything was ready for Linux test!

We created fresh 64-bit installation of Ubuntu 14.04 and followed instructions on https://dotnet.github.io/getting-started/ and later https://docs.asp.net/en/latest/getting-started/installing-on-linux.html.

Everything went smoothly! At the end we configured firewall and installed nginx server. nginx is used to proxy requests to Kestrel server. Our application worked, but... It was really really slow :) We found out that there is an issue with current ASP.Net Core RC1 (Kestrel) and nginx combination and that it will be fixed with RC2 release (there were some workarounds published but it didn't help in our case). We will repeat test when RC2 is released.

Overall we are highly impressed with how things are evolving with .NET Core. Hat off to all participating in this project!

p.s.
I just quietly hope that Microsoft will decide to implement native compilation of web apps on .NET Core. That would be really really fantastic!

Work in progress: installable smart agents for richer telemetry

We are planning to extend our platform with smart agents that can be installed on workstations or servers. We will provide for example CPU, memory, disk space monitoring, ..., with possibility to extend agent with custom logic to monitor virtually anything.

We plan to develop cross platform shared codebase with platform specific extensions. For example, here is example of simple implementation for Windows operating system, which uses Performance Counter to get CPU usage:

namespace AppBeat.Telemetry.Windows
{
    class CPU : AppBeat.Telemetry.Core.BaseResource, ITelemetryProvider
    {
        public ResourceValue GetValue()
        {
            return GetResourceValuePercentage(
                nameof(CPU),
                Utility.PerformanceCounter.GetValue(
                    Constants.PC_CATEGORY_PROCESSOR,
                    Constants.PC_COUNTER_NAME_PROCESSOR_TIME,
                    Constants.PC_INSTANCE
                )
            );
        }
    }
}

Strong emphasis is of course on security. Some security aspects:

  • Firewall friendly: no inbound connections will be made, instead all telemetry will be pushed from smart agent to AppBeat server (only outbound connections will be made)
  • All communication with AppBeat server is over secure SSL connection
  • Additional to that, all messages will also be encrypted by application (smart agent) by using your unique private key. This additionally protects you from man-in-the-middle attack.

This is still work in progress but we want to give you a glimpse of what we are doing :)

We have switched to BETA 2

In this version of AppBeat we primarily focused on some optimizations of our core monitor service. For example, our core now sends database updates much much efficiently. In each monitoring batch that we dispatch we have several checks. When those checks return result, our dispatcher manager packs all the results into single DataTable and sends it to database as Table-Valued Parameter. This means single roundtrip to database, instead of previously tens of single database updates.

We are close to releasing final version of AppBeat. Stay tuned!