From b633a2d5a47d700faa461aa15d33ac36846bbacd Mon Sep 17 00:00:00 2001 From: David Justice Date: Wed, 9 May 2018 10:07:46 -0700 Subject: [PATCH] basic readme info and quick start example --- README.md | 74 +++++++++++++++++++++ _examples/.gitignore | 1 + _examples/helloworld/Makefile | 12 ++++ _examples/helloworld/consumer/main.go | 73 +++++++++++++++++++++ _examples/helloworld/producer/main.go | 53 +++++++++++++++ _examples/helloworld/readme.md | 93 +++++++++++++++++++++++++++ 6 files changed, 306 insertions(+) create mode 100644 _examples/.gitignore create mode 100644 _examples/helloworld/Makefile create mode 100644 _examples/helloworld/consumer/main.go create mode 100644 _examples/helloworld/producer/main.go create mode 100644 _examples/helloworld/readme.md diff --git a/README.md b/README.md index 72f1506..663d69e 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,77 @@ +# Microsoft Azure Service Bus Client for Golang + +Microsoft Azure Service Bus is a reliable cloud messaging service (MaaS) which simplifies enterprise cloud messaging. It +enables developers to build scalable cloud solutions and implement complex messaging workflows over an efficient binary +protocol called AMQP. + +This library provides a simple interface for sending, receiving and managing Service Bus entities such as Queues, Topics +and Subscriptions. + +For more information about Service Bus, check out the [Azure documentation](https://azure.microsoft.com/en-us/services/service-bus/). + +This library is a pure Golang implementation of Azure Event Hubs over AMQP. + + +## Preview of Service Bus for Golang +This library is currently a preview. There may be breaking interface changes until it reaches semantic version `v1.0.0`. +If you run into an issue, please don't hesitate to log a +[new issue](https://github.com/Azure/azure-service-bus-go/issues/new) or open a pull request. + +## Installing the library +To more reliably manage dependencies in your application we recommend [golang/dep](https://github.com/golang/dep). + +With dep: +``` +dep ensure -add github.com/Azure/azure-service-bus-go +``` + +With go get: +``` +go get -u github.com/Azure/azure-service-bus-go/... +``` + +If you need to install Go, follow [the official instructions](https://golang.org/dl/) + +## Using Service Bus +In this section we'll cover some basics of the library to help you get started. + +This library has two main dependencies, [vcabbage/amqp](https://github.com/vcabbage/amqp) and +[Azure AMQP Common](https://github.com/Azure/azure-amqp-common-go). The former provides the AMQP protocol implementation +and the latter provides some common authentication, persistence and request-response message flows. + +### Quick start +Let's send and receive `"hello, world!"`. +```go +// Connect +connStr := mustGetenv("SERVICEBUS_CONNECTION_STRING") +ns, err := servicebus.NewNamespace(servicebus.NamespaceWithConnectionString(connStr)) +handleErr(err) + +queueName := "helloworld" +// Create the queue if it doesn't exist +qm := ns.NewQueueManager() +_, err := qm.Put(context.Background(), queueName) +handleErr(err) +q := ns.NewQueue(queueName) + +// Send message to queue +err := q.Send(context.Background(), servicebus.NewEventFromString("Hello World!")) +handleErr(err) + +// Receive message from queue +listenHandle, err := q.Receive(context.Background()) +defer listenHandle.Close(context.Background) +handleErr(err) + +// Wait for a signal to quit: +signalChan := make(chan os.Signal, 1) +signal.Notify(signalChan, os.Interrupt, os.Kill) +<-signalChan +``` + +## Examples +- [HelloWorld: Producer and Consumer](./_examples/helloworld): an example of sending and receiving messages from a +Service Bus Queue. # Contributing diff --git a/_examples/.gitignore b/_examples/.gitignore new file mode 100644 index 0000000..c5e82d7 --- /dev/null +++ b/_examples/.gitignore @@ -0,0 +1 @@ +bin \ No newline at end of file diff --git a/_examples/helloworld/Makefile b/_examples/helloworld/Makefile new file mode 100644 index 0000000..823f90e --- /dev/null +++ b/_examples/helloworld/Makefile @@ -0,0 +1,12 @@ +# Go parameters +GOCMD=go +GOBUILD=$(GOCMD) build +GOCLEAN=$(GOCMD) clean + +all: clean build +build: + $(GOBUILD) -o ./bin/consumer ./consumer/main.go + $(GOBUILD) -o ./bin/producer ./producer/main.go +clean: + $(GOCLEAN) + rm -rf ./bin \ No newline at end of file diff --git a/_examples/helloworld/consumer/main.go b/_examples/helloworld/consumer/main.go new file mode 100644 index 0000000..dd984b0 --- /dev/null +++ b/_examples/helloworld/consumer/main.go @@ -0,0 +1,73 @@ +package main + +import ( + "context" + "fmt" + "os" + "time" + + "github.com/Azure/azure-service-bus-go" +) + +func main() { + // Connect + connStr := mustGetenv("SERVICEBUS_CONNECTION_STRING") + ns, err := servicebus.NewNamespace(servicebus.NamespaceWithConnectionString(connStr)) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + queueName := "helloworld" + // Create the queue if it doesn't exist + err = ensureQueue(ns, queueName) + q := ns.NewQueue(queueName) + + // Start listening to events on the queue + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + exit := make(chan struct{}) + listenHandle, err := q.Receive(ctx, func(ctx context.Context, event *servicebus.Event) error { + text := string(event.Data) + if text == "exit\n" { + fmt.Println("Oh snap!! Someone told me to exit!") + exit <- *new(struct{}) + } else { + fmt.Println(string(event.Data)) + } + return nil + }) + defer listenHandle.Close(context.Background()) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + fmt.Println("I am listening...") + + select { + case <-exit: + fmt.Println("closing after 2 seconds") + select { + case <-time.After(2 * time.Second): + listenHandle.Close(context.Background()) + return + } + } +} + +func ensureQueue(ns *servicebus.Namespace, queueName string) error { + qm := ns.NewQueueManager() + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + _, err := qm.Put(ctx, queueName) + return err +} + +func mustGetenv(key string) string { + v := os.Getenv(key) + if v == "" { + panic("Environment variable '" + key + "' required for integration tests.") + } + return v +} \ No newline at end of file diff --git a/_examples/helloworld/producer/main.go b/_examples/helloworld/producer/main.go new file mode 100644 index 0000000..1e822f0 --- /dev/null +++ b/_examples/helloworld/producer/main.go @@ -0,0 +1,53 @@ +package main + +import ( + "bufio" + "context" + "fmt" + "os" + "time" + + "github.com/Azure/azure-service-bus-go" +) + +func main() { + // Connect + connStr := mustGetenv("SERVICEBUS_CONNECTION_STRING") + ns, err := servicebus.NewNamespace(servicebus.NamespaceWithConnectionString(connStr)) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + queueName := "helloworld" + // Create the queue if it doesn't exist + err = ensureQueue(ns, queueName) + q := ns.NewQueue(queueName) + reader := bufio.NewReader(os.Stdin) + for { + fmt.Print("Enter text: ") + text, _ := reader.ReadString('\n') + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + q.Send(ctx, servicebus.NewEventFromString(text)) + if text == "exit\n" { + break + } + cancel() + } +} + +func ensureQueue(ns *servicebus.Namespace, queueName string) error { + qm := ns.NewQueueManager() + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + _, err := qm.Put(ctx, queueName) + return err +} + +func mustGetenv(key string) string { + v := os.Getenv(key) + if v == "" { + panic("Environment variable '" + key + "' required for integration tests.") + } + return v +} diff --git a/_examples/helloworld/readme.md b/_examples/helloworld/readme.md new file mode 100644 index 0000000..bdce5d5 --- /dev/null +++ b/_examples/helloworld/readme.md @@ -0,0 +1,93 @@ +# Hello World Producer / Consumer + +This example illustrates a producer sending messages into a Service Bus FIFO Queue. The consumer +receives from each message in FIFO order from the queue, and outputs the message it receives. Upon entering 'exit' into the +producer, the producer will send, then exit, and the receiver will receive the message and close. + +## To Run +- from this directory execute `make` +- open two terminal windows + - in the first terminal, execute `./bin/consumer` + - in the second terminal, execute `./bin/producer` + - in the second terminal, type some works and press enter +- see the words you typed in the second terminal in the first +- type 'exit' in the second terminal when you'd like to end your session + +## Producer +```go +func main() { + // Connect + connStr := mustGetenv("SERVICEBUS_CONNECTION_STRING") + ns, err := servicebus.NewNamespace(servicebus.NamespaceWithConnectionString(connStr)) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + queueName := "helloworld" + // Create the queue if it doesn't exist + err = ensureQueue(ns, queueName) + q := ns.NewQueue(queueName) + reader := bufio.NewReader(os.Stdin) + for { + fmt.Print("Enter text: ") + text, _ := reader.ReadString('\n') + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + q.Send(ctx, servicebus.NewEventFromString(text)) + if text == "exit\n" { + break + } + cancel() + } +} +``` + +## Consumer +```go +func main() { + // Connect + connStr := mustGetenv("SERVICEBUS_CONNECTION_STRING") + ns, err := servicebus.NewNamespace(servicebus.NamespaceWithConnectionString(connStr)) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + queueName := "helloworld" + // Create the queue if it doesn't exist + err = ensureQueue(ns, queueName) + q := ns.NewQueue(queueName) + + // Start listening to events on the queue + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + exit := make(chan struct{}) + listenHandle, err := q.Receive(ctx, func(ctx context.Context, event *servicebus.Event) error { + text := string(event.Data) + if text == "exit\n" { + fmt.Println("Oh snap!! Someone told me to exit!") + exit <- *new(struct{}) + } else { + fmt.Println(string(event.Data)) + } + return nil + }) + defer listenHandle.Close(context.Background()) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + fmt.Println("I am listening...") + + select { + case <-exit: + fmt.Println("closing after 2 seconds") + select { + case <-time.After(2 * time.Second): + listenHandle.Close(context.Background()) + return + } + } +} +``` \ No newline at end of file