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

Guide on "Don't block the event loop" #1478

Merged
11 commits merged into from
Dec 7, 2017
Merged

Conversation

davisjam
Copy link
Contributor

Towards #1471.

Not finished yet, hoping to get some initial feedback.

@davisjam davisjam changed the title WIP Guide on "Don't block the event loop" Guide on "Don't block the event loop" Nov 19, 2017
Copy link
Contributor

@Tiriel Tiriel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haven't finished ready in entirety yet, but one general opinion yet: I think you should go for a more formal tone.
This sounds too much like a blog post to me, not like an "official" guide. That may not be the general feeling of everyone, but I for one would prefer a more neutral tone on a guide found on Node.js official website.

Coming soon: complete review, although I'm not as technical as some!

@davisjam
Copy link
Contributor Author

Thanks for the comment on tone. I will try a more formal approach in my next revision.

Thoughts about the technical content?

Copy link
Contributor

@Tiriel Tiriel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As said, I'm not the most technical reviewer you could get, I'm largely a noob in Node.js and JS itself. I still hope my comments will help!


A safer alternative is the [node-re2](https://github.com/uhop/node-re2) project, which uses Google's blazing-fast [RE2](https://github.com/google/re2) regexp engine. But be warned, RE2 is not 100% compatible with Node's regexps, so check for regressions if you swap in the node-re2 module to handle your regexps. And really complicated regexps may not be supported by node-re2.

As usual, if you're trying to match something "obvious", like a URL or a file path, use an npm module!
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quick question here, mostly for my own education:
In that case, wouldn't stringVar.indexOf(searchVar) !== -1 or stringVar.includes(searchVar) !== false be more efficient, and eliminating the need of another module?

I originally come from PHP, and replacing preg_match() with stripos($string, $search) !== false is mostly preferred for the same reasons, so I thought it would be the same in JS.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're just doing a strcmp or substr-style string match, then yes, you should just use indexOf. You don't need a regular expression for this, nor will a regexp actually be dangerous in this context.

But sometimes people need more matching power for more complicated expressions, and a sufficiently complicated regexp can lead to REDOS.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, that's reassuring 😄
Maybe in that case you could specify this alternative, and that sufficiently complex regex are the real problem here? (I'm not quite sure what a sufficiently complete regex would be either; regex using escaped/reserved chars and/or logn regex?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the new REDOS section clearer? Still needs work?


This gives all of the other pending clients a turn.
It's pretty easy to accomplish this by sticking whatever state you're carrying around in a closure or an object.
And you might want to add a TODO to revisit this section of your code later.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some example might be good here. I think most newcomers/basic users won't necessarily have a clue about what you're talking here. The notion of 'immediate' in the event loop can be misleading and some people won't understand why it would partly solve the problem IMHO.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. I've been thinking about some examples.

And you might want to add a TODO to revisit this section of your code later.

## Don't block the Worker Pool
Work in progress.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Damn, that was the piece I was most eager to read 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Soon!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alrighty, first draft of this is up.

@vsemozhetbyt
Copy link
Contributor

@davisjam It seems your local email in git settings does not match your GitHub one. Can you add a local one to GitHub email list so that your contributions to Node.js repositories can be associated with your GitHub account?

mail

@davisjam davisjam force-pushed the DontBlockTheEventLoop branch from 20a30d5 to eeb8dfe Compare November 19, 2017 22:51
@davisjam
Copy link
Contributor Author

@vsemozhetbyt Thanks, always forget this.

@davisjam
Copy link
Contributor Author

@Tiriel:

  1. Is the language up to an appropriate level of formality, or should I work on the tone further?
  2. Does the regexp section make more sense now?

I haven't revised anything after the REDOS section yet.

- REDOS
- JSON DOS
- "Complex calculations without blocking the Event Loop"
@Tiriel
Copy link
Contributor

Tiriel commented Nov 20, 2017

@davisjam Way better now IMHO! It's more precise, the examples add a lot, and the tone is better suited to the subject and target as I see it.

@davisjam
Copy link
Contributor Author

The first draft of the full document is up. Comments appreciated.

@ayaankazerouni
Copy link

+1 Cool guide! I learned a lot, especially from the REDOS section.

@davisjam
Copy link
Contributor Author

I'm not the most technical reviewer you could get, I'm largely a noob in Node.js and JS itself

@Tiriel When you have a moment, can you ping some appropriate folks for technical feedback? Your thoughts on style and correctness are of course also much appreciated.

@vsemozhetbyt
Copy link
Contributor

Let's cc @nodejs/documentation for a start.

@vsemozhetbyt vsemozhetbyt added content Issues/pr concerning content enhancement labels Nov 21, 2017
@gibfahn
Copy link
Member

gibfahn commented Nov 21, 2017

cc/ @sam-github if you're around, seems like something you'd be interested in.

Copy link
Contributor

@sam-github sam-github left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its good to provide some information on this, particularly to provide implementation advice to users. It would be easy for someone to read this and think that network I/O occurs in the uv thread pool (which it doesn't), I think that aspect should be much more clear.


## Should you read this guide?
If you're writing a server using Node, keep reading.
If you're writing command-line scripts with Node, this guide might still come in handy, but it isn't crucial.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cli scripts can do, for example, heavy DNS lookups at the same time as file I/O, so worker pool can be blocked.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True. I view the server case as more concerning because of the DoS possibility. Do you want me to remove this caveat?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove, or expand to make more clear the situations in which some things aren't problems. No need to optimize anything for a short-running app that does a one-shot HTTP request is what you are trying to say, I think.

If you're writing command-line scripts with Node, this guide might still come in handy, but it isn't crucial.

## TL; DR
Node.js runs JavaScript code in the Event Loop and handles I/O in a Worker Pool (the threadpool).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, just file I/O, network I/O is handled on the main loop.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. I'll fix to clarify what kinds of I/O go to the Worker Pool.

## TL; DR
Node.js runs JavaScript code in the Event Loop and handles I/O in a Worker Pool (the threadpool).
Node scales well, sometimes better than more heavyweight approaches like Apache.
The secret to Node's scalability is that it uses a small number of threads to handle many clients.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where small number of threads is likely zero thread for a network server (no file i/o

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This depends on the env variable and on whether the server has ever used the threadpool, since libuv's threads are created the first time the threadpool is used. I don't see a reason to confuse the issue though, this is intended as the high-level summary.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel this confuses the issue, though, because the secret to node's scalability isn't that it uses threadpools well (so does java), the secret is that a fairly typical HTTP server making outbound DB or other network requests uses no threads at all.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. It uses one thread -- the main loop -- to handle many clients, rather than Apache-style with one thread per active client.


## A quick review of Node's architecture

Node uses the Event-Driven Architecture: it has an Event Loop for orchestration and a Worker Pool for expensive tasks.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

file i/o isn't expensive, no more so than network i/o, it just doesn't have good completion APIs at the O/S level to allow it to be done on the main loop, so threads are needed so that i/o can be done with blocking system calls

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding of the libuv loop (which is limited to Linux) is that the trouble is not the completion APIs but rather the ability of the OS to say that the file descriptor is ready and thus not to block when you do I/O on it. libuv only sends network traffic when it will not block in doing so, but the OS will not guarantee that read/write on a file descriptor will be non-blocking.

Based on this understanding, my claim is correct - the I/O done on the event loop is always cheap from the event loop's perspective because the OS guarantees it to be non-blocking.

Am I missing something here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe. The actual problem that is that you can't poll/epoll/select/kqueue a file descriptor for readiness, and so we can't do non-blocking reads or writes. And I guess you could call a blocking call "expensive", but network i/o can be done in thread pools with blocking calls, and lots of languages do exactly that. node doesn't, because network i/o can be non-blocking on unix, whereas file i/o can't (without the async i/o posix extensions, but they are poorly supported, and while windows has better async i/o for files, early tests by libuv authors showed that it would randomly block, it was to flaky to be useful).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Last I checked, posix async I/O is just a threadpool in libc, no different from the libuv threadpool. I've prototyped Node with kernel AIO to see if things had improved since 2011, but the O_DIRECT restriction remains and its costs are catastrophic.

Anyway, I'll flesh out this discussion a bit more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aio was intended to be implemented in kernel and thus to rock... but hasn't happened yet, the saga is long, some info here: https://lwn.net/Articles/724198/. There is various user-space emulation using blocking I/O in a thread pool.... so, yeah, uv doesn't use that, there is no point.

The Event Loop's queue is full of pending events.
When the Event Loop sees a new event, it invokes its callback, which is JavaScript code that sees your Node application.
The Event Loop is the only consumer of this queue.
The Node runtime produces events for this queue.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the o/s produces the events, not the node runtime

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, via things like epoll. Where do you see the line between technical accuracy and "missing the forest for the trees" in guides like this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because its not really a queue, if it was, we could ask "how long is that queue?", but we can't.... because it doesn't exist. node reads from the o/s's internal queue, gets a set of ready events, processes them then blocks reading again. no queue. the whole queue thing is brought up sometimes, but I don't think introducing something that doesn' exist is helpful in understanding how node works. I never describe anything like it in https://www.youtube.com/watch?v=P9csgxBgaZ8, for example

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From a framework developer perspective, it's a queue that you can only see looking backwards. From an application developer perspective, though, I think the concept of a queue is a fine approximation of reality. I'm envisioning the target audience to be application developers for whom I think the "queue" concept is fine.

How strongly do you feel about this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am OK with the whole thing, except this sentence:

The Node runtime produces events for this queue.

I think that specific sentence should be removed. node doesn't produce the events. it asks for the o/s to produce them. I wouldn't say that I'm producing a cappucino when I order a cappucino at a cafe. Causing it to be produced? Sure, producing it? no.

When the Event Loop sees a new event, it invokes its callback, which is JavaScript code that sees your Node application.
The Event Loop is the only consumer of this queue.
The Node runtime produces events for this queue.
Specifically, Node asks libuv to monitor file descriptors using [epoll](http://man7.org/linux/man-pages/man7/epoll.7.html)), and the Event Loop's queue consists of the ready descriptors.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only on linux, its kqueue on OS X, and other mechanisms on Windows

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, good catch.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about saying "an epoll-like system call" with a link to the epoll man page? Part of my goal is to point users to resources that will give them a richer understanding of Node concepts and Node under the hood. That was also my intent with the "cooperative multitasking" link.

The consumers of this queue are the Workers in the Worker Pool, who all compete to work on the next Task.
Most of the time, the Event Loop is the only producer of Tasks for the Worker Pool.

It is crucial to understand that this queue-based approach means that the Event Loop and the Workers rely on [cooperative multitasking](https://en.wikipedia.org/wiki/Cooperative_multitasking).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this isn't the common understanding of cooperative multi-tasking. coop tasking means that the running thread can suspend itself, but node doesn't do this, ever (on main loop or in pool). it runs to completion, which is not cooperative multitasking

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't think of a better way to describe this other than saying "queue-based". Should I stick with that? Is there a better term?

Counterpoint, though -- queue-based is "cooperative multitasking" in the sense that a callback/task yields precisely when it completes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that other than the queue to the uv work pool (which is actually a queue), I don't think queues should be mentioned. Not sure what a good replacement is, sorry! I can see the ghostly parallels, both node and co-op multitasking systems require careful consideration of how much work you do, and how you construct your app, but the analogy breaks down fast, because cooperative multi-tasking has a fairly agreed upon definition, and its not what node does, so better stay away from it, IMO.

##### Best practices for offloading
Follow these best practices for offloading:
1. You should create your own Computation Worker Pool for extensive computation.
2. The Computation Worker Pool should have no more than Workers than your machine has [logical cores](https://nodejs.org/api/os.html#os_os_cpus).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about when you have multiple addons, each with a number of threads equal to the number of logical cores?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest creating a single Computation Worker Pool at the application level, similar to the Node Worker Pool that handles I/O from all points in the application. Do you have any reference applications I can look at to describe alternate patterns?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but no such thing exists, so current addons don't use it. it has been proposed that uv expose two work APIs, one for blocking non-cpu intensive calls (file i/o, dns.lookup), the other for cpu intensive activities (crypto.pbkdf for key generation, etc), but no code has been PRed, or benchmarks to show it will work. so, in the meantime, you have to consider all the internal pools of all the addons, and actually most addons will mix cpu and i/o intensive work in the same uv work pool. I'm slowly working towards getting metrics in node about the state of the uv pool, but that doesn't exist yet, so not worth mentioning here.

Copy link
Contributor Author

@davisjam davisjam Nov 21, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. If I added such an API would it be of interest? Is anyone working on this right now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I'll just remove this section. It sounds like this is too much of an open problem to worry about right now.

### What is the Node Worker Pool used for?
In the Node core modules, the Node Worker Pool is used for the asynchronous versions of the following classes of APIs:
1. File system I/O
2. DNS queries
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only dns.lookup, the other ones don't use the pool

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. I'll fix this. I believe all of the FS APIs map directly to libuv versions, though?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then this function would still be asynchronous, but the cost of each partition would be `O(n)`, not `O(1)`, making it much less safe to use for arbitrary values of `n`.

## Conclusion
Node has threads called Event Handlers, i.e. the Event Loop and the threadpool Workers, and these execute JS- and C++-callbacks.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the thread in the libuv work pool aren't called Event Handlers, except here, by you! And the lib uv workers never execute JS code. I don't think its helpful to overgeneralize the main thread to describe it as a kind of worker.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I agree that this is a weird overgeneralization. I'll take another look at this.

@davisjam
Copy link
Contributor Author

Thanks for all the great comments, @sam-github! I'll get started on a revision.

@Tiriel
Copy link
Contributor

Tiriel commented Nov 21, 2017

Just a quick semi off-topic:
Thanks @sam-github & @davisjam , just reading your comments makes me learn a huge load of new things!
I really look forward to reading the final version of this guide!

- Rewrite the "A quick review of Node" section
- Remove "Event Handler" abstraction
- Provide more internal details
- Relax the "Offloading best practices"
- New task variation example: crypto.randomBytes
- Misc. formatting and bonus material
@davisjam
Copy link
Contributor Author

@sam-github e9c40e9 attempts to address your concerns.

This includes I/O for which an operating system does not provide a non-blocking version, as well as particularly CPU-intensive tasks.

These are the Node module APIs that make use of this Worker Pool:
1. I/O-intensive
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

worth mentioning net module?

Copy link
Contributor Author

@davisjam davisjam Nov 22, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is my understanding that the net module does not use the Worker Pool, thanks to good OS support for non-blocking network I/O. The module docs do not bear the usual caveats about the threadpool, and as far as I can tell from the source there is no call to uv_queue_work.

Am I wrong in this? Or are you suggesting I explicitly mention the net module as a "safe" option? If so, I attempted to do so in the section "What code runs on the Event Loop?" with the sentence "The Event Loop will also fulfill the non-blocking asynchronous requests made by its callbacks, e.g., network I/O.". Do you think I should name a few examples there, like net and UDP?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

correct, net does not use threads

@sam-github
Copy link
Contributor

thanks for addressing my comments @davisjam

@davisjam
Copy link
Contributor Author

Sure thing, @sam-github. Any more suggestions, or people that should be tagged?

@sam-github
Copy link
Contributor

@jasnell was looking at loop behaviour, he might have some comments

Then this function would still be asynchronous, but the cost of each partition would be `O(n)`, not `O(1)`, making it much less safe to use for arbitrary values of `n`.

## Conclusion
Node has two types of threads: one Event Loop and `k` Workers.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about the JavaScript thread?

Copy link
Contributor Author

@davisjam davisjam Nov 25, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am referring to the "JavaScript thread" as the Event Loop throughout, to contrast it with the Worker Pool (threadpool) threads, and because it does more than JavaScript (e.g. wandering into libuv to fulfill network I/O requests, timers, etc.).

See the section "What code runs on the Event Loop?"

"In summary, the Event Loop executes the JavaScript callbacks registered for events, and is also responsible for fulfilling non-blocking asynchronous requests like network I/O."

Let me know if this is not clear or if you have alternative suggestions for phrasing.

#### Variation example: Long-running file system reads
Suppose your server must read files in order to handle some client requests.
After consulting Node's [File system](https://nodejs.org/api/fs.html) APIs, you opted to use `fs.readFile()` for simplicity.
However, `fs.readFile()` is not partitioned: it submits a single `fs.read()` Task spanning the entire file.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually being fixed if I understand correctly: nodejs/node#17054

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's the idea, anyway. But this guide is describing things as they are, not as I hope they will be.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See also nodejs/node#17250.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be worth adding a link to nodejs/node#17054 in here to note the proposed change then.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a link in 0a42816, thank you.

@davisjam
Copy link
Contributor Author

I recognize this is a pretty long document, but does anyone have additional change requests?

Copy link
Member

@gibfahn gibfahn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really helpful, thanks a lot for writing this!

LGTM, couple of questions though.

`JSON.parse` and `JSON.stringify` are other potentially expensive operations.
While these are `O(n)` in the length of the input, for large `n` they can take surprisingly long.

If your server manipulates JSON objects, particularly those from a client, you should be cautious about the size of the objects or strings you work with on the Event Loop.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worth mentioning asynchronous JSON parsing modules here (and then linking to The risks of npm modules section)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, will do.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in ccd4f75.


In a server, *you should not use the synchronous APIs from these modules*.
These APIs are expensive, because they involve significant computation or require I/O.
If you execute them on the Event Loop, they will take far longer to complete than a typical JavaScript instruction, blocking the Event Loop.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you do if there is no async core api?

Maybe the answer is "raise an issue in core", but this was my question on reading this, so maybe worth saying something.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I'll try another pass on this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in ccd4f75.

## The risks of npm modules
Node developers benefit tremendously from the [npm ecosystem](https://www.npmjs.com/), with hundreds of thousands of modules offering functionality to accelerate your development process.

However, the vast majority of these modules are written by third-party developers and undergo no formal verification process.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does node core undergo a formal verification process? Mentioning it here makes it seem like it's in contrast to something else, but I'm not sure what that something is.

Copy link
Contributor Author

@davisjam davisjam Dec 4, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, "formal" isn't the right word. It's more of a "many eyes on Node, few eyes on most 3rd-party modules" type situation. I'll change the wording.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in ccd4f75.

@davisjam
Copy link
Contributor Author

davisjam commented Dec 4, 2017

@gibfahn Thank you for your review. I've tried to address your comments in ccd4f75. Let me know if you have more concerns before you'd be willing to approve.

@davisjam
Copy link
Contributor Author

davisjam commented Dec 4, 2017

@sam-github Anything else needed for your approval?

@sam-github
Copy link
Contributor

looks good to me

@davisjam
Copy link
Contributor Author

davisjam commented Dec 7, 2017

The full draft has been up for about 2 weeks and has gone through a few reviews. Ready to be landed?

This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
content Issues/pr concerning content enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants