Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Messaging and Redis

mythz edited this page · 2 revisions

  1. Getting Started

    1. Creating your first project
      1. Create Service from scratch
    2. Your first webservice explained
    3. ServiceStack's new API Design
    4. Designing a REST-ful service with ServiceStack
    5. Example Projects Overview
    6. Learning Resources
  2. Reference

    1. Order of Operations
    2. The IoC container
    3. Configuration and AppSettings
    4. Metadata page
    5. Rest, SOAP & default endpoints
    6. SOAP support
    7. Routing
    8. Service return types
    9. Customize HTTP Responses
    10. Plugins
    11. Validation
    12. Error Handling
    13. Security
    14. Debugging
    15. JavaScript Client Library (ss-utils.js)
  3. Clients

    1. Overview
    2. C#/.NET client
    3. Add ServiceStack Reference
      1. C# Add Reference
      2. F# Add Reference
      3. VB.NET Add Reference
      4. Swift Add Reference
      5. Java Add Reference
    4. Silverlight client
    5. JavaScript client
      1. Add TypeScript Reference
    6. Dart Client
    7. MQ Clients
  4. Formats

    1. Overview
    2. JSON/JSV and XML
    3. ServiceStack's new HTML5 Report Format
    4. ServiceStack's new CSV Format
    5. MessagePack Format
    6. ProtoBuf Format
  5. View Engines

    1. Razor & Markdown Razor
    2. Markdown Razor
  6. Hosts

    1. IIS
    2. Self-hosting
    3. Messaging
    4. Mono
  7. Security

    1. Authentication/authorization
    2. Sessions
    3. Restricting Services
  8. Advanced

    1. Configuration options
    2. Access HTTP specific features in services
    3. Logging
    4. Serialization/deserialization
    5. Request/response filters
    6. Filter attributes
    7. Concurrency Model
    8. Built-in caching options
    9. Built-in profiling
    10. Form Hijacking Prevention
    11. Auto-Mapping
    12. HTTP Utils
    13. Virtual File System
    14. Config API
    15. Physical Project Structure
    16. Modularizing Services
    17. ServiceStack Integration
    18. Embedded Native Desktop Apps
    19. Auto Batched Requests
    20. Versioning
  9. Server Events

    1. Overview
    2. JavaScript Client
    3. C# Server Events Client
    4. Redis Server Events
  10. Encrypted Messaging

    1. Overview
    2. Encrypted Client
  11. Plugins

    1. Auto Query
    2. Server Sent Events
    3. Swagger API
    4. Postman
    5. Request logger
    6. Sitemaps
    7. Cancellable Requests
    8. CorsFeature
  12. Tests

    1. Testing
    2. HowTo write unit/integration tests
  13. ServiceStackVS

    1. Install ServiceStackVS
    2. Add ServiceStack Reference
    3. AngularJS App Template
    4. ReactJS App Template
  14. Other Languages

    1. FSharp
      1. Add ServiceStack Reference
    2. VB.NET
      1. Add ServiceStack Reference
    3. Swift
      1. Swift Add Reference
    4. Java
      1. Add ServiceStack Reference
      2. Android Studio & IntelliJ
      3. Eclipse
  15. Deployment

    1. Deploy Multiple Sites to single AWS Instance
      1. Simple Deployments to AWS with WebDeploy
    2. Advanced Deployments with OctopusDeploy
  16. Install 3rd Party Products

    1. Redis on Windows
    2. RabbitMQ on Windows
  17. Use Cases

    1. Single Page Apps
      1. HTML, CSS and JS Minifiers
    2. Azure
      1. Connecting to Azure Redis via SSL
    3. Logging
    4. Bundling and Minification
    5. NHibernate
  18. Performance

    1. Real world performance
  19. How To

    1. Sending stream to ServiceStack
    2. Setting UserAgent in ServiceStack JsonServiceClient
    3. ServiceStack adding to allowed file extensions
    4. Default web service page how to
  20. Future

    1. Roadmap
Clone this wiki locally

MQ Examples

The Reusability ServiceStack.UseCase contains a good introductory demo of using MQ's(message-queues) in ServiceStack where the same services can be called via Web Service or via MQ. Using MQ's provide instant response times, in addition to reliable and durable execution of your services.

The SMessage Service

The SMessage Service shows an example of dividing a service into multiple subtasks and dispatching them for instant response times and parallel processing of blocking operations without needing any multi-threading code in your application logic, e.g:

public object Any(SMessage request)
{
    var sw = Stopwatch.StartNew();
    if (!request.Defer) //Process sequentially or Defer execution
    {
        //Executes service sequentially: N+1 service calls, will timeout if N is too big
        var results = new List<SMessageReceipt>();
        results.AddRange(Email.Send(request));
        results.AddRange(FacebookR.Send(request));
        results.AddRange(Twitter.Send(request));
        Db.InsertAll(results);
    }
    else
    {
        //Split service into smaller tasks and defers messages in MQ broker for processing in parallel
        Email.CreateMessages(request).ForEach(MessageProducer.Publish);
        Facebook.CreateMessages(request).ForEach(MessageProducer.Publish);
        Twitter.CreateMessages(request).ForEach(MessageProducer.Publish);
    }

    return new SMessageResponse {
        TimeTakenMs = sw.ElapsedMilliseconds,
    };
}

Process each service concurrently without holding up the processing of other tasks

Another benefit of dispatching messages into multiple sub tasks is if the Email API is slow, it doesn't hold up the processing of the other tasks which are all running concurrently in the background each individually processing messages as fast as they can.

Easily Parallelize and Multiply your services throughput

The RedisMqServer also supports spawning any number of background threads for individual requests, so if Posting to twitter was an IO intensive operation you can double the throughput by simply assigning 2 or more worker threads, e.g:

mqService.RegisterHandler<PostStatusTwitter>(ServiceController.ExecuteMessage, noOfThreads:2);
mqService.RegisterHandler<CallFacebook>(ServiceController.ExecuteMessage);
mqService.RegisterHandler<EmailMessage>(ServiceController.ExecuteMessage);

Redis MQ Client / Server

A redis-based message queue client/server that can be hosted in any .NET or ASP.NET application. All Redis MQ Hosts lives in the ServiceStack.Server project and brings the many benefits of using a Message Queue.

PM> Install-Package ServiceStack.Server

RedisMqServer

Works by using a background thread for each service. This allows you to process messages from different services concurrently. Recommended if you have any long-running services so other services can still run in parallel.

Major kudos goes to Redis which thanks to its versatility, has Pub/Sub and Lists primitives that makes implementing a Queue trivial.

MQ Architecture in ServiceStack

The logical architecture of how a MQ Publisher and MQ Host works together in ServiceStack:

ServiceStack MQ Client Architecture

Easily testable and swappable

All MQ implementations share the same IMessageService so they're easily swappable and testable. There is also an InMemoryTransientMessageService available, useful for development & testing.

These versions already sports the major features you've come to expect from a MQ:

  • Each service maintains its own Standard and Priority MQ's
  • Automatic Retries on messages generating errors with Failed messages sent to a DLQ (Dead Letter Queue) when its Retry threshold is reached.
  • Each message can have a ReplyTo pointing to any Queue, alternatively you can even provide a ServiceStack endpoint URL which will send the response to a Web Service instead. If the web service is not available it falls back into publishing it in the default Response Queue so you never lose a message! MQ/Web Services that don't return any output have their Request DTOs sent to a rolling Out queue which can be monitored by external services (i.e. the publisher/callee) to determine when the request has been processed.

Re-use your existing Web Services!

Although you can host RedisMqServer in any ASP.NET web app, the benefit of hosting inside ServiceStack is that your web services are already capable of processing Redis MQ messages without any changes required since they're already effectively designed to work like a Message service to begin with, i.e. C# POCO-in -> C# POCO-out.

This is another example of how ServiceStack's prescribed DTO-first architecture continues to pay dividends since each web service is a DI clean-room allowing your C# logic to be kept pure as it only has to deal with untainted POCO DTOs, allowing your same web service to be re-used in: SOAP, REST (JSON,XML,JSV,CSV,HTML) web services, view models for dynamic HTML pages and now as a MQ service!

Future Roadmap

Eventually (based on feedback) there will be posts/documentation/examples forthcoming covering how to use it, in the meantime you can Check out the Messaging API to see how simple it is to use. To see some working code showing some of the capabilities listed above, view the tests.

Example

Hooking up a basic send/reply example is as easy as:

//DTO messages:
public class Hello { public string Name { get; set; } }
public class HelloResponse { public string Result { get; set; } }

var redisFactory = new PooledRedisClientManager("localhost:6379");
var mqHost = new RedisMqServer(redisFactory, retryCount:2);

//Server - MQ Service Impl:
mqHost.RegisterHandler<Hello>(m =>
    new HelloResponse { Result = "Hello, " + m.GetBody().Name });
mqHost.Start();

...

//Client - Process Response:
mqHost.RegisterHandler<HelloResponse>(m => {
    Console.WriteLine("Received: " + m.GetBody().Result);
});
mqHost.Start();

...

//Producer - Start publishing messages:
var mqClient = mqHost.CreateMessageQueueClient();
mqClient.Publish(new Hello { Name = "ServiceStack" });

Redis

Note: This is a quote of a google group topic to provide more information about ServiceStack and Redis until more documentation/examples are added.

Redis is a NoSQL datastore that runs as a network server. To start it you need to run an instance of redis-server either locally or remotely accessible.

Probably will help to understand the background concepts behind Redis so you can get a better idea of how it works. A good start is this brief overview of Redis which also includes as how you can install it: http://stackoverflow.com/a/2760282/85785

