Publish/Subscribe with context

This commit is contained in:
Asim 2015-05-23 23:16:26 +01:00
parent b5dcbbe998
commit 32928bfb67
4 changed files with 71 additions and 26 deletions

View File

@ -2,6 +2,7 @@ package broker
import ( import (
"code.google.com/p/go-uuid/uuid" "code.google.com/p/go-uuid/uuid"
"golang.org/x/net/context"
) )
type Broker interface { type Broker interface {
@ -9,15 +10,15 @@ type Broker interface {
Connect() error Connect() error
Disconnect() error Disconnect() error
Init() error Init() error
Publish(string, []byte) error Publish(context.Context, string, []byte) error
Subscribe(string, func(*Message)) (Subscriber, error) Subscribe(string, func(context.Context, *Message)) (Subscriber, error)
} }
type Message struct { type Message struct {
Id string Id string
Timestamp int64 Timestamp int64
Topic string Topic string
Data []byte Body []byte
} }
type Subscriber interface { type Subscriber interface {
@ -59,10 +60,10 @@ func Disconnect() error {
return DefaultBroker.Disconnect() return DefaultBroker.Disconnect()
} }
func Publish(topic string, data []byte) error { func Publish(ctx context.Context, topic string, body []byte) error {
return DefaultBroker.Publish(topic, data) return DefaultBroker.Publish(ctx, topic, body)
} }
func Subscribe(topic string, function func(*Message)) (Subscriber, error) { func Subscribe(topic string, function func(context.Context, *Message)) (Subscriber, error) {
return DefaultBroker.Subscribe(topic, function) return DefaultBroker.Subscribe(topic, function)
} }

View File

@ -17,8 +17,11 @@ import (
"code.google.com/p/go-uuid/uuid" "code.google.com/p/go-uuid/uuid"
log "github.com/golang/glog" log "github.com/golang/glog"
c "github.com/myodc/go-micro/context"
"github.com/myodc/go-micro/errors" "github.com/myodc/go-micro/errors"
"github.com/myodc/go-micro/registry" "github.com/myodc/go-micro/registry"
"golang.org/x/net/context"
) )
type httpBroker struct { type httpBroker struct {
@ -36,10 +39,16 @@ type httpSubscriber struct {
id string id string
topic string topic string
ch chan *httpSubscriber ch chan *httpSubscriber
fn func(*Message) fn func(context.Context, *Message)
svc registry.Service svc registry.Service
} }
// used in brokers where there is no support for headers
type envelope struct {
Header map[string]string
Message *Message
}
var ( var (
DefaultSubPath = "/_sub" DefaultSubPath = "/_sub"
) )
@ -141,24 +150,26 @@ func (h *httpBroker) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return return
} }
var msg *Message var e *envelope
if err = json.Unmarshal(b, &msg); err != nil { if err = json.Unmarshal(b, &e); err != nil {
errr := errors.InternalServerError("go.micro.broker", fmt.Sprintf("Error parsing request body: %v", err)) errr := errors.InternalServerError("go.micro.broker", fmt.Sprintf("Error parsing request body: %v", err))
w.WriteHeader(500) w.WriteHeader(500)
w.Write([]byte(errr.Error())) w.Write([]byte(errr.Error()))
return return
} }
if len(msg.Topic) == 0 { if len(e.Message.Topic) == 0 {
errr := errors.InternalServerError("go.micro.broker", "Topic not found") errr := errors.InternalServerError("go.micro.broker", "Topic not found")
w.WriteHeader(500) w.WriteHeader(500)
w.Write([]byte(errr.Error())) w.Write([]byte(errr.Error()))
return return
} }
ctx := c.WithMetaData(context.Background(), e.Header)
h.RLock() h.RLock()
for _, subscriber := range h.subscribers[msg.Topic] { for _, subscriber := range h.subscribers[e.Message.Topic] {
subscriber.fn(msg) subscriber.fn(ctx, e.Message)
} }
h.RUnlock() h.RUnlock()
} }
@ -184,18 +195,26 @@ func (h *httpBroker) Init() error {
return nil return nil
} }
func (h *httpBroker) Publish(topic string, data []byte) error { func (h *httpBroker) Publish(ctx context.Context, topic string, body []byte) error {
s, err := registry.GetService("topic:" + topic) s, err := registry.GetService("topic:" + topic)
if err != nil { if err != nil {
return err return err
} }
b, err := json.Marshal(&Message{ message := &Message{
Id: uuid.NewUUID().String(), Id: uuid.NewUUID().String(),
Timestamp: time.Now().Unix(), Timestamp: time.Now().Unix(),
Topic: topic, Topic: topic,
Data: data, Body: body,
}
header, _ := c.GetMetaData(ctx)
b, err := json.Marshal(&envelope{
header,
message,
}) })
if err != nil { if err != nil {
return err return err
} }
@ -210,7 +229,7 @@ func (h *httpBroker) Publish(topic string, data []byte) error {
return nil return nil
} }
func (h *httpBroker) Subscribe(topic string, function func(*Message)) (Subscriber, error) { func (h *httpBroker) Subscribe(topic string, function func(context.Context, *Message)) (Subscriber, error) {
// parse address for host, port // parse address for host, port
parts := strings.Split(h.Address(), ":") parts := strings.Split(h.Address(), ":")
host := strings.Join(parts[:len(parts)-1], ":") host := strings.Join(parts[:len(parts)-1], ":")

View File

@ -8,6 +8,9 @@ import (
"code.google.com/p/go-uuid/uuid" "code.google.com/p/go-uuid/uuid"
"github.com/apcera/nats" "github.com/apcera/nats"
"github.com/myodc/go-micro/broker" "github.com/myodc/go-micro/broker"
c "github.com/myodc/go-micro/context"
"golang.org/x/net/context"
) )
type nbroker struct { type nbroker struct {
@ -19,6 +22,12 @@ type subscriber struct {
s *nats.Subscription s *nats.Subscription
} }
// used in brokers where there is no support for headers
type envelope struct {
Header map[string]string
Message *broker.Message
}
func (n *subscriber) Topic() string { func (n *subscriber) Topic() string {
return n.s.Subject return n.s.Subject
} }
@ -58,12 +67,19 @@ func (n *nbroker) Init() error {
return nil return nil
} }
func (n *nbroker) Publish(topic string, data []byte) error { func (n *nbroker) Publish(ctx context.Context, topic string, body []byte) error {
b, err := json.Marshal(&broker.Message{ header, _ := c.GetMetaData(ctx)
message := &broker.Message{
Id: uuid.NewUUID().String(), Id: uuid.NewUUID().String(),
Timestamp: time.Now().Unix(), Timestamp: time.Now().Unix(),
Topic: topic, Topic: topic,
Data: data, Body: body,
}
b, err := json.Marshal(&envelope{
header,
message,
}) })
if err != nil { if err != nil {
return err return err
@ -71,13 +87,14 @@ func (n *nbroker) Publish(topic string, data []byte) error {
return n.conn.Publish(topic, b) return n.conn.Publish(topic, b)
} }
func (n *nbroker) Subscribe(topic string, function func(*broker.Message)) (broker.Subscriber, error) { func (n *nbroker) Subscribe(topic string, function func(context.Context, *broker.Message)) (broker.Subscriber, error) {
sub, err := n.conn.Subscribe(topic, func(msg *nats.Msg) { sub, err := n.conn.Subscribe(topic, func(msg *nats.Msg) {
var data *broker.Message var e *envelope
if err := json.Unmarshal(msg.Data, &data); err != nil { if err := json.Unmarshal(msg.Data, &e); err != nil {
return return
} }
function(data) ctx := c.WithMetaData(context.Background(), e.Header)
function(ctx, e.Message)
}) })
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -7,6 +7,9 @@ import (
log "github.com/golang/glog" log "github.com/golang/glog"
"github.com/myodc/go-micro/broker" "github.com/myodc/go-micro/broker"
"github.com/myodc/go-micro/cmd" "github.com/myodc/go-micro/cmd"
c "github.com/myodc/go-micro/context"
"golang.org/x/net/context"
) )
var ( var (
@ -17,8 +20,12 @@ func pub() {
tick := time.NewTicker(time.Second) tick := time.NewTicker(time.Second)
i := 0 i := 0
for _ = range tick.C { for _ = range tick.C {
ctx := c.WithMetaData(context.Background(), map[string]string{
"id": fmt.Sprintf("%d", i),
})
msg := fmt.Sprintf("%d: %s", i, time.Now().String()) msg := fmt.Sprintf("%d: %s", i, time.Now().String())
if err := broker.Publish(topic, []byte(msg)); err != nil { if err := broker.Publish(ctx, topic, []byte(msg)); err != nil {
log.Errorf("[pub] failed: %v", err) log.Errorf("[pub] failed: %v", err)
} else { } else {
fmt.Println("[pub] pubbed message:", msg) fmt.Println("[pub] pubbed message:", msg)
@ -28,8 +35,9 @@ func pub() {
} }
func sub() { func sub() {
_, err := broker.Subscribe(topic, func(msg *broker.Message) { _, err := broker.Subscribe(topic, func(ctx context.Context, msg *broker.Message) {
fmt.Println("[sub] received message:", string(msg.Data)) md, _ := c.GetMetaData(ctx)
fmt.Println("[sub] received message:", string(msg.Body), "context", md)
}) })
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)