fixed error handling and docs

This commit is contained in:
2024-09-09 16:38:58 +01:00
parent dba01de425
commit 9283306006
5 changed files with 52 additions and 17 deletions

View File

@@ -11,7 +11,7 @@ go get -u gitlab.com/naterciom/gubgub
## Example
Ignoring errors for code brevity!
We'll be ignoring errors for code brevity!
```Go
package main
@@ -32,22 +32,33 @@ func consumer(msg MyMessage) {
fmt.Printf("Hello %s", msg.Name)
}
func main() {
func m2ain() {
topic := gubgub.NewAsyncTopic[MyMessage]()
defer topic.Close() // Returns after all messages are delivered
_ := topic.Subscribe(gubgub.Forever(consumer))
_ = topic.Subscribe(gubgub.Forever(consumer))
// The AsyncTopic doesn't wait for the subscriber to be registered so, for the purposes of this
// example, we sleep on it.
time.Sleep(time.Millisecond)
_ := topic.Publish(MyMessage{Name: "John Smith"}) // Returns immediately
_ = topic.Publish(MyMessage{Name: "John Smith"}) // Returns immediately
}
```
## Topics
Topics are what this is all about. You publish to a topic and you subscribe to a topic. That is it.
Topics are what this is all about.
You publish to a topic and you subscribe to a topic.
That is it.
A `Subscriber` is just a callback func.
A message is considered delivered when all subscribers have been called for that message and returned.
If you `Publish` a message successfully (did not get an error) then you can be sure the message will be deliverd before any call to `Close` returns.
Topics are meant to live as long as the application but you should call the `Close` method upon shutdown to fulfill the publishing promise.
Use the `WithOnClose` option when creating the topic to perform any extra clean up you might need to do if the topic is closed.
GubGub offers 2 kinds of topics:

View File

@@ -15,14 +15,28 @@ func main() {
topic := gubgub.NewAsyncTopic[string]()
defer topic.Close()
topic.Subscribe(gubgub.Forever(UpperCaser))
err := topic.Subscribe(gubgub.Forever(UpperCaser))
if err != nil {
log.Fatal(err)
}
topic.Subscribe(Countdown(3))
err = topic.Subscribe(Countdown(3))
if err != nil {
log.Fatal(err)
}
topic.Subscribe(gubgub.Buffered(gubgub.Forever(Slow)))
err = topic.Subscribe(gubgub.Buffered(gubgub.Forever(Slow)))
if err != nil {
log.Fatal(err)
}
go func() {
for s := range gubgub.Feed(topic, false) {
feed, err := gubgub.Feed(topic, false)
if err != nil {
log.Fatal(err)
}
for s := range feed {
log.Printf("ForRange: %s", s)
}
}()
@@ -35,6 +49,7 @@ func main() {
if err != nil {
log.Fatal(err)
}
topic.Publish(scanner.Text())
}
}

15
feed.go
View File

@@ -1,10 +1,12 @@
package gubgub
import "iter"
import (
"iter"
)
// Feed allows the usage of for/range to consume future published messages.
// Feed allows the usage of for/range loop to consume future published messages.
// The supporting subscriber will eventually be discarded after you exit the for loop.
func Feed[T any](t Subscribable[T], buffered bool) iter.Seq[T] {
func Feed[T any](t Subscribable[T], buffered bool) (iter.Seq[T], error) {
feed := make(chan T) // closed by the subscriber
unsubscribe := make(chan struct{}) // closed by the iterator
@@ -22,7 +24,10 @@ func Feed[T any](t Subscribable[T], buffered bool) iter.Seq[T] {
subscriber = Buffered(subscriber)
}
t.Subscribe(subscriber)
err := t.Subscribe(subscriber)
if err != nil {
return nil, err
}
// Iterator
return func(yield func(T) bool) {
@@ -33,5 +38,5 @@ func Feed[T any](t Subscribable[T], buffered bool) iter.Seq[T] {
return
}
}
}
}, nil
}

View File

@@ -32,9 +32,12 @@ func TestFeed_Topics(t *testing.T) {
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
feed, err := Feed(tc.topic, false)
require.NoError(t, err)
feedback := make(chan int)
go func() {
for i := range Feed(tc.topic, false) {
for i := range feed {
feedback <- i
}
}()
@@ -58,5 +61,4 @@ func TestFeed_Topics(t *testing.T) {
}
})
}
}

View File

@@ -29,6 +29,8 @@ func NoOp[T any]() Subscriber[T] {
// available memory.
// This is useful if message publishing is surge prone and message processing is slow or
// unpredictable (for example: subscriber makes network request).
// IMPORTANT: messages are considered delivered even it they are still in the buffer which means
// that buffered subscribers are NOT COVERED by the publishing promise.
// Message average processing rate must still be higher than the average message publishing rate
// otherwise it will eventually lead to memory issues. You will need to find a better strategy to
// deal with such scenario.