Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Channel gets closed after every call to Invoke #18

Open
dfyx opened this issue Feb 19, 2016 · 3 comments
Open

Channel gets closed after every call to Invoke #18

dfyx opened this issue Feb 19, 2016 · 3 comments

Comments

@dfyx
Copy link

dfyx commented Feb 19, 2016

Currently, every call of RetryingWcfActionInvoker.Invoke constructs its own provider instance and disposes it afterwards. This causes a problem with long running duplex connections because the channel gets closed.

In 2.1.2 I used the following patched version that caches its provider between calls and only replaces it when something goes wrong.

        private TServiceInterface provider;

        /// <summary>
        /// This function is called when a proxy's method is called that should return something.
        /// </summary>
        /// <param name="method">Method implementing the service call using WCF</param>
        /// <param name="invokeInfo"></param>
        public TResponse Invoke<TResponse>(Func<TServiceInterface, TResponse> method, InvokeInfo invokeInfo = null)
        {
            provider = this.RefreshProvider(provider, 0, invokeInfo);
            TResponse lastResponse = default(TResponse);
            IDelayPolicy delayPolicy = this.DelayPolicyFactory();

            var sw = Stopwatch.StartNew();

            this.HandleOnCallBegin(invokeInfo);

            Exception mostRecentException = null;
            for (int i = 0; i < this.RetryCount + 1; i++)
            {
                try
                {
                    this.HandleOnBeforeInvoke(i, invokeInfo);

                    // make the service call
                    TResponse response = method(provider);

                    this.HandleOnAfterInvoke(i, response, invokeInfo);

                    if (this.ResponseInRetryable(response))
                    {
                        lastResponse = response;
                        provider = this.Delay(i, delayPolicy, provider, invokeInfo);
                        continue;
                    }

                    sw.Stop();

                    response = this.ExecuteResponseHandlers(response);

                    this.HandleOnCallSuccess(sw.Elapsed, response, (i + 1), invokeInfo);

                    return response;
                }
                catch (Exception ex)
                {
                    this.HandleOnException(ex, i, invokeInfo);

                    if (this.ExceptionIsRetryable(ex))
                    {
                        mostRecentException = ex;
                        provider = this.Delay(i, delayPolicy, provider, invokeInfo);
                    }
                    else
                    {
                        throw;
                    }
                }
            }

            if (mostRecentException != null)
            {
                if (RetryCount == 0)
                    throw mostRecentException;

                var exception = this.RetryFailureExceptionFactory(this.RetryCount, mostRecentException, invokeInfo);
                throw exception;
            }

            return lastResponse;
        }

I've used this in production for a couple of months and it works just fine. Unfortunately I can't port it to 2.2.0 because our company doesn't have access to VS2015 yet. So consider this an informal pull request.

P.S.: the same probably applies to InvokeAsync.

@dfyx
Copy link
Author

dfyx commented Feb 19, 2016

Or am I just missing something?

@jweber
Copy link
Owner

jweber commented May 3, 2016

I spent a bit of time looking at this and part of my issue is with a lack of familiarity with how WCF duplex communication works. A couple of tests start failing when I make the changes in your comment but I feel like that may just be due to how the WCF services are being hosted for testing.

If you are able to dig into it using VS2015 at this time (apologies for the long delayed response) maybe you could resolve what the issue is.

When I get more time I'll be able to dig into it further but I just wanted to give an update.

@c0nnex
Copy link

c0nnex commented Dec 22, 2016

Same problem here.
Because Invoke/InvokeAsync disposes the provider after each call , the DuplexChannel is closed, and all callbacks fail.
Your Duplex-Tests pass, because the turnaround between call and callback is too small for the underlying channel to be really closed before the callback is made. Add some delay before the callback and you will see the problem.

After applying above patch to Invoke and InvokeAsync all works fine with my DuplexChannel

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants