ServiceStack message queue handling and Profiler - servicestack

I'm currently trying out the persistent mini profiler feature of ServiceStack and I'm currently having trouble registering profile information for my Redis Message Queue handlers.
A bit more background:
I have some regular REST api handlers which takes in a request, defers some updates of account information and replies OK back to the caller. These messages are posted to a Redis server, using the ServiceStack Redis MQ pattern. Therefore, the Redis message handling is registered as:
var redisFactory = new PooledRedisClientManager(redisClients);
var mqHost = new RedisMqServer(redisFactory, retryCount: 2);
var defaultThreadCount = 4;
mqHost.RegisterHandler<SomeDto>(m => this.ServiceController.ExecuteMessage(m), noOfThreads:defaultThreadCount);
mqHost.RegisterHandler<SomeOtherDto>(m => this.ServiceController.ExecuteMessage(m), noOfThreads:defaultThreadCount);
mqHost.Start();
And my messages are being handled properly too.
In a custom ServiceRunner I've enabled profiling of all requests in the BeforeEachRequest and added a custom Profiler step like this:
public override void BeforeEachRequest(IRequest requestContext, T request)
{
Profiler.Start();
using (Profiler.StepStatic("Executing handler"))
{
base.BeforeEachRequest(requestContext, request);
}
}
All my HTTP REST requests are making it to the SQL tables, but none of the MQ handler calls are registered. And I'm 100% confident that the handlers are indeed being executed, since the result of that execution is stored in a MongoDB collection.
Anything I'm missing?
-- EDIT --
I forgot to mention that this project is indeed hosted via an ASP.NET application. The AppHost is initialized in Global.asax App_Start - I just found it more convenient to have "before request" handing in a custom service runner rather than the ASP.NET Begin_Request handler.

I have a similar problem with a self hosted server. The problem is that the profiler uses HttpContext.Current to store the profiling results. If there is no valid context it does not know which profiling 'session' to add the results to.
It is possible to implement your own ProfilingProvider by setting Profile.Settings.ProfilingProvider, but, unless I am missing something, it will be tricky (if not impossible) to implement this properly in an Async environment with the current IProfilerProvider interface.

I wrote a very simple and naive provider which you can use for profiling. This will not pick up any of the steps that ServiceStack already adds by default, but it might still be useful for your own debugging.
Example use:
Profiler.Settings.ProfilerProvider = RequestProfilerProvider.Instance;
PreRequestFilters.Add((req, res) => RequestProfiler.Start(req));
GlobalRequestFilters.Add((req, res, dto) => {
var profiler = RequestProfiler.GetProfiler(req);
using (profiler.Step("Very slow step")) {
Thread.Sleep(1000);
}
});
GlobalResponseFilters.Add((req, res, dto) => RequestProfiler.Stop(req));

Related

Servicestack Multitenancy dynamic plugins

We are moving from an on premise-like application to a multi tenant cloud application.
for my web application we made a very simple interface based on IPlugin, to create a plugin architecture. (customers can have/install different plugins)
public interface IWebPlugin : IPlugin
{
string ContentBaseUrl { set; get; }
}
We have some plugins that would normally be loaded in on startup. Now i'm migrating the code to load at the beginning of a request (the Register function is called on request start), and scope everything inside this request.
It's not ideal but it would bring the least impact on the plugin system for now.
I could scope the Container by making an AppHost child container which would stick to the request:
Container IHasContainer.Container
{
get
{
if (HasStarted)
return ChildContainer;
return base.Container;
}
}
public Container ChildContainer
{
get { return HttpContext.Current.Items.GetOrAdd<Container>("ChildContainer", c => Container.CreateChildContainer()); }
}
problem case
Now im trying to make plugins work that actually add API services.
appHost.Routes.Add<GetTranslations>("/Localizations/translations", ApplyTo.Get);
But this service is unreachable (and not visible in metadata). How do i make it reachable?
I see you execute the following in ServiceController AfterInit. Re-executing this still wouldnt make it work.
//Copied from servicestack repo
public void AfterInit()
{
//Register any routes configured on Metadata.Routes
foreach (var restPath in appHost.RestPaths)
{
RegisterRestPath(restPath);
//Auto add Route Attributes so they're available in T.ToUrl() extension methods
restPath.RequestType
.AddAttributes(new RouteAttribute(restPath.Path, restPath.AllowedVerbs)
{
Priority = restPath.Priority,
Summary = restPath.Summary,
Notes = restPath.Notes,
});
}
//Sync the RestPaths collections
appHost.RestPaths.Clear();
appHost.RestPaths.AddRange(RestPathMap.Values.SelectMany(x => x));
appHost.Metadata.AfterInit();
}
solution directions
Is there a way i could override the route finding? like extending RestHandler.FindMatchingRestPath(httpMethod, pathInfo, out contentType);
Or could i restart the path compilation/caching? (would be enough for now that the service would be reachable tenant wide )
All configuration in ServiceStack should be contained within AppHost.Configure() and remain immutable thereafter. It's not ThreadSafe to modify ServiceStack's Static Configuration at runtime like trying to modify registered routes or Service Metadata which needs to be registered once at StartUp in AppHost.Configure().
It looks as though you'll need to re-architect your solution so all Routes are registered on Startup. If it helps Plugins can implement IPreInitPlugin and IPostInitPlugin interfaces to execute custom logic before and after Plugins are registered. They can also register a appHost.AfterInitCallbacks to register custom logic after ServiceStack's AppHost has been initialized.
Not sure if it's applicable but at runtime you can "hi-jack Requests" in ServiceStack by registering a RawHttpHandler or a PreRequestFilter, e.g:
appHost.RawHttpHandlers.Add(httpReq =>
MyShouldHandleThisRoute(httpReq.PathInfo)
? new CustomActionHandler((req, res) => {
//Handle Route
});
: null);
Simple answer seems to be, no. The framework wasn't build to be a run-time plugable system.
You will have to make this architecture yourself on top of ServiceStack.
Routing solution
To make it route to these run-time loaded services/routes it is needed to make your own implementation.
The ServiceStack.HttpHandlerFactory checks if a route exist (one that is registered on init). so here is where you will have to start extending. The method GetHandlerForPathInfo checks if it can find the (service)route and otherwise return a NotFoundHandler or StaticFileHandler.
My solution consists of the following code:
string contentType;
var restPath = RestHandler.FindMatchingRestPath(httpMethod, pathInfo, out contentType);
//Added part
if (restPath == null)
restPath = AppHost.Instance.FindPluginServiceForRoute(httpMethod, pathInfo);
//End added part
if (restPath != null)
return new RestHandler { RestPath = restPath, RequestName = restPath.RequestType.GetOperationName(), ResponseContentType = contentType };
technically speaking IAppHost.IServiceRoutes should be the one doing the routing. Probably in the future this will be extensible.
Resolving services
The second problem is resolving the services. After the route has been found and the right Message/Dto Type has been resolved. The IAppHost.ServiceController will attempt to find the right service and make it execute the message.
This class also has init functions which are called on startup to reflect all the services in servicestack. I didn't found a work around yet, but ill by working on it to make it possible in ServiceStack coming weeks.
Current version on nuget its not possible to make it work. I added some extensibility in servicestack to make it +- possible.
Ioc Solution out of the box
For ioc ServiceStack.Funq gives us a solution. Funq allows making child containers where you can register your ioc on. On resolve a child container will, if it can't resolve the interface, ask its parent to resolve it.
Container.CreateChildContainer()

ServiceStack Redis Messaging - IMessage?

I would like to use Redis to invoke a service operation on my Service Stack service.
I have created a simple DTO as the message request, and am registering the message service as per the demo pages:
var messageService = m_Container.Resolve<RedisMqServer>();
messageService.RegisterHandler<SubscribeAddressRequest>(x => ServiceController.ExecuteMessage(x) );
messageService.Start();
ServiceStack actually receives these messages, but I get the following error (from my Container):
No component for supporting the service ServiceStack.Messaging.IMessage was found.
This is very odd, why is ServiceStack asking for a dependency to be injected as an IMessage? I have not registered any providers for an IMessage so I understand that this would fail, but I do not see any providers. I am registering the following types:
string[] RedisHosts = new string[] { (string)ConfigurationManager.AppSettings["RedisHost"] };
container.Register(
Component.For<IRedisClientsManager>().ImplementedBy<PooledRedisClientManager>().DependsOn(new { poolSize = 1000, poolTimeOutSeconds = 1, readWriteHosts = RedisHosts }),
Component.For<RedisMqServer>(),
Component.For<IMessageQueueClient>().UsingFactoryMethod((k, c) =>
{
return k.Resolve<RedisMqServer>().CreateMessageQueueClient();
})
);
It looks like this is an issue with the Container you're using, I'm not sure why it's asking for this, it may have something to do with your IOC's auto bootstrap scanning process, but it's not something you'd want resolved from the IOC. To help with the investigation, the type in the RegisterHandler callback is of IMessage<T>, e.g:
messageService.RegisterHandler<SubscribeAddressRequest>(x // <- IMessage<T>
I have found the cause of the issue, which is that my IoC Container (Castle Windsor) is injecting the RequestFilter and ResponseFilter on a RedisMqServer with a dynamic Func with the aim of resolving an IMessage from the container (when using TypedFactoryFacility).
This is because of the delegate-factory which is part of the TypedFactoryFacility (I usually use interface-factories).
I got round this by disabling the automatic enabling of the Castle Windsor delegate-factory when using the Typed Factory Facility:
Remove components in Castle Windsor 3

Global request/response interceptor

What would be the easiest way to setup a request/response interceptor in ServiceStack that would execute for a particular service?
A request filter (IHasRequestFilter) works fine but a response filter (IHasResponseFilter) is not triggered if the service returns non 2xx status code. I need to retrieve the status code returned by the method as well as the response DTO (if any).
A custom ServiceRunner and overriding the OnBeforeExecute and OnAfterExecute methods seems to work fine but I find it pretty intrusive as the service runner need to be replaced for the entire application and I couldn't find a way clean way to isolate per functionality the tasks that need to be executed in those methods.
Is there some extension point in ServiceStack that I am missing that would allow me to execute some code before each service method and after each service method? A plugin would be ideal but how can I subscribe to some fictitious BeforeExecute and AfterExecute methods that would allow me to run some custom code?
UPDATE:
Just after posting the question I found out that global response filters are executed no matter what status code is returned by the service which is exactly what I needed. So one last question: Is it possible to retrieve the service type that will handle the request in a request filter? I need to check whether this service is decorated by some custom marker attribute.
I have found out a solution to my question about how to retrieve the service type in a custom request/response filter:
appHost.RequestFilters.Add((req, res, requestDto) =>
{
var metadata = EndpointHost.Metadata;
Type serviceType = metadata.GetServiceTypeByRequest(requestDto.GetType());
...
}
A custom ServiceRunner and overriding the OnBeforeExecute and OnAfterExecute methods seems to work fine but I find it pretty intrusive as the service runner need to be replaced for the entire application
Quick note, you can opt-in and choose only what requests should use a custom service runner, e.g:
public override IServiceRunner<TRequest> CreateServiceRunner<TRequest>(
ActionContext actionContext)
{
return useCustomRunner(actionContext.RequestType)
? new MyServiceRunner<TRequest>(this, actionContext)
: base.CreateServiceRunner<TRequest>(actionContext);
}
IHttpRequest has OperationName. I think thats what you are after.

What is lost from the stack when a service handles async messages in ServiceStack?

I'm using the messaging feature of ServiceStack for back end transactions I expect to involve database locks where consistency is very important.
I've registered handlers as explained in the documentation:
mqHost.RegisterHandler<Hello>(m => {
return this.ServiceController.ExecuteMessage(m);
});
I've noticed the Filters don't get called. Presumably, they're really "Http" filters similar to MVC. So it makes sense they're ignored.
How does Authorization work with message handlers, is it ignored too?
And as I want to keep my async services internal, and always async, is there any benefit in making them inherit from ServiceBase at all?
As I'm thinking of creating another envelop layer between IMessage and Body for some Identity data that can be passed from my public services out of AuthSession and to the Async service.

Fire and forget with ServiceStack's AsyncServiceBase

I have following service
public class AppService : AsyncServiceBase<EvaluateStock>
{
public IBus Bus { get; set; }
public override object ExecuteAsync(EvaluateStock request)
{
// this will block the incoming http request
// unitl task is completed
// long computation
// Bus.Publish(result)
}
}
which gets called by different consumers following way
POST
http://srv1/app/json/asynconeway/EvaluateStock
Using asynconeway I was assuming that it will allow me to achieve fire and forget as WCF does with IsOneWay. But seems is not the case.
Do I miss something ?
AsyncServiceBase has been deprecated as ExecuteAsync is now in ServiceBase which is what gets called when a request is made to /asynconeway/XXX pre-defined endpoint.
Rather than overriding ExecuteAsync the recommended approach is to implement IMessageFactory which is what gets called if an IMessageFactory has been registered in the AppHost IOC. If an IMessageFactory wasn't registered than it just gets executed Sync - at which point if you still wanted it non-blocking you would override it. The impl for ExecuteAsync is at:
// Persists the request into the registered message queue if configured,
// otherwise calls Execute() to handle the request immediately.
//
// IAsyncService.ExecuteAsync() will be used instead of IService.Execute() for
// EndpointAttributes.AsyncOneWay requests
public virtual object ExecuteAsync(TRequest request)
{
if (MessageFactory == null)
{
return Execute(request);
}
BeforeEachRequest(request);
//Capture and persist this async request on this Services 'In Queue'
//for execution after this request has been completed
using (var producer = MessageFactory.CreateMessageProducer()) {
producer.Publish(request);
}
return ServiceUtils.CreateResponseDto(request);
}
IMessageFactory (client)/IMessageService (server) is apart of ServiceStack's Messaging API which allows you to publish messages for deferred execution later. See the Redis and Messaging wiki for an example of an end-to-end solution that uses the built-in Redis IMessageService. There are also InMemory and RCon IMesssageService's available and it should be easy to create your own as well.
Future Async support
There is also an async branch that has ServiceStack running on IHttpAsyncHandler and already has a functional alpha build available for you to try at: ServiceStack-v4.00-alpha.zip
With this change ServiceStack supports Task<> as a return type on services. You only need to register the Task<> plugin. To see a full example look at this integration test.

Resources