Goodbye messages, proper exit handling
This commit is contained in:
parent
53da96ec10
commit
68d4fc50a6
@ -8,9 +8,19 @@ import (
|
|||||||
|
|
||||||
// Config keeps info about configuration of this daemon
|
// Config keeps info about configuration of this daemon
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Token string `envconfig:"TOKEN" required:"false"` // not used yet
|
Token string `envconfig:"TOKEN" required:"false"` // Authentication token, if empty auth is disabled
|
||||||
NATSURL string `envconfig:"NATS_URL" required:"true"`
|
Host string `envconfig:"HOST" required:"false" default:"127.0.0.1"` // IP address used for the REST server to listen
|
||||||
Labels []string `envconfig:"LABELS" required:"false" default:""`
|
Port uint16 `envconfig:"PORT" required:"false" default:"1313"` // Port related to the address above
|
||||||
|
NATSURL string `envconfig:"NATS_URL" required:"true"` // NATS URL used to connect to the NATS server
|
||||||
|
NATSDiscoveryChannel string `envconfig:"NATS_DISCOVERY_CHANNEL" required:"true" default:"lobby.discovery"` // Channel where the kepp alive packets are sent
|
||||||
|
Labels []string `envconfig:"LABELS" required:"false" default:""` // List of labels
|
||||||
|
LabelsPath string `envconfig:"LABELS_PATH" required:"false" default:"/etc/lobby/labels"` // Path where filesystem based labels are located
|
||||||
|
// TemplatesPath string `envconfig:"TEMPLATES_PATH" required:"false" default:"/etc/lobby/templates"` // Path where templates are stored for custom output
|
||||||
|
HostName string `envconfig:"HOSTNAME" required:"false"` // Overrise local machine's hostname
|
||||||
|
CleanEvery uint `envconfig:"CLEAN_EVERY" required:"false" default:"15"` // How often to clean the list of servers to get rid of the not alive ones
|
||||||
|
KeepAlive uint `envconfig:"KEEP_ALIVE" required:"false" default:"5"` // how often to send the keepalive message with all availabel information [secs]
|
||||||
|
TTL uint `envconfig:"TTL" required:"false" default:"30"` // After how many secs is discovery record considered as invalid
|
||||||
|
NodeExporterPort uint `envconfig:"NODE_EXPORTER_PORT" required:"false" default:"9100"` // Default port where node_exporter listens on all registered servers
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetConfig return configuration created based on environment variables
|
// GetConfig return configuration created based on environment variables
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/labstack/echo"
|
"github.com/labstack/echo"
|
||||||
@ -16,6 +20,8 @@ var discoveryStorage server.Discoveries = server.Discoveries{}
|
|||||||
|
|
||||||
var config Config
|
var config Config
|
||||||
|
|
||||||
|
var shuttingDown bool
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
discoveryStorage.LogChannel = make(chan string)
|
discoveryStorage.LogChannel = make(chan string)
|
||||||
}
|
}
|
||||||
@ -29,15 +35,43 @@ func cleanDiscoveryPool() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sendGoodbyePacket is almost same as sendDiscoveryPacket but it's not running in loop
|
||||||
|
// and it adds goodbye message so other nodes know this node is gonna die.
|
||||||
|
func sendGoodbyePacket(nc *nats.Conn) {
|
||||||
|
discovery, err := getIdentification()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("sending discovery identification error: %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
envelope := discoveryEnvelope{
|
||||||
|
Discovery: discovery,
|
||||||
|
Message: "goodbye",
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := envelope.Bytes()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("sending discovery formating message error: %v\n", err)
|
||||||
|
}
|
||||||
|
err = nc.Publish(config.NATSDiscoveryChannel, data)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("sending discovery error: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// sendDisoveryPacket sends discovery packet regularly so the network know we exist
|
// sendDisoveryPacket sends discovery packet regularly so the network know we exist
|
||||||
func sendDisoveryPacket(nc *nats.Conn) {
|
func sendDiscoveryPacket(nc *nats.Conn) {
|
||||||
for {
|
for {
|
||||||
discovery, err := getIdentification()
|
discovery, err := getIdentification()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("sending discovery identification error: %v\n", err)
|
log.Printf("sending discovery identification error: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := discovery.Bytes()
|
envelope := discoveryEnvelope{
|
||||||
|
Discovery: discovery,
|
||||||
|
Message: "hi",
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := envelope.Bytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("sending discovery formating message error: %v\n", err)
|
log.Printf("sending discovery formating message error: %v\n", err)
|
||||||
}
|
}
|
||||||
@ -46,6 +80,10 @@ func sendDisoveryPacket(nc *nats.Conn) {
|
|||||||
log.Printf("sending discovery error: %v\n", err)
|
log.Printf("sending discovery error: %v\n", err)
|
||||||
}
|
}
|
||||||
time.Sleep(time.Duration(config.KeepAlive) * time.Second)
|
time.Sleep(time.Duration(config.KeepAlive) * time.Second)
|
||||||
|
|
||||||
|
if shuttingDown {
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +127,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
go cleanDiscoveryPool()
|
go cleanDiscoveryPool()
|
||||||
go sendDisoveryPacket(nc)
|
go sendDiscoveryPacket(nc)
|
||||||
|
|
||||||
// --------
|
// --------
|
||||||
// REST API
|
// REST API
|
||||||
@ -141,6 +179,22 @@ func main() {
|
|||||||
// return c.String(http.StatusOK, body.String())
|
// return c.String(http.StatusOK, body.String())
|
||||||
// })
|
// })
|
||||||
|
|
||||||
|
// ------------------------------
|
||||||
|
// Termination signals processing
|
||||||
|
// ------------------------------
|
||||||
|
|
||||||
|
signals := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
|
||||||
|
go func(nc *nats.Conn, e *echo.Echo) {
|
||||||
|
sig := <-signals
|
||||||
|
shuttingDown = true
|
||||||
|
log.Printf("%s signal received, sending goodbye packet\n", sig.String())
|
||||||
|
sendGoodbyePacket(nc)
|
||||||
|
time.Sleep(5 * time.Second) // we wait for a few seconds to let background jobs to finish their job
|
||||||
|
e.Shutdown(context.TODO())
|
||||||
|
}(nc, e)
|
||||||
|
|
||||||
// Start server
|
// Start server
|
||||||
e.Logger.Fatal(e.Start(config.Host + ":" + strconv.Itoa(int(config.Port))))
|
e.Logger.Error(e.Start(config.Host + ":" + strconv.Itoa(int(config.Port))))
|
||||||
}
|
}
|
||||||
|
@ -6,22 +6,24 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/nats-io/nats.go"
|
"github.com/nats-io/nats.go"
|
||||||
"github.com/rosti-cz/server_lobby/server"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// discoveryHandler accepts discovery message and
|
// discoveryHandler accepts discovery message and
|
||||||
func discoveryHandler(m *nats.Msg) {
|
func discoveryHandler(m *nats.Msg) {
|
||||||
message := server.Discovery{}
|
message := discoveryEnvelope{}
|
||||||
err := json.Unmarshal(m.Data, &message)
|
err := json.Unmarshal(m.Data, &message)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(fmt.Errorf("decoding message error: %v", err))
|
log.Println(fmt.Errorf("decoding message error: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
err = message.Validate()
|
err = message.Discovery.Validate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(fmt.Errorf("validation error: %v", err))
|
log.Println(fmt.Errorf("validation error: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
discoveryStorage.Add(message)
|
if message.Message == "hi" {
|
||||||
|
discoveryStorage.Add(message.Discovery)
|
||||||
|
} else if message.Message == "goodbye" {
|
||||||
|
discoveryStorage.Delete(message.Discovery.Hostname)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
20
daemon/types.go
Normal file
20
daemon/types.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/rosti-cz/server_lobby/server"
|
||||||
|
)
|
||||||
|
|
||||||
|
// discoveryEnvelope adds a message to the standard discovery format. The message
|
||||||
|
// can be "hi" or "goodbye" where "hi" is used when the node is sending keep alive
|
||||||
|
// packets and "goodbye" means the node is leaving.
|
||||||
|
type discoveryEnvelope struct {
|
||||||
|
Discovery server.Discovery `json:"discovery"`
|
||||||
|
Message string `json:"message"` // can be hi or goodbye
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *discoveryEnvelope) Bytes() ([]byte, error) {
|
||||||
|
body, err := json.Marshal(e)
|
||||||
|
return body, err
|
||||||
|
}
|
@ -105,6 +105,10 @@ func (d *Discoveries) Refresh(hostname string) {
|
|||||||
|
|
||||||
// Delete removes server identified by hostname from the storage
|
// Delete removes server identified by hostname from the storage
|
||||||
func (d *Discoveries) Delete(hostname string) {
|
func (d *Discoveries) Delete(hostname string) {
|
||||||
|
if !d.Exist(hostname) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if d.LogChannel != nil {
|
if d.LogChannel != nil {
|
||||||
d.LogChannel <- fmt.Sprintf("removing %s", hostname)
|
d.LogChannel <- fmt.Sprintf("removing %s", hostname)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user