Skip to content

Instantly share code, notes, and snippets.

@ReubenBond
Last active January 19, 2016 09:00
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ReubenBond/bf7edc056c1a5d3dbb79 to your computer and use it in GitHub Desktop.
Save ReubenBond/bf7edc056c1a5d3dbb79 to your computer and use it in GitHub Desktop.
Orleans Roadmap Episode 1: Wish List

Orleans Roadmap Episode 1: Wish List

Documentation Overhaul

Our documentation is relatively poor. We need to make things much more approachable for newcomers & experienced users alike. Beefing up the documentation will be a big effort which will pay dividends. It wouldn't hurt to spice things up with some illustrations/graphics, either.

Event Sourcing

There has been much discussion about this and it is clearly something which many are interested in. See #343.

Geo-distributed clusters/grains

Having a planet-scale service is very desireable, but there are many considerations and potential issues regarding performance, availability, and consistency (oh, right, CAP...). See Orleans Virtual Meetup 6 & Geo-Distribution Project.

Simple Reactive Streams

See #940. Grains can return IAsyncObservable<T> or IObservable<T> to callers. This allows us to whimsically create real-time applications on Orleans.

Initial thoughts on implementation:

  • CodeGen will need to accommodate for new return types (We should start with just IAsyncObservable<T>)
  • A proxy type will be created which implements IAsyncObservable<T> and another which implements StreamSubscriptionHandle<T>. These proxies will communicate with remote counterparts.
  • CallbackData will probably be subclassed to create a version which only deregisters itself when OnCompleteAsync or OnErrorAsync is invoked or the StreamSubscriptionHandle<T> implementation calls UnsubscribeAsync.
  • The IAsyncObservable<T> implementation will call the grain method in its SubscribeAsync implementation.

JavaScript client & proxy

Similar to SignalR's JS proxy, we could implement a proxy which exposes grain methods to JS-based clients in the Web browser or NodeJS I imagine we would create a JSON definition of the grain interfaces (grain types, methods, parameters) and create an OWIN/ASP.NET middleware to call into grains. For authorization, we could either expose an interface similar to ASP.NET Web API filters or add a hook along the lines of Action<IOwinContext, IGrain, MethodInfo> or Func<IOwinContext, IGrain, MethodInfo, Task> which can throw the appropriate exception if access is denied.

State Versioning/Migration

New comers often fret about state migration, we should have a very solid solution for them. If the default persistence providers do not support altering state definitions then we should get rid of them or fix them. One fix is to use a 'tagged' serialization format where each field has an associated id in a similar fashion to Protocol Buffers. We could also just use Protocol Buffers when a user has decorated their type with the requisite attribute.

New "clone and go" Getting Started project

We should create a very simple Getting Started project which users can clone and work with. The project should demonstrate the use of DI in grains (using Autofac) and calling into Orleans from an ASP.NET Web API.

TLS Support

There are many scenarios where access to an Orleans Cluster from outside of its local network is desired. Geo-distributed clusters could be easily configured using TLS support instead of setting up site-site VPNs. TLS support will allow us to more safely expose a cluster to outside clients. Note: Consider using WebSockets for security reasons (firewall interrogation of requests)

Cluster Portal

In general, we should push monitoring out to third-party tools, but a simple dashboard for interacting with the cluster in an Orleans-specific manner would be useful for some scenarios. We can draw on the Telemetry APIs, OrleansMonitor, and the Actor Web Console sample. Live streaming of logs from individual grains/categories may also be useful.

Richer Persistence Model For Scalable Storage

Orleans' in-built persistence model is intended for storing relatively small blobs of state. For various reasons, users often want to store state of arbitrary, often increasing size in an efficient manner. We should create a model for extensible 'Distributed Collections', similar to ActorFx' Cloud Collections and Service Fabric's Reliable Collections (IDictinary<TKey,TValue>, IReliableQueue<T>). Our system should be extensible and include implementations for a few basic data structures, such as: queue, dictionary, set, and append-only list. We can also consider implementations of common CRDTs.

First-class Support for Programmatic Configuration

Configuration in Orleans is primarily XML driven and configuring the client or cluster using programmatic configuration is currently second-class and not obvious. We should adopt a fluent, programmable configuration model similar to what's available in Serilog.

Log.Logger = new LoggerConfiguration()
    .WriteTo.ColoredConsole()
    .WriteTo.RollingFile(@"C:\Log-{Date}.txt")
    .CreateLogger();

We should also consider making the configuration itself a POCO.

Aspect-Oriented Programming for Grains

Grain interceptors allow us to express cross-cutting concerns in a common place, improving consistency (& security) and reducing overall code. See #963 & #965.

CoreCLR Support

Work is well and truly under way thanks to an army of contributors, including @dVakulen, @galvesribeiro, @KodrAus, @pherbel, and @grahamehorner. See #368.

An extension or stepping stone to this may include using Roslyn APIs for metadata collection, the first phase of code generation. Currently we use Reflection for metadata collection, but the Roslyn approach would allow us to generate code based on textual source as well as compiled assemblies. @atillah instigated this idea.

Deep Service Fabric Integration

We should be able to host Orleans wherever we want and take full advantage of that platform. Service Fabric is a very desirable target and while we can already host Orleans on Service Fabric, we cannot yet take full advantage of the platform's offering. In particular, local data storage. See #1059.

Hot-update of Grain Implementations

Not sure how feasible this is in .NET or if it is truly desirable - currently we can just kill silos and upgrade them one-by-one.

Multi-cluster Support

Applications should be able to message grains for multiple clusters simultaneously. Currently they are limited to a single cluster each, largely due to static variables. We should allow this behavior from both outside & within a cluster. See #211.

Multi-grain Transactions

Grains in Orleans are effectively partitions, and cross-partition transactions are typically expensive, heavyweight operations. Nonetheless, cross-grain transactions are a desired features and can be useful in certain scenarios.

Broadcast Grains

For scenarios such as fault injection, metrics collection, cache management, and runtime configuration, it would be nice if we could send a message to all silos. This does not break location transparency. To a consumer, a broadcast grain operates just like a regular grain except that all methods must return void or Task. Alternatively we could allow broadcast grains to return any type and collect that on the client, returning an IEnumerable<Task<T>>. Maybe unidirectional communication is preferable here. The concept is not fully baked. See #610.

Grain Groups

I want to be able to implement certain distributed algorithms, such as Raft or Paxos atop Orleans. A Raft implementation would allow us to implement a disk-backed, replicated log. Thinking aloud, it could be nice if we could write code like this:

  // Get members of group with type IBandMember & id "meat trebuchet", (type, id) uniquely identifies a group.
  IGrainGroup<IBandMember> group = groupGrainFactory.GetGroupReference<IBandMember>("meat trebuchet");
  IList<IBandMember> groupGrains = await group.GetMembers();
  foreach (var grain in groupGrains)
  {
    await grain.SingMelody(); // May fail permanently if silo hosting this grain is inaccessible.
  }
  
  // Try adding a new member to the group, may return null if no new member could be activated - similar to malloc()...
  IBandMember newGrain = await group.TryAddMember(); // May fail if all nodes have a member of this group already.
  if (newGrain != null)
  {
    await newGrain.MakeBeautifulMusic(); // May fail permanently if silo hosting this grain is inaccessible.
    await group.TryRemoveMember(newGrain); // May return false if the member was not found in the group directory.
  }

This feature could be used to implement a group per (regular) grain or per tenant/service/whatever, which allows for a great deal of flexibility. Groups can use an eventually consistent directory just like regular grains.

Adding and removing members one-at-a-time allows us to create groups which are smaller than the current cluster. Eg in the Raft example we may want 3 or 5 nodes in a group for a replica set.

Is this a desireable feature? What is the best way to allow library writers to implement distributed algorithms like Raft on Orleans? Can we come up with a solution which fits nicely into Orleans' existing model? Can we stop unsuspecting users from entering shark-infested waters? See #610 for some previous discussion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment