/parcellerStub

Just a stub for sharing some code

Primary LanguageC#MIT LicenseMIT

parcellerStub

Just a stub for quickly sharing some code.

Not compilable, as there are plenty of dependencies that I'm not ready to share, however the parcelling logic is visible and may serve as inspiration ;)

The RequestParceller related classes provide basic WCF parcelling request services. Use these classes to reduce WCF chattiness by bundling multiple, related WCF service calls from multiple threads into a single call.

IMPORTANT: By default, logging to log4net is disabled. To enable logging set the UseLog4Net property to true. The reason for this default configuration is that a common use for this class is parcelling log events that will be sent to a remote viewer via WCF. If we log in this class, we will trigger an infinite cascade of logging events and will degrade system performance greatly. If the parceller is not forwarding log events, it is safe to set this property to True

To the client code, the call appears to be executed independently (the parcelling is fully hidden from client code). The parcelling policy is bounded by two conditions: a maximum parcel size or a parcel-idle timeout. Whenever any of the two conditions are reached, the parcel is sent to the WCF service as a single call

The provided WCF service inteface must expose a WCF operation that can receive a collection of multiple DTO (data-transmission-objects) instances (one for each parcelled request).

The classes are abstract. A concrete implementation of the class must be supplied, overriding the SendParcelToWCFService() method. The SendParcelToWCFService() method must call the WCF service by means of the _service member, passing the DTO objects available in the parcelled tuples. After the WCF call is completed, the overriden SendParcelToWCFService() method must set the results of the WCF call into the `TaskCompletionSource (TCO tuple member) objects in the corresponding parcelled tuples. This action will resume all the multiple, individual calls that are awaiting for their requests to be fulfilled.

Usage Example:

public class AudioHashParceller : ParcellerBase<AudioHashDTO, AudioHashResultDTO, IAudioHashService> {
   protected async override Task SendParcelToWCFService(Parcel parcel, CancellationToken cancelToken) {
         // obtain a list of the DTO objects stored in the parcel tuples
         List<AudioHashDTO> hashes = parcel.Select(item => item.DTO).ToList();
         List<AudioHashResultDTO> results = await _service.ProcessMultipleHashes(hashes)
                                                          .ConfigureAwait(false);
         if( results.Count != hashes.Count )
            throw new Exception("expecting the same amount of results as inputs");
         for( int i = 0; i < results.Count; i++ )
            parcel[i].TCS.SetResult(results[i]);  // resume the method awaiting this result
      }
   }
   
    ...
   
   // Create a parceller that will ship (transmit) whenever 3 items are parcelled by different threads, or 1
   // second has elapsed from the last item bundled in the active parcel
   
   var audioHashParceller = new AudioHashParceller(wcfSevice,
                                                   maxParcelSize: 3,
                                                  idleShipTimeout: TimeSpan.FromSeconds(1.0));
   // Invoke the service
   AudioHashResultDTO result1 = await audioHashParceller.Request(GetAudioHashDTO());