Note that there are some explanatory texts on larger screens.

plurals
  1. POWorkflow services scalability issue
    primarykey
    data
    text
    <p>I'm currently experiencing some issues with workflow services. They work fine if I start 4, 5 in short sequence, but if I increase this value (starting from ~10) then I get the following exception:</p> <blockquote> <p>This channel can no longer be used to send messages as the output session was auto-closed due to a server-initiated shutdown. Either disable auto-close by setting the DispatchRuntime.AutomaticInputSessionShutdown to false, or consider modifying the shutdown protocol with the remote server.</p> </blockquote> <p>I think that the problem is in the way I create proxies. I use the following code to provide proxies, attempting to reuse existing ones:</p> <pre><code>public abstract class ProxyProvider&lt;TService&gt; where TService : class { /// &lt;summary&gt; /// Static reference to the current time provider. /// &lt;/summary&gt; private static ProxyProvider&lt;TService&gt; current = DefaultProxyProvider.Instance; private TService service; /// &lt;summary&gt; /// Gets or sets the current time provider. /// &lt;/summary&gt; /// &lt;value&gt; /// The current time provider. /// &lt;/value&gt; public static ProxyProvider&lt;TService&gt; Current { get { return ProxyProvider&lt;TService&gt;.current; } set { if (value == null) { throw new ArgumentNullException("value"); } ProxyProvider&lt;TService&gt;.current = value; } } /// &lt;summary&gt; /// Resets to default. /// &lt;/summary&gt; public static void ResetToDefault() { ProxyProvider&lt;TService&gt;.current = DefaultProxyProvider.Instance; } /// &lt;summary&gt; /// Loads the proxy. /// &lt;/summary&gt; /// &lt;param name="forceNew"&gt;if set to &lt;c&gt;true&lt;/c&gt; [force new].&lt;/param&gt; /// &lt;returns&gt;The instance of the proxy.&lt;/returns&gt; public virtual TService Provide(bool forceNew = false) { if (forceNew || !this.IsInstanceValid()) { this.service = this.CreateInstance(); return this.service; } return this.service; } /// &lt;summary&gt; /// Internals the load. /// &lt;/summary&gt; /// &lt;returns&gt;The new created service.&lt;/returns&gt; protected abstract TService CreateInstance(); private bool IsInstanceValid() { var instance = this.service as ICommunicationObject; if (instance == null) { return false; } return instance.State != CommunicationState.Faulted &amp;&amp; instance.State != CommunicationState.Closed &amp;&amp; instance.State != CommunicationState.Closing; } /// &lt;summary&gt; /// Defines the default &lt;see cref="ProxyProvider&amp;lt;TService&amp;gt;"/&gt; which uses the System DateTime.UtcNow value. /// &lt;/summary&gt; private sealed class DefaultProxyProvider : ProxyProvider&lt;TService&gt; { /// &lt;summary&gt; /// Reference to the instance of the &lt;see cref="ProxyProvider&amp;lt;TService&amp;gt;"/&gt;. /// &lt;/summary&gt; private static ProxyProvider&lt;TService&gt; instance; /// &lt;summary&gt; /// Gets the instance. /// &lt;/summary&gt; public static ProxyProvider&lt;TService&gt; Instance { get { if (DefaultProxyProvider.instance == null) { DefaultProxyProvider.instance = new DefaultProxyProvider(); } return DefaultProxyProvider.instance; } } /// &lt;summary&gt; /// Loads the specified force new. /// &lt;/summary&gt; /// &lt;returns&gt;A non-disposed instance of the given service.&lt;/returns&gt; protected override TService CreateInstance() { var loadedService = Activator.CreateInstance&lt;TService&gt;(); return loadedService; } } </code></pre> <p>With an additional "lazy" provider:</p> <pre><code>public class CustomConstructorProxyProvider&lt;TService&gt; : ProxyProvider&lt;TService&gt; where TService : class { private readonly Func&lt;TService&gt; constructor; /// &lt;summary&gt; /// Initializes a new instance of the &lt;see cref="CustomConstructorProxyProvider&amp;lt;TService&amp;gt;"/&gt; class. /// &lt;/summary&gt; /// &lt;param name="constructor"&gt;The constructor.&lt;/param&gt; public CustomConstructorProxyProvider(Func&lt;TService&gt; constructor) { this.constructor = constructor; } /// &lt;summary&gt; /// Internals the load. /// &lt;/summary&gt; /// &lt;returns&gt;The new created service.&lt;/returns&gt; protected override TService CreateInstance() { var service = this.constructor(); return service; } } </code></pre> <p>Used this way:</p> <pre><code>var proxy = ProxyProvider&lt;IWorkflowService&gt;.Current.Provide(); proxy.DoSomething(); </code></pre> <p>Initialized like this:</p> <pre><code>ProxyProvider&lt;IWorkflowService&gt;.Current = new CustomConstructorProxyProvider&lt;IWorkflowService&gt;(() =&gt; new WorkflowServiceProxy("endpoint")); </code></pre> <p>Workflow services are hosted by IIS and I added the following throttling settings:</p> <pre><code>&lt;serviceThrottling maxConcurrentCalls="512" maxConcurrentInstances="2147483647" maxConcurrentSessions="1024"/&gt; </code></pre> <p>which should be enough for my needs.</p> <p>I hope that someone can help me configuring client and server to have achieve the desired scalability (a few hundreds started in sequence and running in parallel, using the WorkflowInstance sql store).</p> <p><strong>UPDATE</strong>: I'm using NetTcpBinding for all services.</p> <p><strong>UPDATE 2</strong>: All services are hosted and consumed by now locally.</p> <p>Thanks Francesco</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload