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

SignalR Hub - Hub performance degredation in IE #2456

Closed
stuartchaulk opened this issue Aug 22, 2013 · 9 comments
Closed

SignalR Hub - Hub performance degredation in IE #2456

stuartchaulk opened this issue Aug 22, 2013 · 9 comments
Milestone

Comments

@stuartchaulk
Copy link

I have a severe, logarithmic performance degradation in IE (not Chrome or Fixfox) when returning a Task after using Groups.Add.

E.g. the following method starts to break down after 7 or 8 calls (at 10, it takes longer than I am willing to wait).

    public Task Join(uint creditLineId)
    {
        var groupId = string.Format(GroupPattern, creditLineId);
        doSomeStuff();
        return Groups.Add(Context.ConnectionId, groupId);
    }

If, however, I replace it with a void method, it works fine (kind of, still measurably slower than Chrome/FireFox):

    public void Join(uint creditLineId)
    {
        var groupId = string.Format(GroupPattern, creditLineId);
        doSomeStuff();
        Groups.Add(Context.ConnectionId, groupId);
    }

Note that these are fired, and then more SignalR stuff is called. Client code is similar to the following:

    $.connection.hub.start({ transport: ['webSockets', 'serverSentEvents', 'longPolling'] })
    .done(function () {
        var promises = [];
       _.each(utilizations, function (util) {
            var joined = hub.server.join(util.Id);
            promises.push(joined);
        });

        promises = [];
        $.when.apply($, promises).then(function () {
           var currentRequest = hub.server.requestSomething(_.map(stuff, function (u) {
                return u.Id;
            }));

            promises.push(currentRequest);
       });

        $.when.apply($, promises).then(function () {
            $("#dialog").dialog("open");
        });


    })
    .fail(function (e) {
        HubError(e);
    });

This is happening in IE 10 and IE 10 running in IE 9 mode.

Note that this was tested using V1.1.3.

@davidfowl
Copy link
Member

Can you send us a repro?

@stuartchaulk
Copy link
Author

Will work on it in the morning. Thanks :)

Sent from my Virgin Mobile phone

-------- Original message --------
From: David Fowler notifications@github.com
Date: 08/22/2013 6:21 PM (GMT-05:00)
To: SignalR/SignalR SignalR@noreply.github.com
Cc: Stuart Chaulk schaulk@infusion.com
Subject: Re: [SignalR] SignalR Hub - Hub performance degredation in IE (#2456)

Can you send us a repro?


Reply to this email directly or view it on GitHubhttps://github.com//issues/2456#issuecomment-23130780.


This email, along with any attachments, may be considered confidential and/or proprietary. If you have received it in error, you are on notice of its status. Please notify me immediately by reply email and then delete this message from your system. Please do not copy it or use it for any purposes, or disclose its contents to any other person. Thank you for your cooperation.

@stuartchaulk
Copy link
Author

Here is a sample project that shows the performance issue:

https://drive.google.com/folderview?id=0B5k8a6Y1R74gR0tGLVZXZVE5N28&usp=sharing

Cheers.

@davidfowl
Copy link
Member

Thanks for the project. I'm looking at the page and the instructions but I'm not sure what the expectation is? Am I supposed to see IE freeze?

@stuartchaulk
Copy link
Author

IE won't freeze, but if you monitor the trace logs, you can see that it takes a long time to process the joins.

Here is the trace log using void. Everything happens within a second.

 8/23/2013 1:44:17 PM : JoinWithVoid: 1
 8/23/2013 1:44:17 PM : JoinWithVoid: 2
 8/23/2013 1:44:17 PM : JoinWithVoid: 4
 8/23/2013 1:44:17 PM : JoinWithVoid: 5
 8/23/2013 1:44:17 PM : JoinWithVoid: 9
 8/23/2013 1:44:17 PM : JoinWithVoid: 6
 8/23/2013 1:44:17 PM : JoinWithVoid: 8
 8/23/2013 1:44:17 PM : SendOutput: 1
 8/23/2013 1:44:17 PM : JoinWithVoid: 3
 8/23/2013 1:44:17 PM : SendOutput: 4
 8/23/2013 1:44:17 PM : JoinWithVoid: 7
 8/23/2013 1:44:17 PM : SendOutput: 2
 8/23/2013 1:44:17 PM : SendOutput: 5
 8/23/2013 1:44:17 PM : SendOutput: 7
 8/23/2013 1:44:17 PM : SendOutput: 8
 8/23/2013 1:44:17 PM : SendOutput: 9
 8/23/2013 1:44:17 PM : SendOutput: 10
 8/23/2013 1:44:17 PM : SendOutput: 3
 8/23/2013 1:44:17 PM : SendOutput: 6
 8/23/2013 1:44:17 PM : JoinWithVoid: 10

Everything happens pretty quickly.

Here it is with Task. Takes over 30 seconds.

 8/23/2013 1:44:54 PM : JoinWithTask: 5
 8/23/2013 1:44:54 PM : JoinWithTask: 4
 8/23/2013 1:44:54 PM : JoinWithTask: 2
 8/23/2013 1:44:54 PM : JoinWithTask: 6
 8/23/2013 1:44:54 PM : JoinWithTask: 3
 8/23/2013 1:44:54 PM : JoinWithTask: 1
 8/23/2013 1:44:54 PM : JoinWithTask: 7
 8/23/2013 1:44:54 PM : JoinWithTask: 9
 8/23/2013 1:44:54 PM : JoinWithTask: 8
 The thread '<No Name>' (0x2dac) has exited with code 0 (0x0).
 The thread '<No Name>' (0x3458) has exited with code 0 (0x0).
 The thread '<No Name>' (0x2848) has exited with code 0 (0x0).
 The thread '<No Name>' (0x3354) has exited with code 0 (0x0).
 8/23/2013 1:45:28 PM : SendOutput: 2
 8/23/2013 1:45:28 PM : SendOutput: 4
 8/23/2013 1:45:28 PM : SendOutput: 5
 8/23/2013 1:45:28 PM : SendOutput: 3
 8/23/2013 1:45:28 PM : SendOutput: 1
 8/23/2013 1:45:28 PM : SendOutput: 7
 8/23/2013 1:45:28 PM : JoinWithTask: 10
 8/23/2013 1:45:28 PM : SendOutput: 6
 8/23/2013 1:45:28 PM : SendOutput: 8
 8/23/2013 1:45:28 PM : SendOutput: 10
 8/23/2013 1:45:28 PM : SendOutput: 9

If I run the Task version with chrome, its back to one second:

 8/23/2013 1:51:40 PM : JoinWithTask: 1
 8/23/2013 1:51:40 PM : JoinWithTask: 3
 8/23/2013 1:51:40 PM : JoinWithTask: 2
 8/23/2013 1:51:40 PM : JoinWithTask: 6
 8/23/2013 1:51:40 PM : JoinWithTask: 4
 8/23/2013 1:51:40 PM : JoinWithTask: 7
 8/23/2013 1:51:40 PM : JoinWithTask: 5
 8/23/2013 1:51:40 PM : JoinWithTask: 8
 8/23/2013 1:51:40 PM : SendOutput: 1
 8/23/2013 1:51:40 PM : JoinWithTask: 9
 8/23/2013 1:51:40 PM : SendOutput: 3
 8/23/2013 1:51:40 PM : JoinWithTask: 10
 8/23/2013 1:51:40 PM : SendOutput: 4
 8/23/2013 1:51:40 PM : SendOutput: 5
 8/23/2013 1:51:40 PM : SendOutput: 6
 8/23/2013 1:51:40 PM : SendOutput: 2
 8/23/2013 1:51:40 PM : SendOutput: 7
 8/23/2013 1:51:40 PM : SendOutput: 9
 8/23/2013 1:51:40 PM : SendOutput: 10
 8/23/2013 1:51:40 PM : SendOutput: 8

@davidfowl
Copy link
Member

Firstly, it's nothing to do with IE, it's a longpolling issue. If you specify longpolling chrome behaves the same as IE.

I'm not seeing a performance fail from looking at the network monitor and fiddler, it looks like requests are getting queue in such a way that it's making group acks fail. Here's the problem:

Long polling has 1 long running request and uses ajax posts to send data to mimic a socket. What's happening is that invoking server methods back to back are causing them to get queued up before the new long polling request. When this happens, each of requests hang for 30 seconds waiting for a reply from the client (to confirm it is indeed in the group).

Here's a visual in fiddler:

image

In the above picture, the /connect request (the first long polling request) ends and when trying to poll again, there's several /send requests that are waiting on a reply (the Groups.Add task). That reply will never happen because there's no new /poll request.

This is a pretty awesome bug 😄.

@ghost ghost assigned NTaylorMullen Aug 23, 2013
NTaylorMullen added a commit that referenced this issue Aug 27, 2013
- The manager is used to control how many active ajax requests happen at the same time.
- Defaulted the max allows to 4, this allows for 1 poll long polling request and 1 long running user request.
- Ensured that all deferred ajax requests still fire in order.

#2456
NTaylorMullen added a commit that referenced this issue Aug 27, 2013
- One test ensures that the ajaxManager dispatches deferred ajax requests in the order that they were executed.
- Next ensures that even when a lot of "send" requests are executed synchronously that we don't deadlock.

#2456
@DamianEdwards
Copy link
Member

This is certainly interesting. A thought: another way to approach this would be to return from the Task returning hub methods immediately, with a hub result indicating a pending result. That would end the ajax request very quickly then (like void returning methods). When the Task completes the result could be sent via the bus rather than piggy backing on the original ajax request response. This would only be done for Task returning methods.

NTaylorMullen added a commit that referenced this issue Aug 29, 2013
…equest completes.

- Also added a maxConcurrentSends function to signalR.transports to allow configuration of the ajaxManager.

#2456
NTaylorMullen added a commit that referenced this issue Aug 29, 2013
…tly monkey patch it.

- This did not matter before because we never relied on the return value within the SignalR layer (now we do).
- Also found that joining too many groups resulted in us quickly going over our URL limit of the browser, therefore decreased some of the request thresholds of tests that stress how many ajax requests can be made.

#2456
@NTaylorMullen
Copy link
Contributor

Marking as blocked until we implement the secondary method and compare.

@DamianEdwards DamianEdwards modified the milestones: Backlog, 2.1.0 Beta Apr 14, 2014
@DamianEdwards
Copy link
Member

We'll move this to the new repo as a candidate for v3 or beyond.

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

No branches or pull requests

4 participants