Question

Apologies if this seems like I want my problem saved for me, but I had stumbled upon stact sometime ago and it seems it would be a handy library to get familiar with, and I think it would work well for the problem at hand.

I had a look at the source code, and there's a lot in there! :) don't know where to start.

What I need is a component (Actor?) that would periodically send async web requests and store the results locally (some parsing of the results will happen first). Other threads will ask for the results at different times.

From what I can see, I will need a Scheduler, a Fiber and an Channel to handle returning the results to whoever requests them. Something along the lines of:

private static readonly ConcurrentDictionary<Uri, ServerLoad> ServerLoads = new ConcurrentDictionary<string, ServerLoad>();
public Channel<Request<IEnumerable<ServerLoad>>> ServerLoadChannel { get; private set; 
public LoadRetriever(Inbox inbox, Fiber fiber, Scheduler scheduler, ILoadBalancerConfiguration config)
{
    this.inbox = inbox;
    this.fiber = fiber;
    this.scheduler = scheduler;

    this.scheduler.Schedule(
        0,
        config.FetchIntervalMilliSecs,
        fiber,
        () =>
            {
                foreach (var server in config.Servers)
                {
                    // need someway to send async web request to url in
                    // server.LoadRetrievalAddress and save/update result
                    // in ServerLoads dictionary
                }
            });

    this.ServerLoadChannel = new ConsumerChannel<Request<IEnumerable<ServerLoad>>>(this.fiber, 
        request => request.Respond(ServerLoads.Values));
}

}

This is all theoretical for the time being, and might be completly wrong, the main problem I am having is doing the async requests (WebClient.DownloadStringAsync() and DownloadStringCompleted). Something that does the opposite of AsyncResultChannel

Any tips/examples/push in the right direction would be appreciated!

(tried to create a tag for stact but my reputation is not good enough :S)

Was it helpful?

Solution

Well, there are a few things here. First, you should create a class that is an Actor, using:

public class MyServerCoordinator : Actor 
{}

Then, that actor will load the configuration and create another actor for each server instance. This will allow each configured server to have it's information retrieved on its own schedule.

Then you'll need to create an ActorFactory for each type, using:

var factory = ActorFactory.Create((i,f,s) => new MyServerCoordinator(i,f,s));
var actor = factory.GetActor();

With message passing, you should create a message class for each message you want to exchange between actors instead of using raw CLR types.

Also, in the constructor of each actor, you can setup a Receive loop for handling requests separately of the scheduled updates. Actors can communicate with each other by sending Requests, which include a response channel to the sender. This will allow the per-server actors to talk back to the coordinator.

MyServerCoordinator(Inbox inbox)
{
    inbox.Loop(loop =>
    {
        loop.Receive<Request<ServerData>>(request =>
        {
            request.Respond(new ServerDataResult(_myCurrentValue)); 
            loop.Continue();
        });
    }
}

Each actor has its own fiber, so there is no need to use concurrent collection types or any locking mechanisms. The actor model handles concurrency via message passing, so semaphores and such are not used.

You'll also want to check out some of the samples in the unit tests to see how to interact with the actor from non-actor code using the AnonymousActor.New() inline declaration.

OTHER TIPS

A good place to start would likely be with Cashbox https://github.com/Cashbox/Cashbox. I wrote it with an older version of Stact but most of the concepts should port over just fine.

https://github.com/Cashbox/Cashbox/blob/master/src/Cashbox/Engines/FileStorageEngine.cs is where all the actor-based magic happens. https://github.com/Cashbox/Cashbox/blob/master/src/Cashbox/Engines/FileStorageEngine.cs#L182 is all about making a request and waiting for a response.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top