Jennifer Owens
Jennifer Owens

Reputation: 4114

WCF - C# service should send results continuously

Since it's a long question, cliff notes come first.

Cliff notes:
One client sends input to several services and they keep on working and sending results until the client tells them to stop or they have reached a pre-set maximum number of results.

Do you know how one should go about implementing this, or do you have a C#-example for sth. like this? Is WCF & streaming the right toolset for this ? (Consider that results are custom objects, so it's not exactly the same as streaming a file)

More Detailed Problem Definition:

Situation:

I mention solutions A+B since I think they help explaining the problem:

Solution (A) - The slow non-parallel way:
1. Client sends input to one service.
2. Service initializes based upon the input.
3. Service processes all 1000 pieces of work
(results get added up(super fast btw) so the result of 1000 pieces of work has the same size as the result of one)
4. Service sends result to the client.
5. Client receives result and is happy

Solution (B) - Parallel faster way:
Let's say ten services, so we evenly split it up and each should process 100.

The problem is some services may be much faster than others so giving each the same number(100) is slower than necessary. Furthermore we can't split up according to an a priori speed-test since the speed of one service can change and some might even go down during processing, these are the reasons why I think the following would be best for my purpose.

Solution (C) - The way I would like to implement it:
Client sends out the same request to all services. (same request still implies that the task get's processed in parallel, parallelization is super easy for my problem 1000 pieces of work are so independent that doing 1000 times the "first" piece of work means we are done)

A service keeps working and sending results until it is told to stop or has processed 1000 pieces of work. One result gets sent for 10 pieces of work done. This means all services work parallel on the task and when the client has gotten a sum of 1000 results from all service replies combined it will send the stop signal. That means normally no single service should reach 1000, but with having 1000 we have covered the situation where there is only one service and we have a fail-safe to avoid infinite loops if the stop signal gets lost. (client neither needs to wait nor to be absolutely sure that the stop signal has reached a service)

Throwing away additional results beyond our goal of 1000 is fine.

(The alternative of instead making follow-up requests to services that have responded faster than others would come with the overhead of wasted time due to messages going back and forth and additional initializations. (Add. inits could be avoided but it would be complicated and you still have the other overhead))

I basically have solutions/would know how to implement A+B but I have no clue how I would go about realizing (C). How do you implement a client/service-architecture in C# where the service keeps sending results and doesn't just return one object/value? (Results are custom objects, btw) Does someone know about C#-example-code where sth. like that is implemented? Would streaming be the right way?

I've found the "writing a custom stream"-example but it seems like it's a pretty long way from there to what I want. (As a WCF-noob I can easily be wrong on that though.)

Upvotes: 3

Views: 1865

Answers (2)

Ladislav Mrnka
Ladislav Mrnka

Reputation: 364369

Streaming in the WCF doesn't work in the way that you will open a stream, return the stream to the client and service will still generate results to the stream. If you want to work this way you must go deeper and use sockets directly. In WCF the stream must be written prior to returning it from the operation (I tried to write to returned stream from other thread but it didn't work). Streaming in WCF is only for data transport.

I don't like any of your solution. I would try:

  1. Variant of B. But tasks will not be divided equally upfront. If you have 10 services and 1000 tasks you will send first 10 tasks (each to one service) only only after the service returns the result it will get another task. If tasks can be completed within reasonable time you will need only multiple async calls to services and wait for responses. If any service will not be able to complete task within defined timeout you will send the task to another service. If tasks can be completed fast you can send small batches instead of single task. If task completion takes long you will need duplex communication.
  2. Use Transactional Message queue - MSMQ. You client will generate 1000 messages to "producer queue" and services will take these messages one by one and process them. They will send results as message to another "consumer queue" where client will take results and process them (each result must have correlation to the task). Transactional queue will ensure that each task can be processed only by single service but if service fails or timeout of the transaction will occur the task will be available for processing in another service. MSMQ also offers some additional features like queue for faulty tasks etc. This is little bit advanced scenario. The main problem of this scenario can be limitation in size of messages (max. 4MB per message).

Edit:

Ok because of your clarification it looks like you need to send the same task to multiple services and task will just trigger series of the same computation on the same data. You can achieve it in this way:

  • Build a duplex service using Net.tcp binding
  • Service will implement service contract which will have operations to start computation and to stop computation (you can use IsInitiating and IsTerminating properties of OperationContract)
  • Service will do computation in separate thread started in start operation
  • Stop operation will abort computation thread
  • Client will implement callback contract to receive results from the service
  • Service will call the client callback when the processing thread has result (or multiple results) to send back

Here is an example of using duplex services with WsDualHttpBinding - don't use this binding in your scenario because it is much more complicated if you want to have single client to communicate with multiple same services over duplex HTTP.

Upvotes: 4

Frank Boyne
Frank Boyne

Reputation: 4570

What you describe as Solution (C) sounds like a good use for Asynchronous WCF. Some of these might help...

Synchronous and Asynchronous Operations
Asynchronous Programming Design Patterns
How to: Call WCF Service Operations Asynchronously

Upvotes: 0

Related Questions