-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Sails Cluster / Auto Reload #1716
Conversation
@@ -28,12 +29,15 @@ module.exports = function() { | |||
|
|||
// console.time('cli_rc'); | |||
var log = captains(rconf.log); | |||
var workerCount = (1 * rconf.workers) || 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why 1*?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Simple, concise string to int coercion, returning NaN
if not a coercible string thus shorting to 1.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But doesn't parseInt do the same thing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, parseInt
counts on its fingers—out loud—while 1 *
gets the answer from the person sitting next to it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for clearing that up..
Are there any tests for these changes? |
this looks really neat guys, just need to test it out @jbielick thanks! |
It looks very promising! |
There are probably some things I didn't consider, but I wanted to open this PR to start a conversation about what some possible "gotchas" will be so that I can address them. Let me know how I can help! |
@jbielick Any news about your interesting pull request? It looks great and we would love to merge it. |
Just started to look into clustering myself as well using |
@loicsaintroch Nothing new to report; I've mostly been waiting for feedback regarding the idea as a whole and any unforeseeable issue (from a new contributor's perspective). I was mainly looking for a response on whether this was something the sails contributing team wanted to include in the roadmap and support as it would obviously change the development environment a little bit. I imagine with all the work that's been done since this was created that some of the merge conflicts will take some time to go through. I could see the want to keep the multi-threading enhancement a concern outside of the sails framework, but it isn't very obtrusive and the heavy lifting is done in nodejs source. The work I did in these commits was to cluster the whole application, but this same concept can be applied just to the development environment to have code-reloading available. I can get this PR up to speed, but unless there's interest in merging it, there will continue to be merge conflicts as time goes by. The reason for that is that I had to separate the sails framework hooks and bootstrapping into two separate concerns: 1.) the master process (running grunt, holding the cluster, bootstrapping) and 2.) the child processes (which should only run express threads and take requests). So for future development, there might often have to be a Shall I get the PR up to date? |
great work! I hope to see this merge soon... |
@jbielick Excellent work! @mikermcneil what about this? Do you think this could be added? |
@luislobo we are running cluster mode in PM2 and its launching on different CPU cores. Its been running fine in production environment for a while now. You do get errors on startup about the .tmp directory, and binding to your preferred port. |
I need this. Hope it fixed and merged soon. |
awesome, hope to see this merged soon too 👍 |
Nice work! Hope this gets merged soon. Really a missing feature! |
+1 Have done something very similar using cluster / siege on several occasions with MEAN stack apps. But have found in development there was rarely a need for clustering. In fact, it can get in the way of debugging as your debugger attaches to the master process instance, and breakpoints that occur on a child process are not hit. Therefore, in development simply using nodemon and a single process works well. However, for PRD deployments having this built-in cluster support would be excellent. As others have said, a much needed feature that is currently missing. |
Node.js Cluster module supports the load balancing and sharing of the port between the worker processes. Node v0.12 will even support round-robin load balancing. As for using pm2 and cluster, I think that'd be redundant. It seems that from a DevOps perspective, pm2 would suit the needs of a production environment, clustered application with worker processes and load balancing. I think it's pretty typical to find a clustering / load balancer outside of the application framework, but Node is definitely moving forward with cluster support and the API is such that it's best integrated with the application bootstrapping / setup IMO. As stated by campbellanderson, the only thing stopping sails for running error-free in multiple processes is IO collision. There's no reason pm2 couldn't be the production-ready solution for sails apps, but it means that the sails asset build task ought to be separated from the code that starts the application. Much like having @arcseldon, I think the only real goal of clustering in development was to be able to kill / fork (cycle) one worker process to restart the application with new (changed) code. The current climate for debugging worker processes isn't great and I'm afraid this PR doesn't address that. The best case scenario I've seen is in Node ~0.11, each worker will listen on it's own debugger port, but killing a worker and forking means a new port. It isn't convenient, but, I've got some working code based on that. I've also experimented with a monitor script that uses It sounds like the consensus is a worker process or fork and cycle in development only would be ideal and the production clustering be left to the way it is until someone wants to address that or the sails team has comments on a roadmap there. Does that sound accurate? |
@jbielick Thank you for your answer and though analysis. I'm not a dedicated DevOp, but a developer. Anyway, right now, I need to manage our production servers. Can you explain further about "stopping sails for running error-free in multiple processes is IO collision". |
@luislobo Sounds pretty interesting. I'd love to see that in action. To clarify about
I haven't looked into it in a while, but as of this PR the only issue with clustering the sails process currently would be that it's trying to build assets and things into the
I've been looking into this quite a bit and there's no elegant solution yet. If you start a master process with Consider this gist But what about this? I came up with this pattern in an effort to support development environment server restarts. Obviously the trigger for a cycle wouldn't be an interval, but a file watch. In this pattern, Anyway, some of the thoughts here are great. PM2 is probably a better option for clustering a sails app because you really may want more granular control / monitoring than just |
we've got a hook in-progress for that part |
@jbielick re: clustering and this PR: This has spawned a really awesome discussion. Seems to me the right approach for clustering right now is probably pm2. It seems like the big annoyance is dealing w/ production grunt stuff-- the trick I always use when I run into trouble w/ that is to disable grunt in production by setting |
Attempting to address the auto reloading feature in development environment with cluster processes.
It also allows sails to run with a cluster of processes.
Approach
The master proc bootstraps the app and starts grunt task, but stops before actually starting the http server. It then forks n workers in start.js which all listen and share the app's port using node's very own cluster. Worker processes are delegated the server.listen() and the worker count can be set in
--workers n
or insails.config.workers
.In the development environment, the master proc will also watch the ./api file tree and on change-like events, cycle the cluster of workers with a kill signal. Didn't see a need to gracefully restart workers since cycling the workers is a development-only task.
In the event that a worker dies, another is immediately forked in its place. You can test this by sending a
kill
through your terminal to one of the forks. It will replace itself.Re-forking processes that die will also occur in
production
environment. Ensuring that they are cycled in a long-running application.There's a monkey patch for npm cluster in start.js addressing the missing port attribute on server(). It's not yet been addressed in node, but with the provided patch, the tests and servers all run correctly. (the server runs correctly without it, but attempts to check
address().port
throw exceptions).I've screenshot some preliminary benchmarking on concurrency and request timing with siege and results can be seen below.
I'm sure I've missed some issues, but all tests pass and I'd be glad to work through whatever issues arise as well as strategize how to write better/more tests for this.
Todo
Benchmarks
500 concurrent connections, 1 process
500 concurrent connections, 10 workers
300 concurrent connections, 1 process (master)
300 concurrent connections, 8 workers (master)
1000 concurrent connections, 1 process (master)
1000 concurrent connections, 8 workers (sails-cluster)