The RedisMQ Host is in ServiceStack.Redis project which is a dependency on the ServiceStack NuGet package (if that's how you have ServiceStack installed).

At the moment the there is not much documentation available and will look to improve this after I get the next release of ServiceStack out.

You can look through the tests to get a better idea of how it works, especially the Request/Reply Example

Basically the RedisMQ runs as a separate background thread you start from inside your AppHostHttpListenerBase.

For duplex communication each client and server will require its own AppHostHttpListenerBase + RedisMQ Host, although unless your server is going to call HTTP services on the client you don't need it and you can use BasicAppHost

Here is a simple example of a client/server with HTTP + RedisMQ enabled on the server, and just RedisMQ on the client:

Shared.cs:

using System;

namespace TestMqShared
{
    public class Hello { 
        public string Name { get; set; } 
    }
    public class HelloResponse { 
        public string Result { get; set; } 
    }
}

Server.cs:

using System;
using Funq;
using ServiceStack;
using ServiceStack.Messaging.Redis;
using ServiceStack.Redis;
using ServiceStack.Testing;
using TestMqShared;

namespace TestMq
{
    //Server
    public class HelloService : Service 
    {
        public object Any(Hello req) 
        { 
            return new HelloResponse { Result = "Hello, " + req.Name }; 
        }
    }

    public class ServerAppHost : AppHostHttpListenerBase 
    {
        public ServerAppHost() : base("Test Server", typeof(HelloService).Assembly) {}

        public override void Configure(Container container) 
        {
            base.Routes
                .Add<Hello>("/hello")
                .Add<Hello>("/hello/{Name}");

            var redisFactory = new PooledRedisClientManager("localhost:6379");
            container.Register<IRedisClientsManager>(redisFactory); // req. to log exceptions in redis
            var mqHost = new RedisMqServer(redisFactory, retryCount:2);

            //Server - MQ Service Impl:

            //Listens for 'Hello' messages sent with 'mqClient.Publish(new Hello { Name = "Client" });'
            mqHost.RegisterHandler<Hello>(this.ServiceController.ExecuteMessage);
            mqHost.Start(); //Starts listening for messages
        }
    }

    class MainClass
    {
        public static void Main(string[] args)
        {
            var serverAppHost = new ServerAppHost();
            serverAppHost.Init(); 
            serverAppHost.Start("http://localhost:1400/");
            Console.WriteLine("Server running.  Press enter to terminate...");
            Console.ReadLine(); //Block the server from exiting (i.e. if running inside Console App)
        }
    }
}

Client.cs:

using System;
using Funq;
using ServiceStack;
using ServiceStack.Messaging;
using ServiceStack.Messaging.Redis;
using ServiceStack.Redis;
using ServiceStack.Testing;
using TestMqShared;

namespace TestMqCli
{
    class MainClass
    {
        public static void Main(string[] args)
        {
            var redisFactory = new PooledRedisClientManager("localhost:6379");
            var mqServer = new RedisMqServer(redisFactory, retryCount:2);

            //Client - MQ Service Impl:
            //Listens for 'HelloResponse' as returned by the 'Hello' service on the server
            mqServer.RegisterHandler<HelloResponse>(m => {  
                Console.WriteLine("Received: " + m.GetBody().Result);  //Fired 
                // See comments below
                // m.Options = (int)MessageOption.None;
                return null;
            });

            //or to call an existing service with:
            //mqServer.RegisterHandler<HelloResponse>(m =>   
            //    this.ServiceController.ExecuteMessage(m));

            mqServer.Start(); //Starts listening for messages

            var mqClient = mqServer.CreateMessageQueueClient();
            mqClient.Publish(new Hello { Name = "Client 1" });

            Console.WriteLine("Client running.  Press any key to terminate...");
            Console.ReadLine(); //Block the server from exiting (i.e. if running inside Console App)
        }
    }
}

The first RedisMQ host listening to the Hello message (i.e. the server) will process the message.

When the server returns a 'HelloResponse' message it gets put on the 'HelloResponse' Inbox Queue and the first RedisMQ Host listening to the 'HelloResponse' message (i.e. Client) will have their callback fired.

Note that the HelloResponse will get put back on a 'transient' message queue, mq.HelloResponse.outq with a maximum message limit of 100 (by default). You can subscribe to this queue to get a notification and do further processing, such as recording the number of messages handled. Or you can clear the message NotifyOneWay option to prevent this.

Request + Reply MQ Pattern

However MQ's are normally used for async OneWay messages as any client host listening to 'HelloResponse' could receive the response message, and only 1 will, which is not guaranteed to be the client that sent the original message. For this reason you want to make use of the ReplyTo field of the Message for Request/Reply responses.

var uniqueCallbackQ = "mq:c1" + ":" Guid.NewGuid().ToString("N");
var clientMsg = new Message<Hello>(new Hello { Name = "Client 1" }) {
   ReplyTo =  uniqueCallbackQ
};
mqClient.Publish( clientMsg );
var response = mqClient.Get(clientMsg).ToMessage<HelloResponse>();  //Blocks thread on client until reply message is received

Note: The ReplyTo callback url could also be a ServiceStack endpoint that expects a 'HelloResponse' e.g.

var clientMsg = new Message<Hello>(new Hello { Name = "Client 1" }) {
   ReplyTo =  "http://clienthost:82/helloresponse"
};

In this case the server wont put the response message on the back on the MQ and will instead send the response directly to your client web service host.

There's a few MQ concepts covered above here, I invite you to do your own reading on MQ's in general as it works a little different to normal request/reply web services.

See Also: Redis Commands (PDF)

Something went wrong with that request. Please try again.