Skip to content

Code causes TS Server to hang using 100% CPU and become non-responsive #23458

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

Closed
kpdonn opened this issue Apr 17, 2018 · 8 comments
Closed

Code causes TS Server to hang using 100% CPU and become non-responsive #23458

kpdonn opened this issue Apr 17, 2018 · 8 comments
Assignees
Labels
Bug A bug in TypeScript Fixed A PR has been merged for this issue

Comments

@kpdonn
Copy link
Contributor

kpdonn commented Apr 17, 2018

TypeScript Version: 2.9.0-dev.20180414 (also reproduces in 2.8.1)

Search Terms:
TSServer, CPU, autocomplete

Code

recordautocompletebug

Steps to reproduce

Unfortunately I haven't been able to produce a self contained reproduction, but I can reproduce it consistently in the project I'm working on using just the code above. Specific steps:

  1. Clone https://github.com/kpdonn/kpd-sql/tree/autocompleteHangsBug (note the autocompleteHangsBug branch)
  2. Run yarn to get dependencies
  3. Open typings-tests/autocompleteBug.ts in VS Code.
  4. Type db.with("a", db. in that file and try to autocomplete. Note that actually typing it does matter. It does not reproduce for me if not manually typed.
  5. The TS service hangs and stops responding to any requests. CPU on my machine (macOS) shoots up to 100% and stays there.

Logs
I enabled verbose tsserver trace logs, however the only output it logs once it starts hanging is the following.

[Trace  - 00:06:49] TypeScript Service: canceled request with sequence number 46
[Trace  - 00:06:50] TypeScript Service: canceled request with sequence number 49
[Trace  - 00:06:50] TypeScript Service: canceled request with sequence number 51
[Trace  - 00:06:55] TypeScript Service: canceled request with sequence number 55
[Trace  - 00:06:56] TypeScript Service: canceled request with sequence number 57
[Trace  - 00:06:57] TypeScript Service: canceled request with sequence number 58
[Trace  - 00:06:57] TypeScript Service: canceled request with sequence number 59
[Trace  - 00:06:58] TypeScript Service: canceled request with sequence number 60
[Trace  - 00:06:59] TypeScript Service: canceled request with sequence number 61

I didn't see any stack traces or anything that seemed interesting before those lines start appearing, but if providing the logs will help let me know and I'll add them.

What triggers it
I don't have any idea what the root cause is, but I know what makes it start happening. This change in everything.ts. When I remove BeforeSelect that was added there try to follow the steps to reproduce it again(after restarting tsserver), it no longer happens. BeforeSelect is a mapped type that filters out a handful of methods from SqlBuilder. The code creating the types is pretty complicated, but I don't know why that specifically triggers the problem.

Related Issues:
Possibly #23390, #23259 or #23389.

@mhegazy mhegazy added the Bug A bug in TypeScript label Apr 18, 2018
@mhegazy mhegazy added this to the TypeScript 2.9 milestone Apr 18, 2018
@weswigham
Copy link
Member

weswigham commented Apr 18, 2018

image

It hangs printing a crazy complicated type. The type for db.with, db.columns, and db.select's return types have a scrollbars and are very, very long, thanks to the heavily nested conditional types.

@weswigham
Copy link
Member

weswigham commented Apr 18, 2018

For the record: The reason it's nonresponsive is likely because we don't check cancellation tokens within typeToTypeNode (because how often is the time dominated by construction of the display, 😝 ). If you wait for the operation, however, it'd still be slow (it just won't block other ones).

@mhegazy Do you want us to make typeToTypeNode cancellable?

@kpdonn
Copy link
Contributor Author

kpdonn commented Apr 18, 2018

That makes sense and explains why it only manifests after I add the extra BeforeSelect type to filter some keys. Before I add that type the return type for those methods is the SqlBuilder class so it just prints the name of the class and its type parameter arguments, but BeforeSelect is a mapped type alias so I guess it gets fully expanded.

From my perspective it'd be very welcome if it could just cancel printing the type and be responsive to other requests because I don't care about actually seeing the expanded type there, I just want the static typing and ideally the autocomplete from it.

Also based on that information it sounds like this is related to #18754, #6070 and #13095.

@weswigham
Copy link
Member

@mhegazy we've added the cancellation - is there anything else we want to do here?

@mhegazy
Copy link
Contributor

mhegazy commented May 4, 2018

We should add a limit on the generated type.. both for performance and for readability purposes..

@weswigham
Copy link
Member

We just want to truncate signature help and quick info, right?

@mhegazy
Copy link
Contributor

mhegazy commented May 4, 2018

Our current truncation logic is not ideal for readability, but more importantly, it does not save the work, we will do the work, generate a humongous string, then truncate it. we would be better off both for readability and performance to have a smarter "truncation" logic that is deeper in the stack.

@weswigham
Copy link
Member

@kpdonn we now have truncation enabled in our LS requests - if you could try tonight's nightly at some point and give us a holler as to weather it's made the experience better, that'd be nice.

@mhegazy mhegazy added the Fixed A PR has been merged for this issue label Jul 6, 2018
@mhegazy mhegazy closed this as completed Jul 6, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Fixed A PR has been merged for this issue
Projects
None yet
Development

No branches or pull requests

3 participants