blob: e7b3ff133194f962c6e3bdb6b2eaafb5765fe336 [file] [log] [blame]
//Copyright 2017 Huawei Technologies Co., Ltd
//
//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
//Unless required by applicable law or agreed to in writing, software
//distributed under the License is distributed on an "AS IS" BASIS,
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//See the License for the specific language governing permissions and
//limitations under the License.
package server
import (
"fmt"
"github.com/astaxie/beego"
"os"
"os/signal"
"strings"
"syscall"
"time"
)
import (
"github.com/ServiceComb/service-center/pkg/common"
"github.com/ServiceComb/service-center/server/api"
"github.com/ServiceComb/service-center/server/core/registry"
st "github.com/ServiceComb/service-center/server/core/registry/store"
rs "github.com/ServiceComb/service-center/server/rest"
"github.com/ServiceComb/service-center/server/service"
nf "github.com/ServiceComb/service-center/server/service/notification"
"github.com/ServiceComb/service-center/util"
"golang.org/x/net/context"
"runtime"
)
var (
apiServer *api.APIServer
notifyService *nf.NotifyService
store *st.KvStore
exit chan struct{}
)
const CLEAN_UP_TIMEOUT = 5
func init() {
util.LOGGER.Infof("service center have running simultaneously with %d CPU cores", runtime.GOMAXPROCS(0))
exit = make(chan struct{})
store = st.Store()
notifyService = nf.GetNotifyService()
apiServer = api.GetAPIServer()
rs.ServiceAPI, rs.InstanceAPI, rs.GovernServiceAPI = service.AssembleResources()
go handleSignal()
}
func Run() {
beforeRun()
waitStoreReady()
startNotifyService()
startApiServer()
waitForQuit()
}
func beforeRun() {
var client registry.Registry
wait := []int{1, 1, 1, 5, 10, 20, 30, 60}
for i := 0; client == nil; i++ {
client = registry.GetRegisterCenter()
if i >= len(wait) {
i = len(wait) - 1
}
t := time.Duration(wait[i]) * time.Second
util.LOGGER.Errorf(nil, "initialize service center failed, retry after %s", t)
<-time.After(t)
}
}
func handleSignal() {
sc := make(chan os.Signal, 1)
signal.Notify(sc, os.Interrupt)
signal.Ignore(syscall.SIGQUIT) // when uses jstack to dump stack
s := <-sc
util.LOGGER.Warnf(nil, "Caught signal '%v', now service center quit...", s)
close(exit)
if apiServer != nil {
apiServer.Stop()
}
if notifyService != nil {
notifyService.Stop()
}
if store != nil {
store.Stop()
}
util.GoCloseAndWait()
registry.GetRegisterCenter().Close()
}
func waitForQuit() {
var err error
select {
case err = <-apiServer.Err():
case err = <-notifyService.Err():
case <-exit:
}
if err != nil {
util.LOGGER.Errorf(err, "service center catch errors, %s", err.Error())
}
select {
case <-exit:
util.LOGGER.Warnf(nil, "waiting for %ds to clean up resources...", CLEAN_UP_TIMEOUT)
<-time.After(CLEAN_UP_TIMEOUT * time.Second)
default:
close(exit)
}
util.LOGGER.Warn("service center quit", nil)
}
func autoCompact() {
compactTicker := time.NewTicker(time.Minute * 5)
defer compactTicker.Stop()
for t := range compactTicker.C {
util.LOGGER.Debug(fmt.Sprintf("Compact at %s", t))
registry.GetRegisterCenter().CompactCluster(context.TODO())
}
}
func waitStoreReady() {
store.Run()
<-store.Ready()
}
func startNotifyService() {
notifyService.Config = nf.NotifyServiceConfig{
AddTimeout: 30 * time.Second,
NotifyTimeout: 30 * time.Second,
MaxQueue: 100,
}
notifyService.Start()
}
func startApiServer() {
sslMode := common.GetServerSSLConfig().SSLEnabled
verifyClient := common.GetServerSSLConfig().VerifyClient
restIp := beego.AppConfig.String("httpaddr")
restPort := beego.AppConfig.String("httpport")
grpcIp := beego.AppConfig.DefaultString("grpcaddr", "")
grpcPort := beego.AppConfig.DefaultString("grpcport", "")
cmpName := beego.AppConfig.String("ComponentName")
hostName := fmt.Sprintf("%s_%s", cmpName, strings.Replace(util.GetLocalIP(), ".", "_", -1))
util.LOGGER.Infof("Local listen address: %s:%s, host: %s.", restIp, restPort, hostName)
eps := map[api.APIType]string{}
if len(restIp) > 0 && len(restPort) > 0 {
eps[api.REST] = strings.Join([]string{restIp, restPort}, ":")
}
if len(grpcIp) > 0 && len(grpcPort) > 0 {
eps[api.GRPC] = strings.Join([]string{grpcIp, grpcPort}, ":")
}
apiServer.Config = api.APIServerConfig{
HostName: hostName,
Endpoints: eps,
SSL: sslMode,
VerifyClient: verifyClient,
}
apiServer.Start()
}