Skip to content

Commit

Permalink
Finish v1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
zouyx committed Aug 27, 2017
2 parents 82a9492 + 9bf7dfe commit 4d117f5
Show file tree
Hide file tree
Showing 12 changed files with 650 additions and 140 deletions.
189 changes: 175 additions & 14 deletions app_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"fmt"
"net/url"
"github.com/cihub/seelog"
"encoding/json"
)

const appConfigFileName ="app.properties"
Expand All @@ -19,20 +20,98 @@ var (
long_poll_connect_timeout = 1 * time.Minute //1m

connect_timeout = 1 * time.Second //1s
read_timeout = 5 * time.Second //5s
//for on error retry
on_error_retry_interval = 1 * time.Second //1s
//for typed config cache of parser result, e.g. integer, double, long, etc.
max_config_cache_size = 500 //500 cache key
config_cache_expire_time = 1 * time.Minute //1 minute
//max_config_cache_size = 500 //500 cache key
//config_cache_expire_time = 1 * time.Minute //1 minute

//max retries connect apollo
max_retries=5

//refresh ip list
refresh_ip_list_interval=20 *time.Minute //20m

//appconfig
appConfig *AppConfig

//real servers ip
servers map[string]*serverInfo=make(map[string]*serverInfo,0)

//next try connect period - 60 second
next_try_connect_period int64=60
)

type AppConfig struct {
AppId string `json:"appId"`
Cluster string `json:"cluster"`
NamespaceName string `json:"namespaceName"`
Ip string `json:"ip"`
NextTryConnTime int64 `json:"-"`
}

func (this *AppConfig) getHost() string{
return "http://"+this.Ip+"/"
}

//if this connect is fail will set this time
func (this *AppConfig) setNextTryConnTime(nextTryConnectPeriod int64){
this.NextTryConnTime=time.Now().Unix()+nextTryConnectPeriod
}

//is connect by ip directly
//false : no
//true : yes
func (this *AppConfig) isConnectDirectly() bool{
if this.NextTryConnTime>=0&&this.NextTryConnTime>time.Now().Unix(){
return true
}

return false
}

func (this *AppConfig) selectHost() string{
if !this.isConnectDirectly(){
return this.getHost()
}

for host,server:=range servers{
// if some node has down then select next node
if server.IsDown{
continue
}
return host
}

return ""
}

func setDownNode(host string) {
if host=="" || appConfig==nil{
return
}

if host==appConfig.getHost(){
appConfig.setNextTryConnTime(next_try_connect_period)
}

for key,server:=range servers{
if key==host{
server.IsDown=true
break
}
}
}


type serverInfo struct {
AppName string `json:"appName"`
InstanceId string `json:"instanceId"`
HomepageUrl string `json:"homepageUrl"`
IsDown bool `json:"-"`

}

func init() {
//init common
initCommon()
Expand Down Expand Up @@ -65,15 +144,63 @@ func initConfig() {
}(appConfig)
}

func GetAppConfig()*AppConfig {
return appConfig
//set timer for update ip list
//interval : 20m
func initServerIpList() {
t2 := time.NewTimer(refresh_ip_list_interval)
for {
select {
case <-t2.C:
syncServerIpList()
t2.Reset(refresh_ip_list_interval)
}
}
}

type AppConfig struct {
AppId string `json:"appId"`
Cluster string `json:"cluster"`
NamespaceName string `json:"namespaceName"`
Ip string `json:"ip"`
func syncServerIpListSuccessCallBack(responseBody []byte)(o interface{},err error){
tmpServerInfo:=make([]*serverInfo,0)

err= json.Unmarshal(responseBody,&tmpServerInfo)

if err!=nil{
seelog.Error("Unmarshal json Fail,Error:",err)
return
}

if len(tmpServerInfo)==0 {
seelog.Info("get no real server!")
return
}

for _,server :=range tmpServerInfo {
if server==nil{
continue
}
servers[server.HomepageUrl]=server
}
return
}

//sync ip list from server
//then
//1.update cache
//2.store in disk
func syncServerIpList() error{
appConfig:=GetAppConfig()
if appConfig==nil{
panic("can not find apollo config!please confirm!")
}
url:=getServicesConfigUrl(appConfig)
seelog.Debug("url:",url)

_,err:=request(url,syncServerIpListSuccessCallBack)


return err
}

func GetAppConfig()*AppConfig {
return appConfig
}

func initRefreshInterval() error {
Expand All @@ -90,9 +217,23 @@ func initRefreshInterval() error {
}

func getConfigUrl(config *AppConfig) string{
return getConfigUrlByHost(config,config.getHost())
}

func getConfigUrlByHost(config *AppConfig,host string) string{
current:=GetCurrentApolloConfig()
return fmt.Sprintf("http://%s/configs/%s/%s/%s?releaseKey=%s&ip=%s",
config.Ip,
return fmt.Sprintf("%sconfigs/%s/%s/%s?releaseKey=%s&ip=%s",
host,
url.QueryEscape(config.AppId),
url.QueryEscape(config.Cluster),
url.QueryEscape(config.NamespaceName),
url.QueryEscape(current.ReleaseKey),
getInternal())
}

func getConfigUrlSuffix(config *AppConfig) string{
current:=GetCurrentApolloConfig()
return fmt.Sprintf("configs/%s/%s/%s?releaseKey=%s&ip=%s",
url.QueryEscape(config.AppId),
url.QueryEscape(config.Cluster),
url.QueryEscape(config.NamespaceName),
Expand All @@ -101,9 +242,29 @@ func getConfigUrl(config *AppConfig) string{
}

func getNotifyUrl(notifications string,config *AppConfig) string{
return fmt.Sprintf("http://%s/notifications/v2?appId=%s&cluster=%s&notifications=%s",
config.Ip,
return getNotifyUrlByHost(notifications,
config,
config.getHost())
}

func getNotifyUrlByHost(notifications string,config *AppConfig,host string) string{
return fmt.Sprintf("%snotifications/v2?appId=%s&cluster=%s&notifications=%s",
host,
url.QueryEscape(config.AppId),
url.QueryEscape(config.Cluster),
url.QueryEscape(notifications))
}

func getNotifyUrlSuffix(notifications string,config *AppConfig) string{
return fmt.Sprintf("notifications/v2?appId=%s&cluster=%s&notifications=%s",
url.QueryEscape(config.AppId),
url.QueryEscape(config.Cluster),
url.QueryEscape(notifications))
}

func getServicesConfigUrl(config *AppConfig) string{
return fmt.Sprintf("%sservices/config?appId=%s&ip=%s",
config.getHost(),
url.QueryEscape(config.AppId),
getInternal())
}
99 changes: 99 additions & 0 deletions app_config_server_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package agollo

import (
"net/http"
"fmt"
//"time"
)

const servicesConfigResponseStr =`[{
"appName": "APOLLO-CONFIGSERVICE",
"instanceId": "10.15.128.102:apollo-configservice:8080",
"homepageUrl": "http://10.15.128.102:8080/"
},
{
"appName": "APOLLO-CONFIGSERVICE",
"instanceId": "10.15.88.125:apollo-configservice:8080",
"homepageUrl": "http://10.15.88.125:8080/"
},
{
"appName": "APOLLO-CONFIGSERVICE",
"instanceId": "10.14.0.11:apollo-configservice:8080",
"homepageUrl": "http://10.14.0.11:8080/"
},
{
"appName": "APOLLO-CONFIGSERVICE",
"instanceId": "10.14.0.193:apollo-configservice:8080",
"homepageUrl": "http://10.14.0.193:8080/"
},
{
"appName": "APOLLO-CONFIGSERVICE",
"instanceId": "10.15.128.101:apollo-configservice:8080",
"homepageUrl": "http://10.15.128.101:8080/"
},
{
"appName": "APOLLO-CONFIGSERVICE",
"instanceId": "10.14.0.192:apollo-configservice:8080",
"homepageUrl": "http://10.14.0.192:8080/"
},
{
"appName": "APOLLO-CONFIGSERVICE",
"instanceId": "10.15.88.124:apollo-configservice:8080",
"homepageUrl": "http://10.15.88.124:8080/"
},
{
"appName": "APOLLO-CONFIGSERVICE",
"instanceId": "10.15.128.103:apollo-configservice:8080",
"homepageUrl": "http://10.15.128.103:8080/"
},
{
"appName": "APOLLO-CONFIGSERVICE",
"instanceId": "localhost:apollo-configservice:8080",
"homepageUrl": "http://10.14.0.12:8080/"
},
{
"appName": "APOLLO-CONFIGSERVICE",
"instanceId": "10.14.0.194:apollo-configservice:8080",
"homepageUrl": "http://10.14.0.194:8080/"
}
]`

var server *http.Server

//run mock config server
func runMockServicesConfigServer(handler func(http.ResponseWriter, *http.Request)) {
uri:=fmt.Sprintf("/services/config")
http.HandleFunc(uri, handler)

server = &http.Server{
Addr: appConfig.Ip,
Handler: http.DefaultServeMux,
}

server.ListenAndServe()

//
//seelog.Info("mock notify server:",appConfig.Ip)
//err:=http.ListenAndServe(fmt.Sprintf("%s",appConfig.Ip), nil)
//if err!=nil{
// seelog.Error("runMockConfigServer err:",err)
//}
}

func closeMockServicesConfigServer() {
http.DefaultServeMux=http.NewServeMux()
server.Close()
}


//Normal response
func normalServicesConfigResponse(rw http.ResponseWriter, req *http.Request) {
fmt.Fprintf(rw, servicesConfigResponseStr)
}

////Error response
////will hold 5s and keep response 404
//func errorConfigResponse(rw http.ResponseWriter, req *http.Request) {
// time.Sleep(500 * time.Microsecond)
// rw.WriteHeader(http.StatusNotFound)
//}
Loading

0 comments on commit 4d117f5

Please sign in to comment.