On-Demand Supports SSL

by anton.venema 13. July 2010 18:41

It's here! On-Demand officially supports SSL.

Using On-Demand SSL is trivial. Just change the script tag to load over https:// (i.e. https://sync3.frozenmountain.com/client.js). As long as your page is SSL-secured, the client will automatically configure itself to encrypt all communications.

Happy coding!

Tags: , ,

WebSync Method Containers and Memory Usage

by anton.venema 22. June 2010 20:20

With WebSync Server 3.0.2, we've introduced the targedScan web.config attribute and the WebSyncMethodContainer assembly-level attribute. Together, they can help to reduce memory consumption significantly. This is especially important for shared hosting environments, but is a good practice for any production system.

Before explaining what the new attributes do, let's first look at why memory consumption is an issue at all.

WebSync lets you decorate methods with attributes so they attach to specific server-side events (BeforePublish, AfterSubscribe, etc.). This ability is what makes WebSync so extensible and part of what makes it so easy to use. In order for WebSync to invoke the methods, though, it first has to find them. To do that, WebSync scans the currently loaded assemblies, looking at each type and checking for methods that are decorated with WebSyncEvent or WebSyncScriptModifier. This scan happens just one time, at first run, after which the decorated method information is cached and can be accessed later as needed.

So what's the problem?

Well, there's one small catch. Reflection is expensive, and the .NET framework architects made a design decision a long time ago that any reflective calls for metadata should be cached internally rather than allowing developers to implement caching solutions themselves. This means that whenever type or method information is accessed, the metadata is cached permanently in the application domain. The intention of the architects was to ensure that the reflective work was only every performed once, but for server environments with scarce resources, this is a problem.

As WebSync scans the assemblies/types/methods, .NET caches every piece of information. The internal .NET bloat can be noticeable, even upwards of 100MB memory consumption. We think you would agree, the memory could definitely be put to better use.

Enter the targetedScan and WebSyncMethodContainer attributes, which define where and how to scan.

If targetedScan is set to true in web.config (WebSync/server[targetedScan]), WebSync will ONLY analyze types that are explicitly specified by the WebSyncMethodContainer assembly-level attribute.

For example, if your WebSyncEvent methods are defined in a class called MyWebSyncEvents, simply place the following attribute in AssemblyInfo.cs (in your Properties folder):

[assembly: WebSyncMethodContainer(typeof(MyWebSyncEvents))]

Now, if targetedScan is set to true, WebSync will restrict its scan to just that type and its methods, ignoring all other types/methods and thereby preventing their metadata from being cached by .NET.

(Note: WebSyncMethodContainer can be defined multiple times per assembly, once for each type containing WebSync methods.)

We highly recommend that you use this approach, especially in production systems and reusable extension class libraries. There is no reason to have unnecessary memory consumption, especially when that memory could be used to increase concurrency :)

Tags:

Comet Best Practices: Subscribing and Initial State Load

by anton.venema 5. February 2010 04:29

Many complications arise when building a real-time web application that employs "comet" or "reverse Ajax" to push data from the server. This is mostly due to the fact that real-time web applications require multi-threading, either directly or indirectly, and many of the same issues that arise in threading scenarios directly parallel the issues present in comet-based websites.

A frequently found issue has to do with the timing of subscribing to a comet channel versus the initial state load of the web page.

For example, consider a simple chat application. When the page loads up, the user expects to see some recent chat messages, as well as start receiving any newly published messages. The initial state load is a distinct operation from the subscription to receive new messages. As such, one must be executed before the other. There are only two possible options:

  1. Load state, then subscribe.
  2. Subscribe, then load state.

The first option results in the possibility of missing messages. It's feasible (and likely under load) for a user to publish a message after the state has loaded, but before the subscription has completed. This message would not be included in the state load, and it would not be delivered to the user over comet since the subscription was not present at the time of delivery.

The second option results in the possibility of duplicated messages. It's feasible (and again likely under load) for a user to publish a message after the subscription has completed, but before the state has loaded. This message would be delivered to the user over comet since the subscription was present at the time of delivery, and it would be included in the state load.

It has been suggested that the initial state load should be delivered in the response to the subscription request. This is absolutely possible with WebSync, but it does not remove the problem - it just narrows the gap in which the problem can occur. The scenario where messages go missing or are duplicated becomes less likely, but we find ourselves in a dangerous situation when we try to hide bugs instead of fix them. Testing becomes more difficult and we run the risk of unleashing a bug that is more difficult to track down.

So what do we do?

In general, the best thing to do is not lose messages. (As always, there are exceptions, but this is the general case we have found.) So, subscribe first, and load state data afterwards, usually through an Ajax request.

  • Page loads and a loading indicator is shown.
  • WebSync client is created and subscribes to the channel.
  • In the subscribe onSuccess handler, POST a request for initial state with Ajax.
  • In the Ajax onSuccess handler, populate the UI and remove the loading indicator.

To get rid of the duplicate messages, set a loaded flag to true once the UI has been populated. If the WebSync client receives a message and the loaded flag is false, push it onto a list. Once the loaded flag has been set to true, read through the list and process new messages, discarding duplicates. Duplicates can be identified by a server-generated ID that is attached to every message publication.

Tags:

programming | websync

Automatic Foreign Objects in SubSonic3 SimpleRepository

by anton.venema 30. December 2009 21:38

SubSonic3's SimpleRepository is a wonder to behold. It's simple, clean, effective, and represents a huge step forward in abstracting away the DAL and allowing developers to focus on what matters.

I've been using it in development for a while now, and I have found that it comes up short when dealing with foreign keys. For one thing, foreign relationships are not persisted to the database, so data integrity is not 100% guaranteed for less-than-meticulous programmers.

