forked from adrianco/spigo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
zuul.go
108 lines (106 loc) · 3.89 KB
/
zuul.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// Package zuul simulates an API proxy
// Takes incoming traffic and routes it over microservices in a single zone
package zuul
import (
"fmt"
"github.com/adrianco/spigo/archaius"
"github.com/adrianco/spigo/gotocol"
"log"
"math/rand"
"time"
)
// Start zuul, all configuration and state is sent via messages
func Start(listener chan gotocol.Message) {
dunbar := 30 // starting point for how many nodes to remember
// remember the channel to talk to microservices
microservices := make(map[string]chan gotocol.Message, dunbar)
microindex := make([]chan gotocol.Message, dunbar)
store := make(map[string]string, 4) // key value store
var netflixoss, requestor chan gotocol.Message // remember creator and how to talk back to incoming requests
var name string // remember my name
var edda chan gotocol.Message // if set, send updates
var chatrate time.Duration
chatTicker := time.NewTicker(time.Hour)
chatTicker.Stop()
for {
select {
case msg := <-listener:
if archaius.Conf.Msglog {
log.Printf("%v: %v\n", name, msg)
}
switch msg.Imposition {
case gotocol.Hello:
if name == "" {
// if I don't have a name yet remember what I've been named
netflixoss = msg.ResponseChan // remember how to talk to my namer
name = msg.Intention // message body is my name
}
case gotocol.Inform:
// remember where to send updates
edda = msg.ResponseChan
// logger channel is buffered so no need to use GoSend
edda <- gotocol.Message{gotocol.Hello, nil, time.Now(), name + " " + "zuul"}
case gotocol.NameDrop:
// don't remember too many buddies and don't talk to myself
microservice := msg.Intention // message body is buddy name
if len(microservices) < dunbar && microservice != name {
// remember how to talk to this buddy
microservices[microservice] = msg.ResponseChan // message channel is buddy's listener
if edda != nil {
// if it's setup, tell the logger I have a new buddy to talk to
edda <- gotocol.Message{gotocol.Inform, listener, time.Now(), name + " " + microservice}
}
}
case gotocol.Chat:
// setup the ticker to run at the specified rate
d, e := time.ParseDuration(msg.Intention)
if e == nil && d >= time.Millisecond && d <= time.Hour {
chatrate = d
chatTicker = time.NewTicker(chatrate)
}
case gotocol.GetRequest:
// route the request on to microservices
requestor = msg.ResponseChan
// Intention body indicates which service to route to or which key to get
// need to lookup service by type rather than randomly call one day
if len(microservices) > 0 {
if len(microindex) != len(microservices) {
// rebuild index
i := 0
for _, ch := range microservices {
microindex[i] = ch
i++
}
}
m := rand.Intn(len(microservices))
// start a request to a random member of this zuul proxy
gotocol.Message{gotocol.GetRequest, listener, time.Now(), name}.GoSend(microindex[m])
}
case gotocol.GetResponse:
// return path from a request, send payload back up
if requestor != nil {
gotocol.Message{gotocol.GetResponse, listener, time.Now(), msg.Intention}.GoSend(requestor)
}
case gotocol.Put:
// set a key value pair
var key, value string
fmt.Sscanf(msg.Intention, "%s%s", &key, &value)
// log.Printf("zuul: %v:%v", key, value)
store[key] = value
case gotocol.Goodbye:
if archaius.Conf.Msglog {
log.Printf("%v: Going away, zone: %v\n", name, store["zone"])
}
gotocol.Message{gotocol.Goodbye, nil, time.Now(), name}.GoSend(netflixoss)
return
}
case <-chatTicker.C:
if len(microservices) > 0 {
m := rand.Intn(len(microservices))
// start a request to a random member of this zuul proxy
gotocol.Message{gotocol.GetRequest, listener, time.Now(), name}.GoSend(microindex[m])
}
//default:
}
}
}