2016-04-12 06:11:51 +03:00
|
|
|
Publish & Subscribe Messaging Pattern
|
|
|
|
============
|
|
|
|
Publish-Subscribe is a messaging pattern used to communicate messages between
|
|
|
|
different components without these components knowing anything about each other's identity.
|
|
|
|
|
|
|
|
It is similar to the Observer behavioral design pattern.
|
|
|
|
The fundamental design principals of both Observer and Publish-Subscribe is the decoupling of
|
|
|
|
those interested in being informed about `Event Messages` from the informer (Observers or Publishers).
|
|
|
|
Meaning that you don't have to program the messages to be sent directly to specific receivers.
|
|
|
|
|
|
|
|
To accomplish this, an intermediary, called a "message broker" or "event bus",
|
|
|
|
receives published messages, and then routes them on to subscribers.
|
|
|
|
|
|
|
|
|
2020-09-28 08:04:32 +03:00
|
|
|
There are three components **messages**, **topics**, **subscriptions**.
|
2016-04-12 06:11:51 +03:00
|
|
|
|
|
|
|
```go
|
|
|
|
type Message struct {
|
|
|
|
// Contents
|
|
|
|
}
|
|
|
|
|
|
|
|
type Subscription struct {
|
2020-09-28 08:04:32 +03:00
|
|
|
closed bool
|
|
|
|
inbox chan Message
|
2016-04-12 06:11:51 +03:00
|
|
|
}
|
|
|
|
|
2020-09-28 08:04:32 +03:00
|
|
|
func (s *Subscription) Next() (Message, error) {
|
|
|
|
if s.closed {
|
|
|
|
return Message{}, errors.New("subscription closed")
|
2016-04-12 06:11:51 +03:00
|
|
|
}
|
2020-09-28 08:04:32 +03:00
|
|
|
|
|
|
|
m, ok := <-s.inbox
|
|
|
|
if !ok {
|
|
|
|
return Message{}, errors.New("subscription closed")
|
|
|
|
}
|
|
|
|
|
|
|
|
return m, nil
|
|
|
|
}
|
2016-04-12 06:11:51 +03:00
|
|
|
|
2020-09-28 08:04:32 +03:00
|
|
|
func (s *Subscription) Unsubscribe(Subscription) error {
|
|
|
|
s.closed = true
|
|
|
|
close(s.inbox)
|
2016-04-12 06:11:51 +03:00
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
```go
|
|
|
|
type Topic struct {
|
2020-09-28 08:04:32 +03:00
|
|
|
Subscribers []Subscription
|
2016-04-12 06:11:51 +03:00
|
|
|
MessageHistory []Message
|
|
|
|
}
|
|
|
|
|
2020-09-28 08:04:32 +03:00
|
|
|
func (t *Topic) Subscribe() (Subscription) {
|
|
|
|
return Subscription{inbox: make(chan Message)}
|
2016-04-12 06:11:51 +03:00
|
|
|
}
|
|
|
|
|
2020-09-28 08:04:32 +03:00
|
|
|
func (t *Topic) Publish(msg Message) error {
|
|
|
|
for _, sub := range t.Subscribers {
|
|
|
|
if sub.closed {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
sub.inbox <- msg
|
|
|
|
}()
|
|
|
|
}
|
2016-04-12 06:11:51 +03:00
|
|
|
|
2020-09-28 08:04:32 +03:00
|
|
|
return nil
|
2016-04-12 06:11:51 +03:00
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
Improvements
|
|
|
|
============
|
|
|
|
Events can be published in a parallel fashion by utilizing stackless goroutines.
|
|
|
|
|
|
|
|
Performance can be improved by dealing with straggler subscribers
|
|
|
|
by using a buffered inbox and you stop sending events once the inbox is full.
|