Re-vendor queue-worker publisher for reconnect

- re-vendor queue-worker for publisher via 0.6.0
- bump queue-worker version to 0.6.0 in docker-compose.yml for
AMD64
- use new naming for NATS of nats -> NATS in variables where
required
- add default reconnect of 60 times, 2 seconds apart.

Signed-off-by: Alex Ellis (VMware) <alexellis2@gmail.com>
This commit is contained in:
Alex Ellis (VMware)
2019-01-29 15:04:00 +00:00
committed by Alex Ellis
parent e63150ef70
commit b4a550327d
33 changed files with 1379 additions and 223 deletions

View File

@ -1,38 +1,13 @@
package handler
import (
"encoding/json"
"fmt"
"log"
"os"
"github.com/nats-io/go-nats-streaming"
"github.com/openfaas/faas/gateway/queue"
"regexp"
"sync"
)
// NatsQueue queue for work
type NatsQueue struct {
nc stan.Conn
}
type NatsConfig interface {
GetClientID() string
}
type DefaultNatsConfig struct {
}
var supportedCharacters, _ = regexp.Compile("[^a-zA-Z0-9-_]+")
func (DefaultNatsConfig) GetClientID() string {
val, _ := os.Hostname()
return getClientId(val)
}
// CreateNatsQueue ready for asynchronous processing
func CreateNatsQueue(address string, port int, clientConfig NatsConfig) (*NatsQueue, error) {
queue1 := NatsQueue{}
// CreateNATSQueue ready for asynchronous processing
func CreateNATSQueue(address string, port int, clientConfig NATSConfig) (*NATSQueue, error) {
var err error
natsURL := fmt.Sprintf("nats://%s:%d", address, port)
log.Printf("Opening connection to %s\n", natsURL)
@ -40,28 +15,17 @@ func CreateNatsQueue(address string, port int, clientConfig NatsConfig) (*NatsQu
clientID := clientConfig.GetClientID()
clusterID := "faas-cluster"
nc, err := stan.Connect(clusterID, clientID, stan.NatsURL(natsURL))
queue1.nc = nc
queue1 := NATSQueue{
ClientID: clientID,
ClusterID: clusterID,
NATSURL: natsURL,
Topic: "faas-request",
maxReconnect: clientConfig.GetMaxReconnect(),
reconnectDelay: clientConfig.GetReconnectDelay(),
ncMutex: &sync.RWMutex{},
}
err = queue1.connect()
return &queue1, err
}
// Queue request for processing
func (q *NatsQueue) Queue(req *queue.Request) error {
var err error
fmt.Printf("NatsQueue - submitting request: %s.\n", req.Function)
out, err := json.Marshal(req)
if err != nil {
log.Println(err)
}
err = q.nc.Publish("faas-request", out)
return err
}
func getClientId(hostname string) string {
return "faas-publisher-" + supportedCharacters.ReplaceAllString(hostname, "_")
}

View File

@ -4,36 +4,37 @@ import (
"os"
"strings"
"testing"
"github.com/openfaas/nats-queue-worker/nats"
)
func Test_GetClientID_ContainsHostname(t *testing.T) {
c := DefaultNatsConfig{}
c := DefaultNATSConfig{}
val := c.GetClientID()
hostname, _ := os.Hostname()
if !strings.HasSuffix(val, hostname) {
encodedHostname := nats.GetClientID(hostname)
if !strings.HasSuffix(val, encodedHostname) {
t.Errorf("GetClientID should contain hostname as suffix, got: %s", val)
t.Fail()
}
}
func TestCreateClientId(t *testing.T) {
clientId := getClientId("computer-a")
expected := "faas-publisher-computer-a"
if clientId != expected {
t.Logf("Expected client id `%s` actual `%s`\n", expected, clientId)
func TestCreategetClientID(t *testing.T) {
clientID := getClientID("computer-a")
want := "faas-publisher-computer-a"
if clientID != want {
t.Logf("Want clientID: `%s`, but got: `%s`\n", want, clientID)
t.Fail()
}
}
func TestCreateClientIdWhenHostHasUnsupportedCharacters(t *testing.T) {
clientId := getClientId("computer-a.acme.com")
expected := "faas-publisher-computer-a_acme_com"
if clientId != expected {
t.Logf("Expected client id `%s` actual `%s`\n", expected, clientId)
func TestCreategetClientIDWhenHostHasUnsupportedCharacters(t *testing.T) {
clientID := getClientID("computer-a.acme.com")
want := "faas-publisher-computer-a_acme_com"
if clientID != want {
t.Logf("Want clientID: `%s`, but got: `%s`\n", want, clientID)
t.Fail()
}
}

View File

@ -0,0 +1,41 @@
package handler
import (
"os"
"time"
"github.com/openfaas/nats-queue-worker/nats"
)
type NATSConfig interface {
GetClientID() string
GetMaxReconnect() int
GetReconnectDelay() time.Duration
}
type DefaultNATSConfig struct {
maxReconnect int
reconnectDelay time.Duration
}
func NewDefaultNATSConfig(maxReconnect int, reconnectDelay time.Duration) DefaultNATSConfig {
return DefaultNATSConfig{maxReconnect, reconnectDelay}
}
// GetClientID returns the ClientID assigned to this producer/consumer.
func (DefaultNATSConfig) GetClientID() string {
val, _ := os.Hostname()
return getClientID(val)
}
func (c DefaultNATSConfig) GetMaxReconnect() int {
return c.maxReconnect
}
func (c DefaultNATSConfig) GetReconnectDelay() time.Duration {
return c.reconnectDelay
}
func getClientID(hostname string) string {
return "faas-publisher-" + nats.GetClientID(hostname)
}

View File

@ -0,0 +1,88 @@
package handler
import (
"encoding/json"
"fmt"
"log"
"sync"
"time"
"github.com/nats-io/go-nats-streaming"
"github.com/openfaas/faas/gateway/queue"
)
// NATSQueue queue for work
type NATSQueue struct {
nc stan.Conn
ncMutex *sync.RWMutex
maxReconnect int
reconnectDelay time.Duration
// ClientID for NATS Streaming
ClientID string
// ClusterID in NATS Streaming
ClusterID string
// NATSURL URL to connect to NATS
NATSURL string
// Topic to respond to
Topic string
}
// Queue request for processing
func (q *NATSQueue) Queue(req *queue.Request) error {
fmt.Printf("NatsQueue - submitting request: %s.\n", req.Function)
out, err := json.Marshal(req)
if err != nil {
log.Println(err)
}
q.ncMutex.RLock()
nc := q.nc
q.ncMutex.RUnlock()
return nc.Publish(q.Topic, out)
}
func (q *NATSQueue) connect() error {
nc, err := stan.Connect(
q.ClusterID,
q.ClientID,
stan.NatsURL(q.NATSURL),
stan.SetConnectionLostHandler(func(conn stan.Conn, err error) {
log.Printf("Disconnected from %s\n", q.NATSURL)
q.reconnect()
}),
)
if err != nil {
return err
}
q.ncMutex.Lock()
q.nc = nc
q.ncMutex.Unlock()
return nil
}
func (q *NATSQueue) reconnect() {
for i := 0; i < q.maxReconnect; i++ {
time.Sleep(time.Second * time.Duration(i) * q.reconnectDelay)
if err := q.connect(); err == nil {
log.Printf("Reconnecting (%d/%d) to %s. OK\n", i+1, q.maxReconnect, q.NATSURL)
return
}
log.Printf("Reconnecting (%d/%d) to %s failed\n", i+1, q.maxReconnect, q.NATSURL)
}
log.Printf("Reached reconnection limit (%d) for %s\n", q.maxReconnect, q.NATSURL)
}