Hot swap of running web app

1,102 views
Skip to first unread message

Stefan Scholl

unread,
Jul 20, 2011, 3:25:09 AM7/20/11
to golan...@googlegroups.com
How would you solve the problem of a hot swap of a web app?

I was thinking about running >1 processes behind a proxy/load
balancer. Then signaling 1 of the processes to stop accepting new
requests and to exit gracefully. Restarting this process and then
continue with the other one(s).

But is there a way in the http package to stop accepting new
requests? Do I need to write my own ListenAndServe?


--
Web (en): http://www.no-spoon.de/ -*- Web (de): http://www.frell.de/
<!--[if IE 6]><script>for(x in document.open);</script><![endif]-->

Brian Ketelsen

unread,
Jul 20, 2011, 5:32:27 AM7/20/11
to Stefan Scholl, golan...@googlegroups.com

I did something like this in Skynet [1] but used Go as the load balancer. Rather than telling http to quit listening, I told the load balancer to quit sending traffic. It accomplished the same thing.

Brian


[1] https://github.com/bketelsen/skynet

Brad Fitzpatrick

unread,
Jul 20, 2011, 11:17:42 AM7/20/11
to Stefan Scholl, golan...@googlegroups.com
On Wed, Jul 20, 2011 at 12:25 AM, Stefan Scholl <ste...@no-spoon.de> wrote:
How would you solve the problem of a hot swap of a web app?

I was thinking about running >1 processes behind a proxy/load
balancer. Then signaling 1 of the processes to stop accepting new
requests and to exit gracefully. Restarting this process and then
continue with the other one(s).

But is there a way in the http package to stop accepting new
requests? Do I need to write my own ListenAndServe?

Just close the net.Listener that you give to your *http.Server:


 closeChan := make(chan bool)

 server := &http.Server{ReadTimeout: 15e9, WriteTimeout: 15e9}
 ln, err := net.Listen("tcp", ":8080")
 ...
 go func() {
     <-closeChan
     ln.Close()
 }()
 server.Serve(ln)
 

Stefan Scholl

unread,
Jul 21, 2011, 4:52:09 AM7/21/11
to golan...@googlegroups.com

That was easy. And looks dirty (accessing ln in the go routine).
But it's the end of this process anyway.

Thanks.


http://golang.org/pkg/http/#Server.ListenAndServe with a small
extra. I like it.

Maybe I modify it a bit to use some OS signal via the Channel
signal.Incoming from "os/signal". os.UnixSignal(2) (SIGINT)
sounds reasonable for this.


Stefan Scholl

unread,
Jul 21, 2011, 5:00:24 AM7/21/11
to golan...@googlegroups.com
Brian Ketelsen <bket...@gmail.com> wrote:
> I did something like this in Skynet [1] but used Go as the load balancer. Rather than telling http to quit listening, I told the load balancer to quit sending traffic. It accomplished the same thing.
>
> [1] https://github.com/bketelsen/skynet

This is huge. I'm a bit overwhelmed by it.

Is this something that has to be integrated from the very
beginning or is it easy enough to refit existing projects?


I'm definitely putting this on a list.

Brian Ketelsen

unread,
Jul 21, 2011, 6:50:06 AM7/21/11
to Stefan Scholl, golan...@googlegroups.com

It's probably overkill for most web applications. Skynet is designed to scale by adding more processes, and to be tolerant to crashing or disappearing nodes. That's why the router and service engines are in different processes.

Brian

buu700

unread,
Jul 26, 2011, 3:28:59 PM7/26/11
to golang-nuts
Hey, sorry if this isn't the appropriate thread to ask about this, but
I'm having a bit of trouble getting started with Skynet (which looks
amazing).

Right now, I'm trying to get started creating a service. I generated a
project "MyProject", but now I'm confused as to how I should go about
creating a service. Am I supposed to copy service.go to a new Go file
(i.e. use it as a template) and find/replace "MyProject" with
"ServiceName", or is there something else I'm supposed to change?
(Should all the services be in one file or is it one service per
service file?)

Also, I'm not sure how I should insert my application logic into a
service (it looks like I should put this code above the line
'lr.YourOutputValue = "Hello World"' and then swap 'Hello World' with
whatever return value I'd like to send back to the router; is this
correct?). Is there a way for a router to send parameters to a
service, and if so, how can I specify these from the router and accept
them from the service?

Thanks,
Ryan


On Jul 21, 6:50 am, Brian Ketelsen <bketel...@gmail.com> wrote:
> On Jul 21, 2011, at 5:00 AM, Stefan Scholl wrote:
>
> > Brian Ketelsen <bketel...@gmail.com> wrote:
> >> I did something like this inSkynet[1] but used Go as the load balancer.  Rather than telling http to quit listening, I told the load balancer to quit sending traffic.  It accomplished the same thing.
>
> >> [1]https://github.com/bketelsen/skynet
>
> > This is huge. I'm a bit overwhelmed by it.
>
> > Is this something that has to be integrated from the very
> > beginning or is it easy enough to refit existing projects?
>
> > I'm definitely putting this on a list.
>
> It's probably overkill for most web applications.  Skynetis designed to scale by adding more processes, and to be tolerant to crashing or disappearing nodes.  That's why the router and service engines are in different processes.
>
> Brian

Brian Ketelsen

unread,
Jul 26, 2011, 3:53:13 PM7/26/11
to golang-nuts
For some reason I can't reply from my email client - gmail has been
strange for a few days - I replied off list to this. We have a google
group for skynet - skyne...@googlegroups.com

Brian

buu700

unread,
Jul 26, 2011, 6:45:40 PM7/26/11
to golang-nuts, bket...@gmail.com
Awesome, thanks a lot for the help Brian! I'll go check out the Skynet
group right away.

It looks like your original message isn't showing up because you sent
it to the skynet-dev group instead of golang-nuts, but I've copied and
pasted it to the bottom of this message so anyone else who reads this
thread may reference it.

I think I understand everything a lot better now that I know what the
structs in package.go are for. Basically, each service has an
associated router (though only one instance of each router will be run
while services may have multiple instances), and Skynet will
automatically hand off the relevant structs between routers/services
with any data they may contain. Does this sound right?

Also, just a couple things I wasn't completely clear on: are there any
conventions which router/service/initiator names must follow, and is
there any code created by skygen which I would be advised to
absolutely leave alone (given that I don't understand Skynet nearly
enough yet to do anything really advanced or out of the ordinary)?


Ryan

---

When you generate a skynet project, you should get at least an
initiator, a router and a service.

Each service should be in it's own file - and therefore it's one
executable, this is how Skynet scales. If you are going to have 3
services in a route, then you should have three executables each
implementing the different services.

Your app logic goes exactly where you mentioned - in the
lr.YourOutputValue = whatever section of the service is where you'd
implement your own business logic. Also note that there should be a
MyProject folder with a go file in it that defines the inbound request
and outbound response. In the example on github this is :
GetWidgets/myStartup/package.go

In that file you define your request and response. Say you're
building a weather service API - the inbound (REQUEST) type needs a
zip code and the outbound response would include the fields that you
are sending back in your API.

Skynet is sorely lacking in good documentation and use cases, I'm
working hard to fix that. If you are going to have multiple services,
you can create multiple folders/targets under the service directory
and build them separately. Each service needs a unique name - in the
example it's:

const sName = "GetUserDataService.GetUserData"

You might add a service to log the request, and call it:
const sName = "GetUserDataService.LogGetUserDataRequest"

Make more sense yet?

Brian
Reply all
Reply to author
Forward
0 new messages