What is more crucial, however, and the subject of this post, is the difficulty in loading up foreign objects from their respective keys.

Consider a simple case of a Car and a Wheel:

public class Car
{
    public int Id { get; set; }
}
public class Wheel
{
    public int Id { get; set; }
    public int CarId { get; set; }
}

In code, whenever you have an instance of a Wheel and want to reference the Car it belongs to, you have to do something like this:

// wheel is an instance of Wheel
SimpleRepository repo = new SimpleRepository("connection-string");
Car c = repo.Single<Car>(wheel.CarId);

Pretty simple! We can abstract away the need to always supply a connection string to the SimpleRepository by setting up a static method.

public class Repository
{
    public static SimpleRepository GetRepository()
    {
        return new SimpleRepository("connection-string");
    }
}

We can even abstract out the primary key for our models, knowing all our models will have a unique integer primary key.

public class Record
{
    public int Id { get; set; }
}
public class Car : Record
{
}
public class Wheel : Record
{
    public int CarId { get; set; }
}

That aside, let's get back to foreign object loading, and look at the reverse process. Given a Car, retrieve its Wheels.

// car is an instance of Car
SimpleRepository repo = Repository.GetRepository();
List<Wheel> wheels = repo.Find<Wheel>(w => w.CarId == car.Id).ToList();

Again, fairly simple.

So, what's the problem?

Well, there are two problems actually. The first is that there are performance issues. Consider a common case where the Car instance is passed around to a few methods. If any of those methods (or methods that they call, etc.) have to access the Wheels, they will have to make separate round-trips to the database. Ideally, once the Wheels have been loaded once, they will be cached with the Car instance. The second problem is that of code duplication. If the model changes, the expressions that describe the foreign key relationships will have to be updated everywhere.

So how do we fix it?

Ideally, we would use properties on the models to reflect the foreign key relationships. Something like:

public class Car : Record
{
    public List<Wheel> Wheels { get; }
}
public class Wheel : Record
{
    public int CarId { get; set; }
    public Car Car { get; set; }
}

So that's what we will do :) By abstracting away the details of the foreign key lookups and caching the foreign key objects, we can write the process once and reuse it in every single one of our models. This is what the real-world implementation will look like:

public class Car : Record
{
    public List<Wheel> Wheels
    {
        get { return GetForeignList<Wheel>(w => w.CarId == Id); }
    }
}
public class Wheel : Record
{
    public int CarId { get; set; }
    public Car Car
    {
        get { return GetForeign<Car>(CarId); }
        set { CarId = SetForeign(value); }
    }
}

The GetForeign<T>, SetForeign<T>, and GetForeignList<T> methods are implemented as protected methods in the Record base class we built earlier. All the complexity is wrapped into these methods, including an in-memory cache, so the models can just be... models.

public class Record
{
    public int Id { get; set; }
    
    private Hashtable ForeignCache = new Hashtable();

    protected T GetForeign<T>(int key) where T : Record, new()>
    {
        string relation = typeof(T).Name;
        T foreign = ForeignCache[relation] as T;
        if (foreign == null || foreign.Id != key)
        {
            foreign = Repository.Get<T>(key);
            ForeignCache[relation] = foreign;
        }
        return foreign;
    }

    protected int SetForeign<T>(T foreign) where T : Record, new()
    {
        string relation = typeof(T).Name;
        ForeignCache[relation] = foreign;
        return (foreign == null) ? 0 : foreign.Id;
    }

    protected List<T> GetForeignList<T>(Expression<Func<T, bool>> expression) where T : Record, new()
    {
        return GetForeignList<T>(expression, false);
    }

    protected List<T> GetForeignList<T>(Expression<Func<T, bool>> expression, bool refresh) where T : Record, new()
    {
        string relation = "l-" + typeof(T).Name;
        List<T> foreign = ForeignCache[relation] as List<T>;
        if (foreign == null || refresh)
        {
            foreign = Repository.GetRepository().Find<T>(expression).ToList();
            ForeignCache[relation] = foreign;
        }
        return foreign;
    }
}

Tags:

Building a Managed Comet Server Part 1 - Scalability in ASP.NET

by anton.venema 18. November 2009 23:34

A common misconception about IIS and the .NET framework is that it is unable to scale well to tens of thousands of simultaneous requests. WebSync has proven that this is not the case, so why does that misconception still exist?

Not just a page anymore

In classic ASP, there was no way to make an incoming request go "idle" and just wait for something else to push it along. Instead, requests blocked on the thread pool, eventually saturating it so no further requests could be processed.

ASP.NET takes the same approach with standard requests, but provides another option as well - the IHttpAsyncHandler. This handler is designed to allow multiple requests with long-running executions to take minimal CPU usage and not saturate the thread pool, a perfect solution for building a comet server. It's no surprise, then, that this is the foundation on which WebSync is built.

Beyond the basics

Of course, creating the async handler is pointless if each request just blocks on a thread from the CLR thread pool waiting for events. Even if each request blocked for just a few seconds, you'd quickly exhaust the thread pool under load. The requests have to be offloaded for batch analysis in a separate bounded thread pool. The bounded thread pool can then make use of shared data structures to balance the request load while waiting for events to trigger a response.

To make this work, the CLR thread pool has to have a large number of threads available for the handling of incoming and outgoing requests, and the secondary bounded thread pool has to have just a few threads for the handling of everything in between. The trick is to get incoming requests off the CLR thread pool quickly for long-running processes so the secondary thread pool can bear the weight and keep the CLR thread pool light on it's feet.

Tags: , , ,

programming | websync